diff options
Diffstat (limited to 'sound/soc/codecs')
34 files changed, 9571 insertions, 555 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1db04a28a53..e0b9869df0f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1,16 +1,80 @@ | |||
1 | config SND_SOC_ALL_CODECS | ||
2 | tristate "Build all ASoC CODEC drivers" | ||
3 | depends on I2C | ||
4 | select SPI | ||
5 | select SPI_MASTER | ||
6 | select SND_SOC_AK4535 | ||
7 | select SND_SOC_CS4270 | ||
8 | select SND_SOC_SSM2602 | ||
9 | select SND_SOC_TLV320AIC26 | ||
10 | select SND_SOC_TLV320AIC3X | ||
11 | select SND_SOC_UDA1380 | ||
12 | select SND_SOC_WM8510 | ||
13 | select SND_SOC_WM8580 | ||
14 | select SND_SOC_WM8731 | ||
15 | select SND_SOC_WM8750 | ||
16 | select SND_SOC_WM8753 | ||
17 | select SND_SOC_WM8900 | ||
18 | select SND_SOC_WM8903 | ||
19 | select SND_SOC_WM8971 | ||
20 | select SND_SOC_WM8990 | ||
21 | help | ||
22 | Normally ASoC codec drivers are only built if a machine driver which | ||
23 | uses them is also built since they are only usable with a machine | ||
24 | driver. Selecting this option will allow these drivers to be built | ||
25 | without an explicit machine driver for test and development purposes. | ||
26 | |||
27 | If unsure select "N". | ||
28 | |||
29 | |||
1 | config SND_SOC_AC97_CODEC | 30 | config SND_SOC_AC97_CODEC |
2 | tristate | 31 | tristate |
3 | select SND_AC97_CODEC | 32 | select SND_AC97_CODEC |
4 | 33 | ||
34 | config SND_SOC_AD1980 | ||
35 | tristate | ||
36 | |||
5 | config SND_SOC_AK4535 | 37 | config SND_SOC_AK4535 |
6 | tristate | 38 | tristate |
7 | 39 | ||
40 | # Cirrus Logic CS4270 Codec | ||
41 | config SND_SOC_CS4270 | ||
42 | tristate | ||
43 | |||
44 | # Cirrus Logic CS4270 Codec Hardware Mute Support | ||
45 | # Select if you have external muting circuitry attached to your CS4270. | ||
46 | config SND_SOC_CS4270_HWMUTE | ||
47 | bool | ||
48 | depends on SND_SOC_CS4270 | ||
49 | |||
50 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | ||
51 | # Select if you are affected by the errata where the part will not function | ||
52 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | ||
53 | # not select any sample rates that require MCLK to be divided by 1.5. | ||
54 | config SND_SOC_CS4270_VD33_ERRATA | ||
55 | bool | ||
56 | depends on SND_SOC_CS4270 | ||
57 | |||
58 | config SND_SOC_SSM2602 | ||
59 | tristate | ||
60 | |||
61 | config SND_SOC_TLV320AIC26 | ||
62 | tristate "TI TLV320AIC26 Codec support" | ||
63 | depends on SND_SOC && SPI | ||
64 | |||
65 | config SND_SOC_TLV320AIC3X | ||
66 | tristate | ||
67 | depends on I2C | ||
68 | |||
8 | config SND_SOC_UDA1380 | 69 | config SND_SOC_UDA1380 |
9 | tristate | 70 | tristate |
10 | 71 | ||
11 | config SND_SOC_WM8510 | 72 | config SND_SOC_WM8510 |
12 | tristate | 73 | tristate |
13 | 74 | ||
75 | config SND_SOC_WM8580 | ||
76 | tristate | ||
77 | |||
14 | config SND_SOC_WM8731 | 78 | config SND_SOC_WM8731 |
15 | tristate | 79 | tristate |
16 | 80 | ||
@@ -20,33 +84,20 @@ config SND_SOC_WM8750 | |||
20 | config SND_SOC_WM8753 | 84 | config SND_SOC_WM8753 |
21 | tristate | 85 | tristate |
22 | 86 | ||
23 | config SND_SOC_WM8990 | 87 | config SND_SOC_WM8900 |
24 | tristate | 88 | tristate |
25 | 89 | ||
26 | config SND_SOC_WM9712 | 90 | config SND_SOC_WM8903 |
27 | tristate | 91 | tristate |
28 | 92 | ||
29 | config SND_SOC_WM9713 | 93 | config SND_SOC_WM8971 |
30 | tristate | 94 | tristate |
31 | 95 | ||
32 | # Cirrus Logic CS4270 Codec | 96 | config SND_SOC_WM8990 |
33 | config SND_SOC_CS4270 | ||
34 | tristate | 97 | tristate |
35 | 98 | ||
36 | # Cirrus Logic CS4270 Codec Hardware Mute Support | 99 | config SND_SOC_WM9712 |
37 | # Select if you have external muting circuitry attached to your CS4270. | 100 | tristate |
38 | config SND_SOC_CS4270_HWMUTE | ||
39 | bool | ||
40 | depends on SND_SOC_CS4270 | ||
41 | |||
42 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | ||
43 | # Select if you are affected by the errata where the part will not function | ||
44 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | ||
45 | # not select any sample rates that require MCLK to be divided by 1.5. | ||
46 | config SND_SOC_CS4270_VD33_ERRATA | ||
47 | bool | ||
48 | depends on SND_SOC_CS4270 | ||
49 | 101 | ||
50 | config SND_SOC_TLV320AIC3X | 102 | config SND_SOC_WM9713 |
51 | tristate | 103 | tristate |
52 | depends on I2C | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d7b97abcf72..f977978a340 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,25 +1,39 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ad1980-objs := ad1980.o | ||
2 | snd-soc-ak4535-objs := ak4535.o | 3 | snd-soc-ak4535-objs := ak4535.o |
4 | snd-soc-cs4270-objs := cs4270.o | ||
5 | snd-soc-ssm2602-objs := ssm2602.o | ||
6 | snd-soc-tlv320aic26-objs := tlv320aic26.o | ||
7 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
3 | snd-soc-uda1380-objs := uda1380.o | 8 | snd-soc-uda1380-objs := uda1380.o |
4 | snd-soc-wm8510-objs := wm8510.o | 9 | snd-soc-wm8510-objs := wm8510.o |
10 | snd-soc-wm8580-objs := wm8580.o | ||
5 | snd-soc-wm8731-objs := wm8731.o | 11 | snd-soc-wm8731-objs := wm8731.o |
6 | snd-soc-wm8750-objs := wm8750.o | 12 | snd-soc-wm8750-objs := wm8750.o |
7 | snd-soc-wm8753-objs := wm8753.o | 13 | snd-soc-wm8753-objs := wm8753.o |
14 | snd-soc-wm8900-objs := wm8900.o | ||
15 | snd-soc-wm8903-objs := wm8903.o | ||
16 | snd-soc-wm8971-objs := wm8971.o | ||
8 | snd-soc-wm8990-objs := wm8990.o | 17 | snd-soc-wm8990-objs := wm8990.o |
9 | snd-soc-wm9712-objs := wm9712.o | 18 | snd-soc-wm9712-objs := wm9712.o |
10 | snd-soc-wm9713-objs := wm9713.o | 19 | snd-soc-wm9713-objs := wm9713.o |
11 | snd-soc-cs4270-objs := cs4270.o | ||
12 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
13 | 20 | ||
14 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 21 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
22 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | ||
15 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 23 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | ||
25 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | ||
26 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | ||
27 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
16 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | 28 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o |
17 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 29 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
30 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o | ||
18 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 31 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
19 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 32 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
20 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 33 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
34 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | ||
35 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | ||
36 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | ||
21 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 37 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
22 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 38 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
23 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 39 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | ||
25 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c new file mode 100644 index 00000000000..4e09c1f2c06 --- /dev/null +++ b/sound/soc/codecs/ad1980.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * ad1980.c -- ALSA Soc AD1980 codec support | ||
3 | * | ||
4 | * Copyright: Analog Device Inc. | ||
5 | * Author: Roy Huang <roy.huang@analog.com> | ||
6 | * Cliff Cai <cliff.cai@analog.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/ac97_codec.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dapm.h> | ||
25 | |||
26 | #include "ad1980.h" | ||
27 | |||
28 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
29 | unsigned int reg); | ||
30 | static int ac97_write(struct snd_soc_codec *codec, | ||
31 | unsigned int reg, unsigned int val); | ||
32 | |||
33 | /* | ||
34 | * AD1980 register cache | ||
35 | */ | ||
36 | static const u16 ad1980_reg[] = { | ||
37 | 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ | ||
38 | 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ | ||
39 | 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ | ||
40 | 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ | ||
41 | 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ | ||
42 | 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ | ||
43 | 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ | ||
44 | 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ | ||
45 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
46 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
47 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
48 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
49 | 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ | ||
50 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
51 | 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ | ||
52 | 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ | ||
53 | }; | ||
54 | |||
55 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", | ||
56 | "Stereo Mix", "Mono Mix", "Phone"}; | ||
57 | |||
58 | static const struct soc_enum ad1980_cap_src = | ||
59 | SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); | ||
60 | |||
61 | static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { | ||
62 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), | ||
63 | SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1), | ||
64 | |||
65 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | ||
66 | SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1), | ||
67 | |||
68 | SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1), | ||
69 | SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1), | ||
70 | |||
71 | SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0), | ||
72 | SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1), | ||
73 | |||
74 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), | ||
75 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | ||
76 | |||
77 | SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1), | ||
78 | SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1), | ||
79 | |||
80 | SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1), | ||
81 | SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), | ||
82 | |||
83 | SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0), | ||
84 | SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), | ||
85 | |||
86 | SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), | ||
87 | SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), | ||
88 | |||
89 | SOC_ENUM("Capture Source", ad1980_cap_src), | ||
90 | |||
91 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), | ||
92 | }; | ||
93 | |||
94 | /* add non dapm controls */ | ||
95 | static int ad1980_add_controls(struct snd_soc_codec *codec) | ||
96 | { | ||
97 | int err, i; | ||
98 | |||
99 | for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) { | ||
100 | err = snd_ctl_add(codec->card, snd_soc_cnew( | ||
101 | &ad1980_snd_ac97_controls[i], codec, NULL)); | ||
102 | if (err < 0) | ||
103 | return err; | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
109 | unsigned int reg) | ||
110 | { | ||
111 | u16 *cache = codec->reg_cache; | ||
112 | |||
113 | switch (reg) { | ||
114 | case AC97_RESET: | ||
115 | case AC97_INT_PAGING: | ||
116 | case AC97_POWERDOWN: | ||
117 | case AC97_EXTENDED_STATUS: | ||
118 | case AC97_VENDOR_ID1: | ||
119 | case AC97_VENDOR_ID2: | ||
120 | return soc_ac97_ops.read(codec->ac97, reg); | ||
121 | default: | ||
122 | reg = reg >> 1; | ||
123 | |||
124 | if (reg >= (ARRAY_SIZE(ad1980_reg))) | ||
125 | return -EINVAL; | ||
126 | |||
127 | return cache[reg]; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
132 | unsigned int val) | ||
133 | { | ||
134 | u16 *cache = codec->reg_cache; | ||
135 | |||
136 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
137 | reg = reg >> 1; | ||
138 | if (reg < (ARRAY_SIZE(ad1980_reg))) | ||
139 | cache[reg] = val; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | struct snd_soc_dai ad1980_dai = { | ||
145 | .name = "AC97", | ||
146 | .playback = { | ||
147 | .stream_name = "Playback", | ||
148 | .channels_min = 2, | ||
149 | .channels_max = 2, | ||
150 | .rates = SNDRV_PCM_RATE_48000, | ||
151 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
152 | .capture = { | ||
153 | .stream_name = "Capture", | ||
154 | .channels_min = 2, | ||
155 | .channels_max = 2, | ||
156 | .rates = SNDRV_PCM_RATE_48000, | ||
157 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
158 | }; | ||
159 | EXPORT_SYMBOL_GPL(ad1980_dai); | ||
160 | |||
161 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) | ||
162 | { | ||
163 | u16 retry_cnt = 0; | ||
164 | |||
165 | retry: | ||
166 | if (try_warm && soc_ac97_ops.warm_reset) { | ||
167 | soc_ac97_ops.warm_reset(codec->ac97); | ||
168 | if (ac97_read(codec, AC97_RESET) == 0x0090) | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | soc_ac97_ops.reset(codec->ac97); | ||
173 | /* Set bit 16slot in register 74h, then every slot will has only 16 | ||
174 | * bits. This command is sent out in 20bit mode, in which case the | ||
175 | * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ | ||
176 | ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); | ||
177 | |||
178 | if (ac97_read(codec, AC97_RESET) != 0x0090) | ||
179 | goto err; | ||
180 | return 0; | ||
181 | |||
182 | err: | ||
183 | while (retry_cnt++ < 10) | ||
184 | goto retry; | ||
185 | |||
186 | printk(KERN_ERR "AD1980 AC97 reset failed\n"); | ||
187 | return -EIO; | ||
188 | } | ||
189 | |||
190 | static int ad1980_soc_probe(struct platform_device *pdev) | ||
191 | { | ||
192 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
193 | struct snd_soc_codec *codec; | ||
194 | int ret = 0; | ||
195 | u16 vendor_id2; | ||
196 | |||
197 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | ||
198 | |||
199 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
200 | if (socdev->codec == NULL) | ||
201 | return -ENOMEM; | ||
202 | codec = socdev->codec; | ||
203 | mutex_init(&codec->mutex); | ||
204 | |||
205 | codec->reg_cache = | ||
206 | kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL); | ||
207 | if (codec->reg_cache == NULL) { | ||
208 | ret = -ENOMEM; | ||
209 | goto cache_err; | ||
210 | } | ||
211 | memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \ | ||
212 | ARRAY_SIZE(ad1980_reg)); | ||
213 | codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg); | ||
214 | codec->reg_cache_step = 2; | ||
215 | codec->name = "AD1980"; | ||
216 | codec->owner = THIS_MODULE; | ||
217 | codec->dai = &ad1980_dai; | ||
218 | codec->num_dai = 1; | ||
219 | codec->write = ac97_write; | ||
220 | codec->read = ac97_read; | ||
221 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
222 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
223 | |||
224 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
225 | if (ret < 0) { | ||
226 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); | ||
227 | goto codec_err; | ||
228 | } | ||
229 | |||
230 | /* register pcms */ | ||
231 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
232 | if (ret < 0) | ||
233 | goto pcm_err; | ||
234 | |||
235 | |||
236 | ret = ad1980_reset(codec, 0); | ||
237 | if (ret < 0) { | ||
238 | printk(KERN_ERR "AC97 link error\n"); | ||
239 | goto reset_err; | ||
240 | } | ||
241 | |||
242 | /* Read out vendor ID to make sure it is ad1980 */ | ||
243 | if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) | ||
244 | goto reset_err; | ||
245 | |||
246 | vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); | ||
247 | |||
248 | if (vendor_id2 != 0x5370) { | ||
249 | if (vendor_id2 != 0x5374) | ||
250 | goto reset_err; | ||
251 | else | ||
252 | printk(KERN_WARNING "ad1980: " | ||
253 | "Found AD1981 - only 2/2 IN/OUT Channels " | ||
254 | "supported\n"); | ||
255 | } | ||
256 | |||
257 | ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ | ||
258 | ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ | ||
259 | ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ | ||
260 | |||
261 | ad1980_add_controls(codec); | ||
262 | ret = snd_soc_register_card(socdev); | ||
263 | if (ret < 0) { | ||
264 | printk(KERN_ERR "ad1980: failed to register card\n"); | ||
265 | goto reset_err; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | |||
270 | reset_err: | ||
271 | snd_soc_free_pcms(socdev); | ||
272 | |||
273 | pcm_err: | ||
274 | snd_soc_free_ac97_codec(codec); | ||
275 | |||
276 | codec_err: | ||
277 | kfree(codec->reg_cache); | ||
278 | |||
279 | cache_err: | ||
280 | kfree(socdev->codec); | ||
281 | socdev->codec = NULL; | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | static int ad1980_soc_remove(struct platform_device *pdev) | ||
286 | { | ||
287 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
288 | struct snd_soc_codec *codec = socdev->codec; | ||
289 | |||
290 | if (codec == NULL) | ||
291 | return 0; | ||
292 | |||
293 | snd_soc_dapm_free(socdev); | ||
294 | snd_soc_free_pcms(socdev); | ||
295 | snd_soc_free_ac97_codec(codec); | ||
296 | kfree(codec->reg_cache); | ||
297 | kfree(codec); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | struct snd_soc_codec_device soc_codec_dev_ad1980 = { | ||
302 | .probe = ad1980_soc_probe, | ||
303 | .remove = ad1980_soc_remove, | ||
304 | }; | ||
305 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); | ||
306 | |||
307 | MODULE_DESCRIPTION("ASoC ad1980 driver"); | ||
308 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); | ||
309 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h new file mode 100644 index 00000000000..db6c8500d66 --- /dev/null +++ b/sound/soc/codecs/ad1980.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * ad1980.h -- ad1980 Soc Audio driver | ||
3 | */ | ||
4 | |||
5 | #ifndef _AD1980_H | ||
6 | #define _AD1980_H | ||
7 | /* Bit definition of Power-Down Control/Status Register */ | ||
8 | #define ADC 0x0001 | ||
9 | #define DAC 0x0002 | ||
10 | #define ANL 0x0004 | ||
11 | #define REF 0x0008 | ||
12 | #define PR0 0x0100 | ||
13 | #define PR1 0x0200 | ||
14 | #define PR2 0x0400 | ||
15 | #define PR3 0x0800 | ||
16 | #define PR4 0x1000 | ||
17 | #define PR5 0x2000 | ||
18 | #define PR6 0x4000 | ||
19 | |||
20 | extern struct snd_soc_dai ad1980_dai; | ||
21 | extern struct snd_soc_codec_device soc_codec_dev_ad1980; | ||
22 | |||
23 | #endif | ||
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 7da9f467b7b..088cf992772 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -535,87 +535,85 @@ static struct snd_soc_device *ak4535_socdev; | |||
535 | 535 | ||
536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
537 | 537 | ||
538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | 538 | static int ak4535_i2c_probe(struct i2c_client *i2c, |
539 | 539 | const struct i2c_device_id *id) | |
540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
541 | |||
542 | /* Magic definition of all other variables and things */ | ||
543 | I2C_CLIENT_INSMOD; | ||
544 | |||
545 | static struct i2c_driver ak4535_i2c_driver; | ||
546 | static struct i2c_client client_template; | ||
547 | |||
548 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
549 | around */ | ||
550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
551 | { | 540 | { |
552 | struct snd_soc_device *socdev = ak4535_socdev; | 541 | struct snd_soc_device *socdev = ak4535_socdev; |
553 | struct ak4535_setup_data *setup = socdev->codec_data; | ||
554 | struct snd_soc_codec *codec = socdev->codec; | 542 | struct snd_soc_codec *codec = socdev->codec; |
555 | struct i2c_client *i2c; | ||
556 | int ret; | 543 | int ret; |
557 | 544 | ||
558 | if (addr != setup->i2c_address) | ||
559 | return -ENODEV; | ||
560 | |||
561 | client_template.adapter = adap; | ||
562 | client_template.addr = addr; | ||
563 | |||
564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
565 | if (i2c == NULL) | ||
566 | return -ENOMEM; | ||
567 | |||
568 | i2c_set_clientdata(i2c, codec); | 545 | i2c_set_clientdata(i2c, codec); |
569 | codec->control_data = i2c; | 546 | codec->control_data = i2c; |
570 | 547 | ||
571 | ret = i2c_attach_client(i2c); | ||
572 | if (ret < 0) { | ||
573 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); | ||
574 | goto err; | ||
575 | } | ||
576 | |||
577 | ret = ak4535_init(socdev); | 548 | ret = ak4535_init(socdev); |
578 | if (ret < 0) { | 549 | if (ret < 0) |
579 | printk(KERN_ERR "failed to initialise AK4535\n"); | 550 | printk(KERN_ERR "failed to initialise AK4535\n"); |
580 | goto err; | ||
581 | } | ||
582 | return ret; | ||
583 | 551 | ||
584 | err: | ||
585 | kfree(i2c); | ||
586 | return ret; | 552 | return ret; |
587 | } | 553 | } |
588 | 554 | ||
589 | static int ak4535_i2c_detach(struct i2c_client *client) | 555 | static int ak4535_i2c_remove(struct i2c_client *client) |
590 | { | 556 | { |
591 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 557 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
592 | i2c_detach_client(client); | ||
593 | kfree(codec->reg_cache); | 558 | kfree(codec->reg_cache); |
594 | kfree(client); | ||
595 | return 0; | 559 | return 0; |
596 | } | 560 | } |
597 | 561 | ||
598 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | 562 | static const struct i2c_device_id ak4535_i2c_id[] = { |
599 | { | 563 | { "ak4535", 0 }, |
600 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | 564 | { } |
601 | } | 565 | }; |
566 | MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); | ||
602 | 567 | ||
603 | /* corgi i2c codec control layer */ | ||
604 | static struct i2c_driver ak4535_i2c_driver = { | 568 | static struct i2c_driver ak4535_i2c_driver = { |
605 | .driver = { | 569 | .driver = { |
606 | .name = "AK4535 I2C Codec", | 570 | .name = "AK4535 I2C Codec", |
607 | .owner = THIS_MODULE, | 571 | .owner = THIS_MODULE, |
608 | }, | 572 | }, |
609 | .id = I2C_DRIVERID_AK4535, | 573 | .probe = ak4535_i2c_probe, |
610 | .attach_adapter = ak4535_i2c_attach, | 574 | .remove = ak4535_i2c_remove, |
611 | .detach_client = ak4535_i2c_detach, | 575 | .id_table = ak4535_i2c_id, |
612 | .command = NULL, | ||
613 | }; | 576 | }; |
614 | 577 | ||
615 | static struct i2c_client client_template = { | 578 | static int ak4535_add_i2c_device(struct platform_device *pdev, |
616 | .name = "AK4535", | 579 | const struct ak4535_setup_data *setup) |
617 | .driver = &ak4535_i2c_driver, | 580 | { |
618 | }; | 581 | struct i2c_board_info info; |
582 | struct i2c_adapter *adapter; | ||
583 | struct i2c_client *client; | ||
584 | int ret; | ||
585 | |||
586 | ret = i2c_add_driver(&ak4535_i2c_driver); | ||
587 | if (ret != 0) { | ||
588 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
589 | return ret; | ||
590 | } | ||
591 | |||
592 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
593 | info.addr = setup->i2c_address; | ||
594 | strlcpy(info.type, "ak4535", I2C_NAME_SIZE); | ||
595 | |||
596 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
597 | if (!adapter) { | ||
598 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
599 | setup->i2c_bus); | ||
600 | goto err_driver; | ||
601 | } | ||
602 | |||
603 | client = i2c_new_device(adapter, &info); | ||
604 | i2c_put_adapter(adapter); | ||
605 | if (!client) { | ||
606 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
607 | (unsigned int)info.addr); | ||
608 | goto err_driver; | ||
609 | } | ||
610 | |||
611 | return 0; | ||
612 | |||
613 | err_driver: | ||
614 | i2c_del_driver(&ak4535_i2c_driver); | ||
615 | return -ENODEV; | ||
616 | } | ||
619 | #endif | 617 | #endif |
620 | 618 | ||
621 | static int ak4535_probe(struct platform_device *pdev) | 619 | static int ak4535_probe(struct platform_device *pdev) |
@@ -624,7 +622,7 @@ static int ak4535_probe(struct platform_device *pdev) | |||
624 | struct ak4535_setup_data *setup; | 622 | struct ak4535_setup_data *setup; |
625 | struct snd_soc_codec *codec; | 623 | struct snd_soc_codec *codec; |
626 | struct ak4535_priv *ak4535; | 624 | struct ak4535_priv *ak4535; |
627 | int ret = 0; | 625 | int ret; |
628 | 626 | ||
629 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | 627 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); |
630 | 628 | ||
@@ -646,17 +644,14 @@ static int ak4535_probe(struct platform_device *pdev) | |||
646 | INIT_LIST_HEAD(&codec->dapm_paths); | 644 | INIT_LIST_HEAD(&codec->dapm_paths); |
647 | 645 | ||
648 | ak4535_socdev = socdev; | 646 | ak4535_socdev = socdev; |
647 | ret = -ENODEV; | ||
648 | |||
649 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 649 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
650 | if (setup->i2c_address) { | 650 | if (setup->i2c_address) { |
651 | normal_i2c[0] = setup->i2c_address; | ||
652 | codec->hw_write = (hw_write_t)i2c_master_send; | 651 | codec->hw_write = (hw_write_t)i2c_master_send; |
653 | codec->hw_read = (hw_read_t)i2c_master_recv; | 652 | codec->hw_read = (hw_read_t)i2c_master_recv; |
654 | ret = i2c_add_driver(&ak4535_i2c_driver); | 653 | ret = ak4535_add_i2c_device(pdev, setup); |
655 | if (ret != 0) | ||
656 | printk(KERN_ERR "can't add i2c driver"); | ||
657 | } | 654 | } |
658 | #else | ||
659 | /* Add other interfaces here */ | ||
660 | #endif | 655 | #endif |
661 | 656 | ||
662 | if (ret != 0) { | 657 | if (ret != 0) { |
@@ -678,6 +673,7 @@ static int ak4535_remove(struct platform_device *pdev) | |||
678 | snd_soc_free_pcms(socdev); | 673 | snd_soc_free_pcms(socdev); |
679 | snd_soc_dapm_free(socdev); | 674 | snd_soc_dapm_free(socdev); |
680 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 675 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
676 | i2c_unregister_device(codec->control_data); | ||
681 | i2c_del_driver(&ak4535_i2c_driver); | 677 | i2c_del_driver(&ak4535_i2c_driver); |
682 | #endif | 678 | #endif |
683 | kfree(codec->private_data); | 679 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h index e9fe30e2c05..c7a58703ea3 100644 --- a/sound/soc/codecs/ak4535.h +++ b/sound/soc/codecs/ak4535.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #define AK4535_CACHEREGNUM 0x10 | 37 | #define AK4535_CACHEREGNUM 0x10 |
38 | 38 | ||
39 | struct ak4535_setup_data { | 39 | struct ak4535_setup_data { |
40 | int i2c_bus; | ||
40 | unsigned short i2c_address; | 41 | unsigned short i2c_address; |
41 | }; | 42 | }; |
42 | 43 | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 9deb8c74fdf..0bbd94501d7 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -490,34 +490,7 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute) | |||
490 | 490 | ||
491 | #endif | 491 | #endif |
492 | 492 | ||
493 | static int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind); | 493 | static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *); |
494 | |||
495 | /* | ||
496 | * Notify the driver that a new I2C bus has been found. | ||
497 | * | ||
498 | * This function is called for each I2C bus in the system. The function | ||
499 | * then asks the I2C subsystem to probe that bus at the addresses on which | ||
500 | * our device (the CS4270) could exist. If a device is found at one of | ||
501 | * those addresses, then our probe function (cs4270_i2c_probe) is called. | ||
502 | */ | ||
503 | static int cs4270_i2c_attach(struct i2c_adapter *adapter) | ||
504 | { | ||
505 | return i2c_probe(adapter, &addr_data, cs4270_i2c_probe); | ||
506 | } | ||
507 | |||
508 | static int cs4270_i2c_detach(struct i2c_client *client) | ||
509 | { | ||
510 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
511 | |||
512 | i2c_detach_client(client); | ||
513 | codec->control_data = NULL; | ||
514 | |||
515 | kfree(codec->reg_cache); | ||
516 | codec->reg_cache = NULL; | ||
517 | |||
518 | kfree(client); | ||
519 | return 0; | ||
520 | } | ||
521 | 494 | ||
522 | /* A list of non-DAPM controls that the CS4270 supports */ | 495 | /* A list of non-DAPM controls that the CS4270 supports */ |
523 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { | 496 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { |
@@ -525,14 +498,19 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { | |||
525 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) | 498 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) |
526 | }; | 499 | }; |
527 | 500 | ||
501 | static const struct i2c_device_id cs4270_id[] = { | ||
502 | {"cs4270", 0}, | ||
503 | {} | ||
504 | }; | ||
505 | MODULE_DEVICE_TABLE(i2c, cs4270_id); | ||
506 | |||
528 | static struct i2c_driver cs4270_i2c_driver = { | 507 | static struct i2c_driver cs4270_i2c_driver = { |
529 | .driver = { | 508 | .driver = { |
530 | .name = "CS4270 I2C", | 509 | .name = "CS4270 I2C", |
531 | .owner = THIS_MODULE, | 510 | .owner = THIS_MODULE, |
532 | }, | 511 | }, |
533 | .id = I2C_DRIVERID_CS4270, | 512 | .id_table = cs4270_id, |
534 | .attach_adapter = cs4270_i2c_attach, | 513 | .probe = cs4270_i2c_probe, |
535 | .detach_client = cs4270_i2c_detach, | ||
536 | }; | 514 | }; |
537 | 515 | ||
538 | /* | 516 | /* |
@@ -561,11 +539,11 @@ static struct snd_soc_device *cs4270_socdev; | |||
561 | * Note: snd_soc_new_pcms() must be called before this function can be called, | 539 | * Note: snd_soc_new_pcms() must be called before this function can be called, |
562 | * because of snd_ctl_add(). | 540 | * because of snd_ctl_add(). |
563 | */ | 541 | */ |
564 | static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | 542 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, |
543 | const struct i2c_device_id *id) | ||
565 | { | 544 | { |
566 | struct snd_soc_device *socdev = cs4270_socdev; | 545 | struct snd_soc_device *socdev = cs4270_socdev; |
567 | struct snd_soc_codec *codec = socdev->codec; | 546 | struct snd_soc_codec *codec = socdev->codec; |
568 | struct i2c_client *i2c_client = NULL; | ||
569 | int i; | 547 | int i; |
570 | int ret = 0; | 548 | int ret = 0; |
571 | 549 | ||
@@ -578,12 +556,6 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
578 | 556 | ||
579 | /* Note: codec_dai->codec is NULL here */ | 557 | /* Note: codec_dai->codec is NULL here */ |
580 | 558 | ||
581 | i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
582 | if (!i2c_client) { | ||
583 | printk(KERN_ERR "cs4270: could not allocate I2C client\n"); | ||
584 | return -ENOMEM; | ||
585 | } | ||
586 | |||
587 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); | 559 | codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); |
588 | if (!codec->reg_cache) { | 560 | if (!codec->reg_cache) { |
589 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); | 561 | printk(KERN_ERR "cs4270: could not allocate register cache\n"); |
@@ -591,13 +563,6 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
591 | goto error; | 563 | goto error; |
592 | } | 564 | } |
593 | 565 | ||
594 | i2c_set_clientdata(i2c_client, codec); | ||
595 | strcpy(i2c_client->name, "CS4270"); | ||
596 | |||
597 | i2c_client->driver = &cs4270_i2c_driver; | ||
598 | i2c_client->adapter = adapter; | ||
599 | i2c_client->addr = addr; | ||
600 | |||
601 | /* Verify that we have a CS4270 */ | 566 | /* Verify that we have a CS4270 */ |
602 | 567 | ||
603 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | 568 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); |
@@ -612,18 +577,10 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
612 | goto error; | 577 | goto error; |
613 | } | 578 | } |
614 | 579 | ||
615 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr); | 580 | printk(KERN_INFO "cs4270: found device at I2C address %X\n", |
581 | i2c_client->addr); | ||
616 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); | 582 | printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); |
617 | 583 | ||
618 | /* Tell the I2C layer a new client has arrived */ | ||
619 | |||
620 | ret = i2c_attach_client(i2c_client); | ||
621 | if (ret) { | ||
622 | printk(KERN_ERR "cs4270: could not attach codec, " | ||
623 | "I2C address %x, error code %i\n", addr, ret); | ||
624 | goto error; | ||
625 | } | ||
626 | |||
627 | codec->control_data = i2c_client; | 584 | codec->control_data = i2c_client; |
628 | codec->read = cs4270_read_reg_cache; | 585 | codec->read = cs4270_read_reg_cache; |
629 | codec->write = cs4270_i2c_write; | 586 | codec->write = cs4270_i2c_write; |
@@ -648,20 +605,17 @@ static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) | |||
648 | goto error; | 605 | goto error; |
649 | } | 606 | } |
650 | 607 | ||
608 | i2c_set_clientdata(i2c_client, codec); | ||
609 | |||
651 | return 0; | 610 | return 0; |
652 | 611 | ||
653 | error: | 612 | error: |
654 | if (codec->control_data) { | 613 | codec->control_data = NULL; |
655 | i2c_detach_client(i2c_client); | ||
656 | codec->control_data = NULL; | ||
657 | } | ||
658 | 614 | ||
659 | kfree(codec->reg_cache); | 615 | kfree(codec->reg_cache); |
660 | codec->reg_cache = NULL; | 616 | codec->reg_cache = NULL; |
661 | codec->reg_cache_size = 0; | 617 | codec->reg_cache_size = 0; |
662 | 618 | ||
663 | kfree(i2c_client); | ||
664 | |||
665 | return ret; | 619 | return ret; |
666 | } | 620 | } |
667 | 621 | ||
@@ -727,7 +681,7 @@ static int cs4270_probe(struct platform_device *pdev) | |||
727 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 681 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
728 | if (ret < 0) { | 682 | if (ret < 0) { |
729 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); | 683 | printk(KERN_ERR "cs4270: failed to create PCMs\n"); |
730 | return ret; | 684 | goto error_free_codec; |
731 | } | 685 | } |
732 | 686 | ||
733 | #ifdef USE_I2C | 687 | #ifdef USE_I2C |
@@ -736,8 +690,7 @@ static int cs4270_probe(struct platform_device *pdev) | |||
736 | ret = i2c_add_driver(&cs4270_i2c_driver); | 690 | ret = i2c_add_driver(&cs4270_i2c_driver); |
737 | if (ret) { | 691 | if (ret) { |
738 | printk(KERN_ERR "cs4270: failed to attach driver"); | 692 | printk(KERN_ERR "cs4270: failed to attach driver"); |
739 | snd_soc_free_pcms(socdev); | 693 | goto error_free_pcms; |
740 | return ret; | ||
741 | } | 694 | } |
742 | 695 | ||
743 | /* Did we find a CS4270 on the I2C bus? */ | 696 | /* Did we find a CS4270 on the I2C bus? */ |
@@ -759,10 +712,23 @@ static int cs4270_probe(struct platform_device *pdev) | |||
759 | ret = snd_soc_register_card(socdev); | 712 | ret = snd_soc_register_card(socdev); |
760 | if (ret < 0) { | 713 | if (ret < 0) { |
761 | printk(KERN_ERR "cs4270: failed to register card\n"); | 714 | printk(KERN_ERR "cs4270: failed to register card\n"); |
762 | snd_soc_free_pcms(socdev); | 715 | goto error_del_driver; |
763 | return ret; | ||
764 | } | 716 | } |
765 | 717 | ||
718 | return 0; | ||
719 | |||
720 | error_del_driver: | ||
721 | #ifdef USE_I2C | ||
722 | i2c_del_driver(&cs4270_i2c_driver); | ||
723 | |||
724 | error_free_pcms: | ||
725 | #endif | ||
726 | snd_soc_free_pcms(socdev); | ||
727 | |||
728 | error_free_codec: | ||
729 | kfree(socdev->codec); | ||
730 | socdev->codec = NULL; | ||
731 | |||
766 | return ret; | 732 | return ret; |
767 | } | 733 | } |
768 | 734 | ||
@@ -773,8 +739,7 @@ static int cs4270_remove(struct platform_device *pdev) | |||
773 | snd_soc_free_pcms(socdev); | 739 | snd_soc_free_pcms(socdev); |
774 | 740 | ||
775 | #ifdef USE_I2C | 741 | #ifdef USE_I2C |
776 | if (socdev->codec->control_data) | 742 | i2c_del_driver(&cs4270_i2c_driver); |
777 | i2c_del_driver(&cs4270_i2c_driver); | ||
778 | #endif | 743 | #endif |
779 | 744 | ||
780 | kfree(socdev->codec); | 745 | kfree(socdev->codec); |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c new file mode 100644 index 00000000000..940ce1c3522 --- /dev/null +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -0,0 +1,776 @@ | |||
1 | /* | ||
2 | * File: sound/soc/codecs/ssm2602.c | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * Description: Driver for ssm2602 sound chip | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2008 Analog Devices Inc. | ||
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, see the file COPYING, or write | ||
25 | * to the Free Software Foundation, Inc., | ||
26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/pm.h> | ||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <sound/core.h> | ||
37 | #include <sound/pcm.h> | ||
38 | #include <sound/pcm_params.h> | ||
39 | #include <sound/soc.h> | ||
40 | #include <sound/soc-dapm.h> | ||
41 | #include <sound/initval.h> | ||
42 | |||
43 | #include "ssm2602.h" | ||
44 | |||
45 | #define AUDIO_NAME "ssm2602" | ||
46 | #define SSM2602_VERSION "0.1" | ||
47 | |||
48 | struct snd_soc_codec_device soc_codec_dev_ssm2602; | ||
49 | |||
50 | /* codec private data */ | ||
51 | struct ssm2602_priv { | ||
52 | unsigned int sysclk; | ||
53 | struct snd_pcm_substream *master_substream; | ||
54 | struct snd_pcm_substream *slave_substream; | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * ssm2602 register cache | ||
59 | * We can't read the ssm2602 register space when we are | ||
60 | * using 2 wire for device control, so we cache them instead. | ||
61 | * There is no point in caching the reset register | ||
62 | */ | ||
63 | static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { | ||
64 | 0x0017, 0x0017, 0x0079, 0x0079, | ||
65 | 0x0000, 0x0000, 0x0000, 0x000a, | ||
66 | 0x0000, 0x0000 | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * read ssm2602 register cache | ||
71 | */ | ||
72 | static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec, | ||
73 | unsigned int reg) | ||
74 | { | ||
75 | u16 *cache = codec->reg_cache; | ||
76 | if (reg == SSM2602_RESET) | ||
77 | return 0; | ||
78 | if (reg >= SSM2602_CACHEREGNUM) | ||
79 | return -1; | ||
80 | return cache[reg]; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * write ssm2602 register cache | ||
85 | */ | ||
86 | static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec, | ||
87 | u16 reg, unsigned int value) | ||
88 | { | ||
89 | u16 *cache = codec->reg_cache; | ||
90 | if (reg >= SSM2602_CACHEREGNUM) | ||
91 | return; | ||
92 | cache[reg] = value; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * write to the ssm2602 register space | ||
97 | */ | ||
98 | static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg, | ||
99 | unsigned int value) | ||
100 | { | ||
101 | u8 data[2]; | ||
102 | |||
103 | /* data is | ||
104 | * D15..D9 ssm2602 register offset | ||
105 | * D8...D0 register data | ||
106 | */ | ||
107 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
108 | data[1] = value & 0x00ff; | ||
109 | |||
110 | ssm2602_write_reg_cache(codec, reg, value); | ||
111 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
112 | return 0; | ||
113 | else | ||
114 | return -EIO; | ||
115 | } | ||
116 | |||
117 | #define ssm2602_reset(c) ssm2602_write(c, SSM2602_RESET, 0) | ||
118 | |||
119 | /*Appending several "None"s just for OSS mixer use*/ | ||
120 | static const char *ssm2602_input_select[] = { | ||
121 | "Line", "Mic", "None", "None", "None", | ||
122 | "None", "None", "None", | ||
123 | }; | ||
124 | |||
125 | static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
126 | |||
127 | static const struct soc_enum ssm2602_enum[] = { | ||
128 | SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select), | ||
129 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), | ||
130 | }; | ||
131 | |||
132 | static const struct snd_kcontrol_new ssm2602_snd_controls[] = { | ||
133 | |||
134 | SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
135 | 0, 127, 0), | ||
136 | SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
137 | 7, 1, 0), | ||
138 | |||
139 | SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), | ||
140 | SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), | ||
141 | |||
142 | SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), | ||
143 | SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), | ||
144 | |||
145 | SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1), | ||
146 | |||
147 | SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), | ||
148 | SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), | ||
149 | |||
150 | SOC_ENUM("Capture Source", ssm2602_enum[0]), | ||
151 | |||
152 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), | ||
153 | }; | ||
154 | |||
155 | /* add non dapm controls */ | ||
156 | static int ssm2602_add_controls(struct snd_soc_codec *codec) | ||
157 | { | ||
158 | int err, i; | ||
159 | |||
160 | for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) { | ||
161 | err = snd_ctl_add(codec->card, | ||
162 | snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL)); | ||
163 | if (err < 0) | ||
164 | return err; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* Output Mixer */ | ||
171 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { | ||
172 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), | ||
173 | SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), | ||
174 | SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), | ||
175 | }; | ||
176 | |||
177 | /* Input mux */ | ||
178 | static const struct snd_kcontrol_new ssm2602_input_mux_controls = | ||
179 | SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); | ||
180 | |||
181 | static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { | ||
182 | SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, | ||
183 | &ssm2602_output_mixer_controls[0], | ||
184 | ARRAY_SIZE(ssm2602_output_mixer_controls)), | ||
185 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), | ||
186 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
187 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
188 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
189 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
190 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), | ||
191 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), | ||
192 | SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), | ||
193 | SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), | ||
194 | SND_SOC_DAPM_INPUT("MICIN"), | ||
195 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
196 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
197 | }; | ||
198 | |||
199 | static const struct snd_soc_dapm_route audio_conn[] = { | ||
200 | /* output mixer */ | ||
201 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
202 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | ||
203 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | ||
204 | |||
205 | /* outputs */ | ||
206 | {"RHPOUT", NULL, "Output Mixer"}, | ||
207 | {"ROUT", NULL, "Output Mixer"}, | ||
208 | {"LHPOUT", NULL, "Output Mixer"}, | ||
209 | {"LOUT", NULL, "Output Mixer"}, | ||
210 | |||
211 | /* input mux */ | ||
212 | {"Input Mux", "Line", "Line Input"}, | ||
213 | {"Input Mux", "Mic", "Mic Bias"}, | ||
214 | {"ADC", NULL, "Input Mux"}, | ||
215 | |||
216 | /* inputs */ | ||
217 | {"Line Input", NULL, "LLINEIN"}, | ||
218 | {"Line Input", NULL, "RLINEIN"}, | ||
219 | {"Mic Bias", NULL, "MICIN"}, | ||
220 | }; | ||
221 | |||
222 | static int ssm2602_add_widgets(struct snd_soc_codec *codec) | ||
223 | { | ||
224 | snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets, | ||
225 | ARRAY_SIZE(ssm2602_dapm_widgets)); | ||
226 | |||
227 | snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn)); | ||
228 | |||
229 | snd_soc_dapm_new_widgets(codec); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | struct _coeff_div { | ||
234 | u32 mclk; | ||
235 | u32 rate; | ||
236 | u16 fs; | ||
237 | u8 sr:4; | ||
238 | u8 bosr:1; | ||
239 | u8 usb:1; | ||
240 | }; | ||
241 | |||
242 | /* codec mclk clock divider coefficients */ | ||
243 | static const struct _coeff_div coeff_div[] = { | ||
244 | /* 48k */ | ||
245 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | ||
246 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | ||
247 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | ||
248 | |||
249 | /* 32k */ | ||
250 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | ||
251 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | ||
252 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | ||
253 | |||
254 | /* 8k */ | ||
255 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | ||
256 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | ||
257 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | ||
258 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | ||
259 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | ||
260 | |||
261 | /* 96k */ | ||
262 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | ||
263 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | ||
264 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | ||
265 | |||
266 | /* 44.1k */ | ||
267 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | ||
268 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | ||
269 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | ||
270 | |||
271 | /* 88.2k */ | ||
272 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | ||
273 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | ||
274 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | ||
275 | }; | ||
276 | |||
277 | static inline int get_coeff(int mclk, int rate) | ||
278 | { | ||
279 | int i; | ||
280 | |||
281 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
282 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
283 | return i; | ||
284 | } | ||
285 | return i; | ||
286 | } | ||
287 | |||
288 | static int ssm2602_hw_params(struct snd_pcm_substream *substream, | ||
289 | struct snd_pcm_hw_params *params) | ||
290 | { | ||
291 | u16 srate; | ||
292 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
293 | struct snd_soc_device *socdev = rtd->socdev; | ||
294 | struct snd_soc_codec *codec = socdev->codec; | ||
295 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
296 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; | ||
297 | int i = get_coeff(ssm2602->sysclk, params_rate(params)); | ||
298 | |||
299 | /*no match is found*/ | ||
300 | if (i == ARRAY_SIZE(coeff_div)) | ||
301 | return -EINVAL; | ||
302 | |||
303 | srate = (coeff_div[i].sr << 2) | | ||
304 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | ||
305 | |||
306 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
307 | ssm2602_write(codec, SSM2602_SRATE, srate); | ||
308 | |||
309 | /* bit size */ | ||
310 | switch (params_format(params)) { | ||
311 | case SNDRV_PCM_FORMAT_S16_LE: | ||
312 | break; | ||
313 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
314 | iface |= 0x0004; | ||
315 | break; | ||
316 | case SNDRV_PCM_FORMAT_S24_LE: | ||
317 | iface |= 0x0008; | ||
318 | break; | ||
319 | case SNDRV_PCM_FORMAT_S32_LE: | ||
320 | iface |= 0x000c; | ||
321 | break; | ||
322 | } | ||
323 | ssm2602_write(codec, SSM2602_IFACE, iface); | ||
324 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int ssm2602_startup(struct snd_pcm_substream *substream) | ||
329 | { | ||
330 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
331 | struct snd_soc_device *socdev = rtd->socdev; | ||
332 | struct snd_soc_codec *codec = socdev->codec; | ||
333 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
334 | struct snd_pcm_runtime *master_runtime; | ||
335 | |||
336 | /* The DAI has shared clocks so if we already have a playback or | ||
337 | * capture going then constrain this substream to match it. | ||
338 | */ | ||
339 | if (ssm2602->master_substream) { | ||
340 | master_runtime = ssm2602->master_substream->runtime; | ||
341 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
342 | SNDRV_PCM_HW_PARAM_RATE, | ||
343 | master_runtime->rate, | ||
344 | master_runtime->rate); | ||
345 | |||
346 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
347 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
348 | master_runtime->sample_bits, | ||
349 | master_runtime->sample_bits); | ||
350 | |||
351 | ssm2602->slave_substream = substream; | ||
352 | } else | ||
353 | ssm2602->master_substream = substream; | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) | ||
359 | { | ||
360 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
361 | struct snd_soc_device *socdev = rtd->socdev; | ||
362 | struct snd_soc_codec *codec = socdev->codec; | ||
363 | /* set active */ | ||
364 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static void ssm2602_shutdown(struct snd_pcm_substream *substream) | ||
370 | { | ||
371 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
372 | struct snd_soc_device *socdev = rtd->socdev; | ||
373 | struct snd_soc_codec *codec = socdev->codec; | ||
374 | /* deactivate */ | ||
375 | if (!codec->active) | ||
376 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
377 | } | ||
378 | |||
379 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) | ||
380 | { | ||
381 | struct snd_soc_codec *codec = dai->codec; | ||
382 | u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; | ||
383 | if (mute) | ||
384 | ssm2602_write(codec, SSM2602_APDIGI, | ||
385 | mute_reg | APDIGI_ENABLE_DAC_MUTE); | ||
386 | else | ||
387 | ssm2602_write(codec, SSM2602_APDIGI, mute_reg); | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
392 | int clk_id, unsigned int freq, int dir) | ||
393 | { | ||
394 | struct snd_soc_codec *codec = codec_dai->codec; | ||
395 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
396 | switch (freq) { | ||
397 | case 11289600: | ||
398 | case 12000000: | ||
399 | case 12288000: | ||
400 | case 16934400: | ||
401 | case 18432000: | ||
402 | ssm2602->sysclk = freq; | ||
403 | return 0; | ||
404 | } | ||
405 | return -EINVAL; | ||
406 | } | ||
407 | |||
408 | static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
409 | unsigned int fmt) | ||
410 | { | ||
411 | struct snd_soc_codec *codec = codec_dai->codec; | ||
412 | u16 iface = 0; | ||
413 | |||
414 | /* set master/slave audio interface */ | ||
415 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
416 | case SND_SOC_DAIFMT_CBM_CFM: | ||
417 | iface |= 0x0040; | ||
418 | break; | ||
419 | case SND_SOC_DAIFMT_CBS_CFS: | ||
420 | break; | ||
421 | default: | ||
422 | return -EINVAL; | ||
423 | } | ||
424 | |||
425 | /* interface format */ | ||
426 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
427 | case SND_SOC_DAIFMT_I2S: | ||
428 | iface |= 0x0002; | ||
429 | break; | ||
430 | case SND_SOC_DAIFMT_RIGHT_J: | ||
431 | break; | ||
432 | case SND_SOC_DAIFMT_LEFT_J: | ||
433 | iface |= 0x0001; | ||
434 | break; | ||
435 | case SND_SOC_DAIFMT_DSP_A: | ||
436 | iface |= 0x0003; | ||
437 | break; | ||
438 | case SND_SOC_DAIFMT_DSP_B: | ||
439 | iface |= 0x0013; | ||
440 | break; | ||
441 | default: | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | |||
445 | /* clock inversion */ | ||
446 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
447 | case SND_SOC_DAIFMT_NB_NF: | ||
448 | break; | ||
449 | case SND_SOC_DAIFMT_IB_IF: | ||
450 | iface |= 0x0090; | ||
451 | break; | ||
452 | case SND_SOC_DAIFMT_IB_NF: | ||
453 | iface |= 0x0080; | ||
454 | break; | ||
455 | case SND_SOC_DAIFMT_NB_IF: | ||
456 | iface |= 0x0010; | ||
457 | break; | ||
458 | default: | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | /* set iface */ | ||
463 | ssm2602_write(codec, SSM2602_IFACE, iface); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | ||
468 | enum snd_soc_bias_level level) | ||
469 | { | ||
470 | u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f; | ||
471 | |||
472 | switch (level) { | ||
473 | case SND_SOC_BIAS_ON: | ||
474 | /* vref/mid, osc on, dac unmute */ | ||
475 | ssm2602_write(codec, SSM2602_PWR, reg); | ||
476 | break; | ||
477 | case SND_SOC_BIAS_PREPARE: | ||
478 | break; | ||
479 | case SND_SOC_BIAS_STANDBY: | ||
480 | /* everything off except vref/vmid, */ | ||
481 | ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); | ||
482 | break; | ||
483 | case SND_SOC_BIAS_OFF: | ||
484 | /* everything off, dac mute, inactive */ | ||
485 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
486 | ssm2602_write(codec, SSM2602_PWR, 0xffff); | ||
487 | break; | ||
488 | |||
489 | } | ||
490 | codec->bias_level = level; | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | #define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
495 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
496 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
497 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | ||
498 | SNDRV_PCM_RATE_96000) | ||
499 | |||
500 | struct snd_soc_dai ssm2602_dai = { | ||
501 | .name = "SSM2602", | ||
502 | .playback = { | ||
503 | .stream_name = "Playback", | ||
504 | .channels_min = 2, | ||
505 | .channels_max = 2, | ||
506 | .rates = SSM2602_RATES, | ||
507 | .formats = SNDRV_PCM_FMTBIT_S32_LE,}, | ||
508 | .capture = { | ||
509 | .stream_name = "Capture", | ||
510 | .channels_min = 2, | ||
511 | .channels_max = 2, | ||
512 | .rates = SSM2602_RATES, | ||
513 | .formats = SNDRV_PCM_FMTBIT_S32_LE,}, | ||
514 | .ops = { | ||
515 | .startup = ssm2602_startup, | ||
516 | .prepare = ssm2602_pcm_prepare, | ||
517 | .hw_params = ssm2602_hw_params, | ||
518 | .shutdown = ssm2602_shutdown, | ||
519 | }, | ||
520 | .dai_ops = { | ||
521 | .digital_mute = ssm2602_mute, | ||
522 | .set_sysclk = ssm2602_set_dai_sysclk, | ||
523 | .set_fmt = ssm2602_set_dai_fmt, | ||
524 | } | ||
525 | }; | ||
526 | EXPORT_SYMBOL_GPL(ssm2602_dai); | ||
527 | |||
528 | static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) | ||
529 | { | ||
530 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
531 | struct snd_soc_codec *codec = socdev->codec; | ||
532 | |||
533 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int ssm2602_resume(struct platform_device *pdev) | ||
538 | { | ||
539 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
540 | struct snd_soc_codec *codec = socdev->codec; | ||
541 | int i; | ||
542 | u8 data[2]; | ||
543 | u16 *cache = codec->reg_cache; | ||
544 | |||
545 | /* Sync reg_cache with the hardware */ | ||
546 | for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) { | ||
547 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
548 | data[1] = cache[i] & 0x00ff; | ||
549 | codec->hw_write(codec->control_data, data, 2); | ||
550 | } | ||
551 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
552 | ssm2602_set_bias_level(codec, codec->suspend_bias_level); | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | /* | ||
557 | * initialise the ssm2602 driver | ||
558 | * register the mixer and dsp interfaces with the kernel | ||
559 | */ | ||
560 | static int ssm2602_init(struct snd_soc_device *socdev) | ||
561 | { | ||
562 | struct snd_soc_codec *codec = socdev->codec; | ||
563 | int reg, ret = 0; | ||
564 | |||
565 | codec->name = "SSM2602"; | ||
566 | codec->owner = THIS_MODULE; | ||
567 | codec->read = ssm2602_read_reg_cache; | ||
568 | codec->write = ssm2602_write; | ||
569 | codec->set_bias_level = ssm2602_set_bias_level; | ||
570 | codec->dai = &ssm2602_dai; | ||
571 | codec->num_dai = 1; | ||
572 | codec->reg_cache_size = sizeof(ssm2602_reg); | ||
573 | codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg), | ||
574 | GFP_KERNEL); | ||
575 | if (codec->reg_cache == NULL) | ||
576 | return -ENOMEM; | ||
577 | |||
578 | ssm2602_reset(codec); | ||
579 | |||
580 | /* register pcms */ | ||
581 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
582 | if (ret < 0) { | ||
583 | pr_err("ssm2602: failed to create pcms\n"); | ||
584 | goto pcm_err; | ||
585 | } | ||
586 | /*power on device*/ | ||
587 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
588 | /* set the update bits */ | ||
589 | reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL); | ||
590 | ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); | ||
591 | reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL); | ||
592 | ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); | ||
593 | reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V); | ||
594 | ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | ||
595 | reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V); | ||
596 | ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | ||
597 | /*select Line in as default input*/ | ||
598 | ssm2602_write(codec, SSM2602_APANA, | ||
599 | APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC | | ||
600 | APANA_ENABLE_MIC_BOOST); | ||
601 | ssm2602_write(codec, SSM2602_PWR, 0); | ||
602 | |||
603 | ssm2602_add_controls(codec); | ||
604 | ssm2602_add_widgets(codec); | ||
605 | ret = snd_soc_register_card(socdev); | ||
606 | if (ret < 0) { | ||
607 | pr_err("ssm2602: failed to register card\n"); | ||
608 | goto card_err; | ||
609 | } | ||
610 | |||
611 | return ret; | ||
612 | |||
613 | card_err: | ||
614 | snd_soc_free_pcms(socdev); | ||
615 | snd_soc_dapm_free(socdev); | ||
616 | pcm_err: | ||
617 | kfree(codec->reg_cache); | ||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | static struct snd_soc_device *ssm2602_socdev; | ||
622 | |||
623 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
624 | /* | ||
625 | * ssm2602 2 wire address is determined by GPIO5 | ||
626 | * state during powerup. | ||
627 | * low = 0x1a | ||
628 | * high = 0x1b | ||
629 | */ | ||
630 | static int ssm2602_i2c_probe(struct i2c_client *i2c, | ||
631 | const struct i2c_device_id *id) | ||
632 | { | ||
633 | struct snd_soc_device *socdev = ssm2602_socdev; | ||
634 | struct snd_soc_codec *codec = socdev->codec; | ||
635 | int ret; | ||
636 | |||
637 | i2c_set_clientdata(i2c, codec); | ||
638 | codec->control_data = i2c; | ||
639 | |||
640 | ret = ssm2602_init(socdev); | ||
641 | if (ret < 0) | ||
642 | pr_err("failed to initialise SSM2602\n"); | ||
643 | |||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | static int ssm2602_i2c_remove(struct i2c_client *client) | ||
648 | { | ||
649 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
650 | kfree(codec->reg_cache); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static const struct i2c_device_id ssm2602_i2c_id[] = { | ||
655 | { "ssm2602", 0 }, | ||
656 | { } | ||
657 | }; | ||
658 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | ||
659 | /* corgi i2c codec control layer */ | ||
660 | static struct i2c_driver ssm2602_i2c_driver = { | ||
661 | .driver = { | ||
662 | .name = "SSM2602 I2C Codec", | ||
663 | .owner = THIS_MODULE, | ||
664 | }, | ||
665 | .probe = ssm2602_i2c_probe, | ||
666 | .remove = ssm2602_i2c_remove, | ||
667 | .id_table = ssm2602_i2c_id, | ||
668 | }; | ||
669 | |||
670 | static int ssm2602_add_i2c_device(struct platform_device *pdev, | ||
671 | const struct ssm2602_setup_data *setup) | ||
672 | { | ||
673 | struct i2c_board_info info; | ||
674 | struct i2c_adapter *adapter; | ||
675 | struct i2c_client *client; | ||
676 | int ret; | ||
677 | |||
678 | ret = i2c_add_driver(&ssm2602_i2c_driver); | ||
679 | if (ret != 0) { | ||
680 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
681 | return ret; | ||
682 | } | ||
683 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
684 | info.addr = setup->i2c_address; | ||
685 | strlcpy(info.type, "ssm2602", I2C_NAME_SIZE); | ||
686 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
687 | if (!adapter) { | ||
688 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
689 | setup->i2c_bus); | ||
690 | goto err_driver; | ||
691 | } | ||
692 | client = i2c_new_device(adapter, &info); | ||
693 | i2c_put_adapter(adapter); | ||
694 | if (!client) { | ||
695 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
696 | (unsigned int)info.addr); | ||
697 | goto err_driver; | ||
698 | } | ||
699 | return 0; | ||
700 | err_driver: | ||
701 | i2c_del_driver(&ssm2602_i2c_driver); | ||
702 | return -ENODEV; | ||
703 | } | ||
704 | #endif | ||
705 | |||
706 | static int ssm2602_probe(struct platform_device *pdev) | ||
707 | { | ||
708 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
709 | struct ssm2602_setup_data *setup; | ||
710 | struct snd_soc_codec *codec; | ||
711 | struct ssm2602_priv *ssm2602; | ||
712 | int ret = 0; | ||
713 | |||
714 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | ||
715 | |||
716 | setup = socdev->codec_data; | ||
717 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
718 | if (codec == NULL) | ||
719 | return -ENOMEM; | ||
720 | |||
721 | ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); | ||
722 | if (ssm2602 == NULL) { | ||
723 | kfree(codec); | ||
724 | return -ENOMEM; | ||
725 | } | ||
726 | |||
727 | codec->private_data = ssm2602; | ||
728 | socdev->codec = codec; | ||
729 | mutex_init(&codec->mutex); | ||
730 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
731 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
732 | |||
733 | ssm2602_socdev = socdev; | ||
734 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
735 | if (setup->i2c_address) { | ||
736 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
737 | ret = ssm2602_add_i2c_device(pdev, setup); | ||
738 | } | ||
739 | #else | ||
740 | /* other interfaces */ | ||
741 | #endif | ||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | /* remove everything here */ | ||
746 | static int ssm2602_remove(struct platform_device *pdev) | ||
747 | { | ||
748 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
749 | struct snd_soc_codec *codec = socdev->codec; | ||
750 | |||
751 | if (codec->control_data) | ||
752 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
753 | |||
754 | snd_soc_free_pcms(socdev); | ||
755 | snd_soc_dapm_free(socdev); | ||
756 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
757 | i2c_unregister_device(codec->control_data); | ||
758 | i2c_del_driver(&ssm2602_i2c_driver); | ||
759 | #endif | ||
760 | kfree(codec->private_data); | ||
761 | kfree(codec); | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | struct snd_soc_codec_device soc_codec_dev_ssm2602 = { | ||
767 | .probe = ssm2602_probe, | ||
768 | .remove = ssm2602_remove, | ||
769 | .suspend = ssm2602_suspend, | ||
770 | .resume = ssm2602_resume, | ||
771 | }; | ||
772 | EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); | ||
773 | |||
774 | MODULE_DESCRIPTION("ASoC ssm2602 driver"); | ||
775 | MODULE_AUTHOR("Cliff Cai"); | ||
776 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h new file mode 100644 index 00000000000..f344e6d76e3 --- /dev/null +++ b/sound/soc/codecs/ssm2602.h | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * File: sound/soc/codecs/ssm2602.h | ||
3 | * Author: Cliff Cai <Cliff.Cai@analog.com> | ||
4 | * | ||
5 | * Created: Tue June 06 2008 | ||
6 | * | ||
7 | * Modified: | ||
8 | * Copyright 2008 Analog Devices Inc. | ||
9 | * | ||
10 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, see the file COPYING, or write | ||
24 | * to the Free Software Foundation, Inc., | ||
25 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
26 | */ | ||
27 | |||
28 | #ifndef _SSM2602_H | ||
29 | #define _SSM2602_H | ||
30 | |||
31 | /* SSM2602 Codec Register definitions */ | ||
32 | |||
33 | #define SSM2602_LINVOL 0x00 | ||
34 | #define SSM2602_RINVOL 0x01 | ||
35 | #define SSM2602_LOUT1V 0x02 | ||
36 | #define SSM2602_ROUT1V 0x03 | ||
37 | #define SSM2602_APANA 0x04 | ||
38 | #define SSM2602_APDIGI 0x05 | ||
39 | #define SSM2602_PWR 0x06 | ||
40 | #define SSM2602_IFACE 0x07 | ||
41 | #define SSM2602_SRATE 0x08 | ||
42 | #define SSM2602_ACTIVE 0x09 | ||
43 | #define SSM2602_RESET 0x0f | ||
44 | |||
45 | /*SSM2602 Codec Register Field definitions | ||
46 | *(Mask value to extract the corresponding Register field) | ||
47 | */ | ||
48 | |||
49 | /*Left ADC Volume Control (SSM2602_REG_LEFT_ADC_VOL)*/ | ||
50 | #define LINVOL_LIN_VOL 0x01F /* Left Channel PGA Volume control */ | ||
51 | #define LINVOL_LIN_ENABLE_MUTE 0x080 /* Left Channel Input Mute */ | ||
52 | #define LINVOL_LRIN_BOTH 0x100 /* Left Channel Line Input Volume update */ | ||
53 | |||
54 | /*Right ADC Volume Control (SSM2602_REG_RIGHT_ADC_VOL)*/ | ||
55 | #define RINVOL_RIN_VOL 0x01F /* Right Channel PGA Volume control */ | ||
56 | #define RINVOL_RIN_ENABLE_MUTE 0x080 /* Right Channel Input Mute */ | ||
57 | #define RINVOL_RLIN_BOTH 0x100 /* Right Channel Line Input Volume update */ | ||
58 | |||
59 | /*Left DAC Volume Control (SSM2602_REG_LEFT_DAC_VOL)*/ | ||
60 | #define LOUT1V_LHP_VOL 0x07F /* Left Channel Headphone volume control */ | ||
61 | #define LOUT1V_ENABLE_LZC 0x080 /* Left Channel Zero cross detect enable */ | ||
62 | #define LOUT1V_LRHP_BOTH 0x100 /* Left Channel Headphone volume update */ | ||
63 | |||
64 | /*Right DAC Volume Control (SSM2602_REG_RIGHT_DAC_VOL)*/ | ||
65 | #define ROUT1V_RHP_VOL 0x07F /* Right Channel Headphone volume control */ | ||
66 | #define ROUT1V_ENABLE_RZC 0x080 /* Right Channel Zero cross detect enable */ | ||
67 | #define ROUT1V_RLHP_BOTH 0x100 /* Right Channel Headphone volume update */ | ||
68 | |||
69 | /*Analogue Audio Path Control (SSM2602_REG_ANALOGUE_PATH)*/ | ||
70 | #define APANA_ENABLE_MIC_BOOST 0x001 /* Primary Microphone Amplifier gain booster control */ | ||
71 | #define APANA_ENABLE_MIC_MUTE 0x002 /* Microphone Mute Control */ | ||
72 | #define APANA_ADC_IN_SELECT 0x004 /* Microphone/Line IN select to ADC (1=MIC, 0=Line In) */ | ||
73 | #define APANA_ENABLE_BYPASS 0x008 /* Line input bypass to line output */ | ||
74 | #define APANA_SELECT_DAC 0x010 /* Select DAC (1=Select DAC, 0=Don't Select DAC) */ | ||
75 | #define APANA_ENABLE_SIDETONE 0x020 /* Enable/Disable Side Tone */ | ||
76 | #define APANA_SIDETONE_ATTN 0x0C0 /* Side Tone Attenuation */ | ||
77 | #define APANA_ENABLE_MIC_BOOST2 0x100 /* Secondary Microphone Amplifier gain booster control */ | ||
78 | |||
79 | /*Digital Audio Path Control (SSM2602_REG_DIGITAL_PATH)*/ | ||
80 | #define APDIGI_ENABLE_ADC_HPF 0x001 /* Enable/Disable ADC Highpass Filter */ | ||
81 | #define APDIGI_DE_EMPHASIS 0x006 /* De-Emphasis Control */ | ||
82 | #define APDIGI_ENABLE_DAC_MUTE 0x008 /* DAC Mute Control */ | ||
83 | #define APDIGI_STORE_OFFSET 0x010 /* Store/Clear DC offset when HPF is disabled */ | ||
84 | |||
85 | /*Power Down Control (SSM2602_REG_POWER) | ||
86 | *(1=Enable PowerDown, 0=Disable PowerDown) | ||
87 | */ | ||
88 | #define PWR_LINE_IN_PDN 0x001 /* Line Input Power Down */ | ||
89 | #define PWR_MIC_PDN 0x002 /* Microphone Input & Bias Power Down */ | ||
90 | #define PWR_ADC_PDN 0x004 /* ADC Power Down */ | ||
91 | #define PWR_DAC_PDN 0x008 /* DAC Power Down */ | ||
92 | #define PWR_OUT_PDN 0x010 /* Outputs Power Down */ | ||
93 | #define PWR_OSC_PDN 0x020 /* Oscillator Power Down */ | ||
94 | #define PWR_CLK_OUT_PDN 0x040 /* CLKOUT Power Down */ | ||
95 | #define PWR_POWER_OFF 0x080 /* POWEROFF Mode */ | ||
96 | |||
97 | /*Digital Audio Interface Format (SSM2602_REG_DIGITAL_IFACE)*/ | ||
98 | #define IFACE_IFACE_FORMAT 0x003 /* Digital Audio input format control */ | ||
99 | #define IFACE_AUDIO_DATA_LEN 0x00C /* Audio Data word length control */ | ||
100 | #define IFACE_DAC_LR_POLARITY 0x010 /* Polarity Control for clocks in RJ,LJ and I2S modes */ | ||
101 | #define IFACE_DAC_LR_SWAP 0x020 /* Swap DAC data control */ | ||
102 | #define IFACE_ENABLE_MASTER 0x040 /* Enable/Disable Master Mode */ | ||
103 | #define IFACE_BCLK_INVERT 0x080 /* Bit Clock Inversion control */ | ||
104 | |||
105 | /*Sampling Control (SSM2602_REG_SAMPLING_CTRL)*/ | ||
106 | #define SRATE_ENABLE_USB_MODE 0x001 /* Enable/Disable USB Mode */ | ||
107 | #define SRATE_BOS_RATE 0x002 /* Base Over-Sampling rate */ | ||
108 | #define SRATE_SAMPLE_RATE 0x03C /* Clock setting condition (Sampling rate control) */ | ||
109 | #define SRATE_CORECLK_DIV2 0x040 /* Core Clock divider select */ | ||
110 | #define SRATE_CLKOUT_DIV2 0x080 /* Clock Out divider select */ | ||
111 | |||
112 | /*Active Control (SSM2602_REG_ACTIVE_CTRL)*/ | ||
113 | #define ACTIVE_ACTIVATE_CODEC 0x001 /* Activate Codec Digital Audio Interface */ | ||
114 | |||
115 | /*********************************************************************/ | ||
116 | |||
117 | #define SSM2602_CACHEREGNUM 10 | ||
118 | |||
119 | #define SSM2602_SYSCLK 0 | ||
120 | #define SSM2602_DAI 0 | ||
121 | |||
122 | struct ssm2602_setup_data { | ||
123 | int i2c_bus; | ||
124 | unsigned short i2c_address; | ||
125 | }; | ||
126 | |||
127 | extern struct snd_soc_dai ssm2602_dai; | ||
128 | extern struct snd_soc_codec_device soc_codec_dev_ssm2602; | ||
129 | |||
130 | #endif | ||
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c new file mode 100644 index 00000000000..bed8a9e63dd --- /dev/null +++ b/sound/soc/codecs/tlv320aic26.c | |||
@@ -0,0 +1,520 @@ | |||
1 | /* | ||
2 | * Texas Instruments TLV320AIC26 low power audio CODEC | ||
3 | * ALSA SoC CODEC driver | ||
4 | * | ||
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/moduleparam.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/pm.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/sysfs.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/pcm.h> | ||
18 | #include <sound/pcm_params.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | #include <sound/soc-of-simple.h> | ||
22 | #include <sound/initval.h> | ||
23 | |||
24 | #include "tlv320aic26.h" | ||
25 | |||
26 | MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver"); | ||
27 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | /* AIC26 driver private data */ | ||
31 | struct aic26 { | ||
32 | struct spi_device *spi; | ||
33 | struct snd_soc_codec codec; | ||
34 | u16 reg_cache[AIC26_NUM_REGS]; /* shadow registers */ | ||
35 | int master; | ||
36 | int datfm; | ||
37 | int mclk; | ||
38 | |||
39 | /* Keyclick parameters */ | ||
40 | int keyclick_amplitude; | ||
41 | int keyclick_freq; | ||
42 | int keyclick_len; | ||
43 | }; | ||
44 | |||
45 | /* --------------------------------------------------------------------- | ||
46 | * Register access routines | ||
47 | */ | ||
48 | static unsigned int aic26_reg_read(struct snd_soc_codec *codec, | ||
49 | unsigned int reg) | ||
50 | { | ||
51 | struct aic26 *aic26 = codec->private_data; | ||
52 | u16 *cache = codec->reg_cache; | ||
53 | u16 cmd, value; | ||
54 | u8 buffer[2]; | ||
55 | int rc; | ||
56 | |||
57 | if (reg >= AIC26_NUM_REGS) { | ||
58 | WARN_ON_ONCE(1); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | /* Do SPI transfer; first 16bits are command; remaining is | ||
63 | * register contents */ | ||
64 | cmd = AIC26_READ_COMMAND_WORD(reg); | ||
65 | buffer[0] = (cmd >> 8) & 0xff; | ||
66 | buffer[1] = cmd & 0xff; | ||
67 | rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2); | ||
68 | if (rc) { | ||
69 | dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); | ||
70 | return -EIO; | ||
71 | } | ||
72 | value = (buffer[0] << 8) | buffer[1]; | ||
73 | |||
74 | /* Update the cache before returning with the value */ | ||
75 | cache[reg] = value; | ||
76 | return value; | ||
77 | } | ||
78 | |||
79 | static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec, | ||
80 | unsigned int reg) | ||
81 | { | ||
82 | u16 *cache = codec->reg_cache; | ||
83 | |||
84 | if (reg >= AIC26_NUM_REGS) { | ||
85 | WARN_ON_ONCE(1); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | return cache[reg]; | ||
90 | } | ||
91 | |||
92 | static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, | ||
93 | unsigned int value) | ||
94 | { | ||
95 | struct aic26 *aic26 = codec->private_data; | ||
96 | u16 *cache = codec->reg_cache; | ||
97 | u16 cmd; | ||
98 | u8 buffer[4]; | ||
99 | int rc; | ||
100 | |||
101 | if (reg >= AIC26_NUM_REGS) { | ||
102 | WARN_ON_ONCE(1); | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | /* Do SPI transfer; first 16bits are command; remaining is data | ||
107 | * to write into register */ | ||
108 | cmd = AIC26_WRITE_COMMAND_WORD(reg); | ||
109 | buffer[0] = (cmd >> 8) & 0xff; | ||
110 | buffer[1] = cmd & 0xff; | ||
111 | buffer[2] = value >> 8; | ||
112 | buffer[3] = value; | ||
113 | rc = spi_write(aic26->spi, buffer, 4); | ||
114 | if (rc) { | ||
115 | dev_err(&aic26->spi->dev, "AIC26 reg read error\n"); | ||
116 | return -EIO; | ||
117 | } | ||
118 | |||
119 | /* update cache before returning */ | ||
120 | cache[reg] = value; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* --------------------------------------------------------------------- | ||
125 | * Digital Audio Interface Operations | ||
126 | */ | ||
127 | static int aic26_hw_params(struct snd_pcm_substream *substream, | ||
128 | struct snd_pcm_hw_params *params) | ||
129 | { | ||
130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
131 | struct snd_soc_device *socdev = rtd->socdev; | ||
132 | struct snd_soc_codec *codec = socdev->codec; | ||
133 | struct aic26 *aic26 = codec->private_data; | ||
134 | int fsref, divisor, wlen, pval, jval, dval, qval; | ||
135 | u16 reg; | ||
136 | |||
137 | dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n", | ||
138 | substream, params); | ||
139 | dev_dbg(&aic26->spi->dev, "rate=%i format=%i\n", params_rate(params), | ||
140 | params_format(params)); | ||
141 | |||
142 | switch (params_rate(params)) { | ||
143 | case 8000: fsref = 48000; divisor = AIC26_DIV_6; break; | ||
144 | case 11025: fsref = 44100; divisor = AIC26_DIV_4; break; | ||
145 | case 12000: fsref = 48000; divisor = AIC26_DIV_4; break; | ||
146 | case 16000: fsref = 48000; divisor = AIC26_DIV_3; break; | ||
147 | case 22050: fsref = 44100; divisor = AIC26_DIV_2; break; | ||
148 | case 24000: fsref = 48000; divisor = AIC26_DIV_2; break; | ||
149 | case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break; | ||
150 | case 44100: fsref = 44100; divisor = AIC26_DIV_1; break; | ||
151 | case 48000: fsref = 48000; divisor = AIC26_DIV_1; break; | ||
152 | default: | ||
153 | dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* select data word length */ | ||
157 | switch (params_format(params)) { | ||
158 | case SNDRV_PCM_FORMAT_S8: wlen = AIC26_WLEN_16; break; | ||
159 | case SNDRV_PCM_FORMAT_S16_BE: wlen = AIC26_WLEN_16; break; | ||
160 | case SNDRV_PCM_FORMAT_S24_BE: wlen = AIC26_WLEN_24; break; | ||
161 | case SNDRV_PCM_FORMAT_S32_BE: wlen = AIC26_WLEN_32; break; | ||
162 | default: | ||
163 | dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL; | ||
164 | } | ||
165 | |||
166 | /* Configure PLL */ | ||
167 | pval = 1; | ||
168 | jval = (fsref == 44100) ? 7 : 8; | ||
169 | dval = (fsref == 44100) ? 5264 : 1920; | ||
170 | qval = 0; | ||
171 | reg = 0x8000 | qval << 11 | pval << 8 | jval << 2; | ||
172 | aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg); | ||
173 | reg = dval << 2; | ||
174 | aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg); | ||
175 | |||
176 | /* Audio Control 3 (master mode, fsref rate) */ | ||
177 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3); | ||
178 | reg &= ~0xf800; | ||
179 | if (aic26->master) | ||
180 | reg |= 0x0800; | ||
181 | if (fsref == 48000) | ||
182 | reg |= 0x2000; | ||
183 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg); | ||
184 | |||
185 | /* Audio Control 1 (FSref divisor) */ | ||
186 | reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1); | ||
187 | reg &= ~0x0fff; | ||
188 | reg |= wlen | aic26->datfm | (divisor << 3) | divisor; | ||
189 | aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * aic26_mute - Mute control to reduce noise when changing audio format | ||
196 | */ | ||
197 | static int aic26_mute(struct snd_soc_dai *dai, int mute) | ||
198 | { | ||
199 | struct snd_soc_codec *codec = dai->codec; | ||
200 | struct aic26 *aic26 = codec->private_data; | ||
201 | u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN); | ||
202 | |||
203 | dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n", | ||
204 | dai, mute); | ||
205 | |||
206 | if (mute) | ||
207 | reg |= 0x8080; | ||
208 | else | ||
209 | reg &= ~0x8080; | ||
210 | aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int aic26_set_sysclk(struct snd_soc_dai *codec_dai, | ||
216 | int clk_id, unsigned int freq, int dir) | ||
217 | { | ||
218 | struct snd_soc_codec *codec = codec_dai->codec; | ||
219 | struct aic26 *aic26 = codec->private_data; | ||
220 | |||
221 | dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i," | ||
222 | " freq=%i, dir=%i)\n", | ||
223 | codec_dai, clk_id, freq, dir); | ||
224 | |||
225 | /* MCLK needs to fall between 2MHz and 50 MHz */ | ||
226 | if ((freq < 2000000) || (freq > 50000000)) | ||
227 | return -EINVAL; | ||
228 | |||
229 | aic26->mclk = freq; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
234 | { | ||
235 | struct snd_soc_codec *codec = codec_dai->codec; | ||
236 | struct aic26 *aic26 = codec->private_data; | ||
237 | |||
238 | dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n", | ||
239 | codec_dai, fmt); | ||
240 | |||
241 | /* set master/slave audio interface */ | ||
242 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
243 | case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break; | ||
244 | case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break; | ||
245 | default: | ||
246 | dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL; | ||
247 | } | ||
248 | |||
249 | /* interface format */ | ||
250 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
251 | case SND_SOC_DAIFMT_I2S: aic26->datfm = AIC26_DATFM_I2S; break; | ||
252 | case SND_SOC_DAIFMT_DSP_A: aic26->datfm = AIC26_DATFM_DSP; break; | ||
253 | case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break; | ||
254 | case SND_SOC_DAIFMT_LEFT_J: aic26->datfm = AIC26_DATFM_LEFTJ; break; | ||
255 | default: | ||
256 | dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL; | ||
257 | } | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* --------------------------------------------------------------------- | ||
263 | * Digital Audio Interface Definition | ||
264 | */ | ||
265 | #define AIC26_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
266 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
267 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
268 | SNDRV_PCM_RATE_48000) | ||
269 | #define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\ | ||
270 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) | ||
271 | |||
272 | struct snd_soc_dai aic26_dai = { | ||
273 | .name = "tlv320aic26", | ||
274 | .playback = { | ||
275 | .stream_name = "Playback", | ||
276 | .channels_min = 2, | ||
277 | .channels_max = 2, | ||
278 | .rates = AIC26_RATES, | ||
279 | .formats = AIC26_FORMATS, | ||
280 | }, | ||
281 | .capture = { | ||
282 | .stream_name = "Capture", | ||
283 | .channels_min = 2, | ||
284 | .channels_max = 2, | ||
285 | .rates = AIC26_RATES, | ||
286 | .formats = AIC26_FORMATS, | ||
287 | }, | ||
288 | .ops = { | ||
289 | .hw_params = aic26_hw_params, | ||
290 | }, | ||
291 | .dai_ops = { | ||
292 | .digital_mute = aic26_mute, | ||
293 | .set_sysclk = aic26_set_sysclk, | ||
294 | .set_fmt = aic26_set_fmt, | ||
295 | }, | ||
296 | }; | ||
297 | EXPORT_SYMBOL_GPL(aic26_dai); | ||
298 | |||
299 | /* --------------------------------------------------------------------- | ||
300 | * ALSA controls | ||
301 | */ | ||
302 | static const char *aic26_capture_src_text[] = {"Mic", "Aux"}; | ||
303 | static const struct soc_enum aic26_capture_src_enum = | ||
304 | SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text); | ||
305 | |||
306 | static const struct snd_kcontrol_new aic26_snd_controls[] = { | ||
307 | /* Output */ | ||
308 | SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1), | ||
309 | SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1), | ||
310 | SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0), | ||
311 | SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1), | ||
312 | SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0), | ||
313 | SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0), | ||
314 | SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0), | ||
315 | SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0), | ||
316 | SOC_ENUM("Capture Source", aic26_capture_src_enum), | ||
317 | }; | ||
318 | |||
319 | /* --------------------------------------------------------------------- | ||
320 | * SoC CODEC portion of driver: probe and release routines | ||
321 | */ | ||
322 | static int aic26_probe(struct platform_device *pdev) | ||
323 | { | ||
324 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
325 | struct snd_soc_codec *codec; | ||
326 | struct snd_kcontrol *kcontrol; | ||
327 | struct aic26 *aic26; | ||
328 | int i, ret, err; | ||
329 | |||
330 | dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n"); | ||
331 | dev_dbg(&pdev->dev, "socdev=%p\n", socdev); | ||
332 | dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data); | ||
333 | |||
334 | /* Fetch the relevant aic26 private data here (it's already been | ||
335 | * stored in the .codec pointer) */ | ||
336 | aic26 = socdev->codec_data; | ||
337 | if (aic26 == NULL) { | ||
338 | dev_err(&pdev->dev, "aic26: missing codec pointer\n"); | ||
339 | return -ENODEV; | ||
340 | } | ||
341 | codec = &aic26->codec; | ||
342 | socdev->codec = codec; | ||
343 | |||
344 | dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n", | ||
345 | &pdev->dev, socdev->dev); | ||
346 | /* register pcms */ | ||
347 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
348 | if (ret < 0) { | ||
349 | dev_err(&pdev->dev, "aic26: failed to create pcms\n"); | ||
350 | return -ENODEV; | ||
351 | } | ||
352 | |||
353 | /* register controls */ | ||
354 | dev_dbg(&pdev->dev, "Registering controls\n"); | ||
355 | for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) { | ||
356 | kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL); | ||
357 | err = snd_ctl_add(codec->card, kcontrol); | ||
358 | WARN_ON(err < 0); | ||
359 | } | ||
360 | |||
361 | /* CODEC is setup, we can register the card now */ | ||
362 | dev_dbg(&pdev->dev, "Registering card\n"); | ||
363 | ret = snd_soc_register_card(socdev); | ||
364 | if (ret < 0) { | ||
365 | dev_err(&pdev->dev, "aic26: failed to register card\n"); | ||
366 | goto card_err; | ||
367 | } | ||
368 | return 0; | ||
369 | |||
370 | card_err: | ||
371 | snd_soc_free_pcms(socdev); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static int aic26_remove(struct platform_device *pdev) | ||
376 | { | ||
377 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
378 | snd_soc_free_pcms(socdev); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | struct snd_soc_codec_device aic26_soc_codec_dev = { | ||
383 | .probe = aic26_probe, | ||
384 | .remove = aic26_remove, | ||
385 | }; | ||
386 | EXPORT_SYMBOL_GPL(aic26_soc_codec_dev); | ||
387 | |||
388 | /* --------------------------------------------------------------------- | ||
389 | * SPI device portion of driver: sysfs files for debugging | ||
390 | */ | ||
391 | |||
392 | static ssize_t aic26_keyclick_show(struct device *dev, | ||
393 | struct device_attribute *attr, char *buf) | ||
394 | { | ||
395 | struct aic26 *aic26 = dev_get_drvdata(dev); | ||
396 | int val, amp, freq, len; | ||
397 | |||
398 | val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2); | ||
399 | amp = (val >> 12) & 0x7; | ||
400 | freq = (125 << ((val >> 8) & 0x7)) >> 1; | ||
401 | len = 2 * (1 + ((val >> 4) & 0xf)); | ||
402 | |||
403 | return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len); | ||
404 | } | ||
405 | |||
406 | /* Any write to the keyclick attribute will trigger the keyclick event */ | ||
407 | static ssize_t aic26_keyclick_set(struct device *dev, | ||
408 | struct device_attribute *attr, | ||
409 | const char *buf, size_t count) | ||
410 | { | ||
411 | struct aic26 *aic26 = dev_get_drvdata(dev); | ||
412 | int val; | ||
413 | |||
414 | val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2); | ||
415 | val |= 0x8000; | ||
416 | aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val); | ||
417 | |||
418 | return count; | ||
419 | } | ||
420 | |||
421 | static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); | ||
422 | |||
423 | /* --------------------------------------------------------------------- | ||
424 | * SPI device portion of driver: probe and release routines and SPI | ||
425 | * driver registration. | ||
426 | */ | ||
427 | static int aic26_spi_probe(struct spi_device *spi) | ||
428 | { | ||
429 | struct aic26 *aic26; | ||
430 | int rc, i, reg; | ||
431 | |||
432 | dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n"); | ||
433 | |||
434 | /* Allocate driver data */ | ||
435 | aic26 = kzalloc(sizeof *aic26, GFP_KERNEL); | ||
436 | if (!aic26) | ||
437 | return -ENOMEM; | ||
438 | |||
439 | /* Initialize the driver data */ | ||
440 | aic26->spi = spi; | ||
441 | dev_set_drvdata(&spi->dev, aic26); | ||
442 | |||
443 | /* Setup what we can in the codec structure so that the register | ||
444 | * access functions will work as expected. More will be filled | ||
445 | * out when it is probed by the SoC CODEC part of this driver */ | ||
446 | aic26->codec.private_data = aic26; | ||
447 | aic26->codec.name = "aic26"; | ||
448 | aic26->codec.owner = THIS_MODULE; | ||
449 | aic26->codec.dai = &aic26_dai; | ||
450 | aic26->codec.num_dai = 1; | ||
451 | aic26->codec.read = aic26_reg_read; | ||
452 | aic26->codec.write = aic26_reg_write; | ||
453 | aic26->master = 1; | ||
454 | mutex_init(&aic26->codec.mutex); | ||
455 | INIT_LIST_HEAD(&aic26->codec.dapm_widgets); | ||
456 | INIT_LIST_HEAD(&aic26->codec.dapm_paths); | ||
457 | aic26->codec.reg_cache_size = AIC26_NUM_REGS; | ||
458 | aic26->codec.reg_cache = aic26->reg_cache; | ||
459 | |||
460 | /* Reset the codec to power on defaults */ | ||
461 | aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00); | ||
462 | |||
463 | /* Power up CODEC */ | ||
464 | aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0); | ||
465 | |||
466 | /* Audio Control 3 (master mode, fsref rate) */ | ||
467 | reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3); | ||
468 | reg &= ~0xf800; | ||
469 | reg |= 0x0800; /* set master mode */ | ||
470 | aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg); | ||
471 | |||
472 | /* Fill register cache */ | ||
473 | for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++) | ||
474 | aic26_reg_read(&aic26->codec, i); | ||
475 | |||
476 | /* Register the sysfs files for debugging */ | ||
477 | /* Create SysFS files */ | ||
478 | rc = device_create_file(&spi->dev, &dev_attr_keyclick); | ||
479 | if (rc) | ||
480 | dev_info(&spi->dev, "error creating sysfs files\n"); | ||
481 | |||
482 | #if defined(CONFIG_SND_SOC_OF_SIMPLE) | ||
483 | /* Tell the of_soc helper about this codec */ | ||
484 | of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai, | ||
485 | spi->dev.archdata.of_node); | ||
486 | #endif | ||
487 | |||
488 | dev_dbg(&spi->dev, "SPI device initialized\n"); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int aic26_spi_remove(struct spi_device *spi) | ||
493 | { | ||
494 | struct aic26 *aic26 = dev_get_drvdata(&spi->dev); | ||
495 | |||
496 | kfree(aic26); | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static struct spi_driver aic26_spi = { | ||
502 | .driver = { | ||
503 | .name = "tlv320aic26", | ||
504 | .owner = THIS_MODULE, | ||
505 | }, | ||
506 | .probe = aic26_spi_probe, | ||
507 | .remove = aic26_spi_remove, | ||
508 | }; | ||
509 | |||
510 | static int __init aic26_init(void) | ||
511 | { | ||
512 | return spi_register_driver(&aic26_spi); | ||
513 | } | ||
514 | module_init(aic26_init); | ||
515 | |||
516 | static void __exit aic26_exit(void) | ||
517 | { | ||
518 | spi_unregister_driver(&aic26_spi); | ||
519 | } | ||
520 | module_exit(aic26_exit); | ||
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h new file mode 100644 index 00000000000..786ba16c945 --- /dev/null +++ b/sound/soc/codecs/tlv320aic26.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Texas Instruments TLV320AIC26 low power audio CODEC | ||
3 | * register definitions | ||
4 | * | ||
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | ||
6 | */ | ||
7 | |||
8 | #ifndef _TLV320AIC16_H_ | ||
9 | #define _TLV320AIC16_H_ | ||
10 | |||
11 | /* AIC26 Registers */ | ||
12 | #define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5)) | ||
13 | #define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5)) | ||
14 | #define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset) | ||
15 | #define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0) | ||
16 | |||
17 | /* Page 0: Auxillary data registers */ | ||
18 | #define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05) | ||
19 | #define AIC26_REG_BAT2 AIC26_PAGE_ADDR(0, 0x06) | ||
20 | #define AIC26_REG_AUX AIC26_PAGE_ADDR(0, 0x07) | ||
21 | #define AIC26_REG_TEMP1 AIC26_PAGE_ADDR(0, 0x09) | ||
22 | #define AIC26_REG_TEMP2 AIC26_PAGE_ADDR(0, 0x0A) | ||
23 | |||
24 | /* Page 1: Auxillary control registers */ | ||
25 | #define AIC26_REG_AUX_ADC AIC26_PAGE_ADDR(1, 0x00) | ||
26 | #define AIC26_REG_STATUS AIC26_PAGE_ADDR(1, 0x01) | ||
27 | #define AIC26_REG_REFERENCE AIC26_PAGE_ADDR(1, 0x03) | ||
28 | #define AIC26_REG_RESET AIC26_PAGE_ADDR(1, 0x04) | ||
29 | |||
30 | /* Page 2: Audio control registers */ | ||
31 | #define AIC26_REG_AUDIO_CTRL1 AIC26_PAGE_ADDR(2, 0x00) | ||
32 | #define AIC26_REG_ADC_GAIN AIC26_PAGE_ADDR(2, 0x01) | ||
33 | #define AIC26_REG_DAC_GAIN AIC26_PAGE_ADDR(2, 0x02) | ||
34 | #define AIC26_REG_SIDETONE AIC26_PAGE_ADDR(2, 0x03) | ||
35 | #define AIC26_REG_AUDIO_CTRL2 AIC26_PAGE_ADDR(2, 0x04) | ||
36 | #define AIC26_REG_POWER_CTRL AIC26_PAGE_ADDR(2, 0x05) | ||
37 | #define AIC26_REG_AUDIO_CTRL3 AIC26_PAGE_ADDR(2, 0x06) | ||
38 | |||
39 | #define AIC26_REG_FILTER_COEFF_L_N0 AIC26_PAGE_ADDR(2, 0x07) | ||
40 | #define AIC26_REG_FILTER_COEFF_L_N1 AIC26_PAGE_ADDR(2, 0x08) | ||
41 | #define AIC26_REG_FILTER_COEFF_L_N2 AIC26_PAGE_ADDR(2, 0x09) | ||
42 | #define AIC26_REG_FILTER_COEFF_L_N3 AIC26_PAGE_ADDR(2, 0x0A) | ||
43 | #define AIC26_REG_FILTER_COEFF_L_N4 AIC26_PAGE_ADDR(2, 0x0B) | ||
44 | #define AIC26_REG_FILTER_COEFF_L_N5 AIC26_PAGE_ADDR(2, 0x0C) | ||
45 | #define AIC26_REG_FILTER_COEFF_L_D1 AIC26_PAGE_ADDR(2, 0x0D) | ||
46 | #define AIC26_REG_FILTER_COEFF_L_D2 AIC26_PAGE_ADDR(2, 0x0E) | ||
47 | #define AIC26_REG_FILTER_COEFF_L_D4 AIC26_PAGE_ADDR(2, 0x0F) | ||
48 | #define AIC26_REG_FILTER_COEFF_L_D5 AIC26_PAGE_ADDR(2, 0x10) | ||
49 | #define AIC26_REG_FILTER_COEFF_R_N0 AIC26_PAGE_ADDR(2, 0x11) | ||
50 | #define AIC26_REG_FILTER_COEFF_R_N1 AIC26_PAGE_ADDR(2, 0x12) | ||
51 | #define AIC26_REG_FILTER_COEFF_R_N2 AIC26_PAGE_ADDR(2, 0x13) | ||
52 | #define AIC26_REG_FILTER_COEFF_R_N3 AIC26_PAGE_ADDR(2, 0x14) | ||
53 | #define AIC26_REG_FILTER_COEFF_R_N4 AIC26_PAGE_ADDR(2, 0x15) | ||
54 | #define AIC26_REG_FILTER_COEFF_R_N5 AIC26_PAGE_ADDR(2, 0x16) | ||
55 | #define AIC26_REG_FILTER_COEFF_R_D1 AIC26_PAGE_ADDR(2, 0x17) | ||
56 | #define AIC26_REG_FILTER_COEFF_R_D2 AIC26_PAGE_ADDR(2, 0x18) | ||
57 | #define AIC26_REG_FILTER_COEFF_R_D4 AIC26_PAGE_ADDR(2, 0x19) | ||
58 | #define AIC26_REG_FILTER_COEFF_R_D5 AIC26_PAGE_ADDR(2, 0x1A) | ||
59 | |||
60 | #define AIC26_REG_PLL_PROG1 AIC26_PAGE_ADDR(2, 0x1B) | ||
61 | #define AIC26_REG_PLL_PROG2 AIC26_PAGE_ADDR(2, 0x1C) | ||
62 | #define AIC26_REG_AUDIO_CTRL4 AIC26_PAGE_ADDR(2, 0x1D) | ||
63 | #define AIC26_REG_AUDIO_CTRL5 AIC26_PAGE_ADDR(2, 0x1E) | ||
64 | |||
65 | /* fsref dividers; used in register 'Audio Control 1' */ | ||
66 | enum aic26_divisors { | ||
67 | AIC26_DIV_1 = 0, | ||
68 | AIC26_DIV_1_5 = 1, | ||
69 | AIC26_DIV_2 = 2, | ||
70 | AIC26_DIV_3 = 3, | ||
71 | AIC26_DIV_4 = 4, | ||
72 | AIC26_DIV_5 = 5, | ||
73 | AIC26_DIV_5_5 = 6, | ||
74 | AIC26_DIV_6 = 7, | ||
75 | }; | ||
76 | |||
77 | /* Digital data format */ | ||
78 | enum aic26_datfm { | ||
79 | AIC26_DATFM_I2S = 0 << 8, | ||
80 | AIC26_DATFM_DSP = 1 << 8, | ||
81 | AIC26_DATFM_RIGHTJ = 2 << 8, /* right justified */ | ||
82 | AIC26_DATFM_LEFTJ = 3 << 8, /* left justified */ | ||
83 | }; | ||
84 | |||
85 | /* Sample word length in bits; used in register 'Audio Control 1' */ | ||
86 | enum aic26_wlen { | ||
87 | AIC26_WLEN_16 = 0 << 10, | ||
88 | AIC26_WLEN_20 = 1 << 10, | ||
89 | AIC26_WLEN_24 = 2 << 10, | ||
90 | AIC26_WLEN_32 = 3 << 10, | ||
91 | }; | ||
92 | |||
93 | extern struct snd_soc_dai aic26_dai; | ||
94 | extern struct snd_soc_codec_device aic26_soc_codec_dev; | ||
95 | |||
96 | #endif /* _TLV320AIC16_H_ */ | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5f9abb19943..566a427c928 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC TLV320AIC3X codec driver | 2 | * ALSA SoC TLV320AIC3X codec driver |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood | 7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood |
@@ -1172,71 +1172,39 @@ static struct snd_soc_device *aic3x_socdev; | |||
1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses | 1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses |
1173 | * 0x18, 0x19, 0x1A, 0x1B | 1173 | * 0x18, 0x19, 0x1A, 0x1B |
1174 | */ | 1174 | */ |
1175 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1176 | |||
1177 | /* Magic definition of all other variables and things */ | ||
1178 | I2C_CLIENT_INSMOD; | ||
1179 | |||
1180 | static struct i2c_driver aic3x_i2c_driver; | ||
1181 | static struct i2c_client client_template; | ||
1182 | 1175 | ||
1183 | /* | 1176 | /* |
1184 | * If the i2c layer weren't so broken, we could pass this kind of data | 1177 | * If the i2c layer weren't so broken, we could pass this kind of data |
1185 | * around | 1178 | * around |
1186 | */ | 1179 | */ |
1187 | static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 1180 | static int aic3x_i2c_probe(struct i2c_client *i2c, |
1181 | const struct i2c_device_id *id) | ||
1188 | { | 1182 | { |
1189 | struct snd_soc_device *socdev = aic3x_socdev; | 1183 | struct snd_soc_device *socdev = aic3x_socdev; |
1190 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
1191 | struct snd_soc_codec *codec = socdev->codec; | 1184 | struct snd_soc_codec *codec = socdev->codec; |
1192 | struct i2c_client *i2c; | ||
1193 | int ret; | 1185 | int ret; |
1194 | 1186 | ||
1195 | if (addr != setup->i2c_address) | ||
1196 | return -ENODEV; | ||
1197 | |||
1198 | client_template.adapter = adap; | ||
1199 | client_template.addr = addr; | ||
1200 | |||
1201 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1202 | if (i2c == NULL) | ||
1203 | return -ENOMEM; | ||
1204 | |||
1205 | i2c_set_clientdata(i2c, codec); | 1187 | i2c_set_clientdata(i2c, codec); |
1206 | codec->control_data = i2c; | 1188 | codec->control_data = i2c; |
1207 | 1189 | ||
1208 | ret = i2c_attach_client(i2c); | ||
1209 | if (ret < 0) { | ||
1210 | printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n", | ||
1211 | addr); | ||
1212 | goto err; | ||
1213 | } | ||
1214 | |||
1215 | ret = aic3x_init(socdev); | 1190 | ret = aic3x_init(socdev); |
1216 | if (ret < 0) { | 1191 | if (ret < 0) |
1217 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); | 1192 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); |
1218 | goto err; | ||
1219 | } | ||
1220 | return ret; | ||
1221 | |||
1222 | err: | ||
1223 | kfree(i2c); | ||
1224 | return ret; | 1193 | return ret; |
1225 | } | 1194 | } |
1226 | 1195 | ||
1227 | static int aic3x_i2c_detach(struct i2c_client *client) | 1196 | static int aic3x_i2c_remove(struct i2c_client *client) |
1228 | { | 1197 | { |
1229 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1198 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1230 | i2c_detach_client(client); | ||
1231 | kfree(codec->reg_cache); | 1199 | kfree(codec->reg_cache); |
1232 | kfree(client); | ||
1233 | return 0; | 1200 | return 0; |
1234 | } | 1201 | } |
1235 | 1202 | ||
1236 | static int aic3x_i2c_attach(struct i2c_adapter *adap) | 1203 | static const struct i2c_device_id aic3x_i2c_id[] = { |
1237 | { | 1204 | { "tlv320aic3x", 0 }, |
1238 | return i2c_probe(adap, &addr_data, aic3x_codec_probe); | 1205 | { } |
1239 | } | 1206 | }; |
1207 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1240 | 1208 | ||
1241 | /* machine i2c codec control layer */ | 1209 | /* machine i2c codec control layer */ |
1242 | static struct i2c_driver aic3x_i2c_driver = { | 1210 | static struct i2c_driver aic3x_i2c_driver = { |
@@ -1244,13 +1212,9 @@ static struct i2c_driver aic3x_i2c_driver = { | |||
1244 | .name = "aic3x I2C Codec", | 1212 | .name = "aic3x I2C Codec", |
1245 | .owner = THIS_MODULE, | 1213 | .owner = THIS_MODULE, |
1246 | }, | 1214 | }, |
1247 | .attach_adapter = aic3x_i2c_attach, | 1215 | .probe = aic3x_i2c_probe, |
1248 | .detach_client = aic3x_i2c_detach, | 1216 | .remove = aic3x_i2c_remove, |
1249 | }; | 1217 | .id_table = aic3x_i2c_id, |
1250 | |||
1251 | static struct i2c_client client_template = { | ||
1252 | .name = "AIC3X", | ||
1253 | .driver = &aic3x_i2c_driver, | ||
1254 | }; | 1218 | }; |
1255 | 1219 | ||
1256 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | 1220 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) |
@@ -1258,6 +1222,46 @@ static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | |||
1258 | value[0] = i2c_smbus_read_byte_data(client, value[0]); | 1222 | value[0] = i2c_smbus_read_byte_data(client, value[0]); |
1259 | return (len == 1); | 1223 | return (len == 1); |
1260 | } | 1224 | } |
1225 | |||
1226 | static int aic3x_add_i2c_device(struct platform_device *pdev, | ||
1227 | const struct aic3x_setup_data *setup) | ||
1228 | { | ||
1229 | struct i2c_board_info info; | ||
1230 | struct i2c_adapter *adapter; | ||
1231 | struct i2c_client *client; | ||
1232 | int ret; | ||
1233 | |||
1234 | ret = i2c_add_driver(&aic3x_i2c_driver); | ||
1235 | if (ret != 0) { | ||
1236 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1237 | return ret; | ||
1238 | } | ||
1239 | |||
1240 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1241 | info.addr = setup->i2c_address; | ||
1242 | strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE); | ||
1243 | |||
1244 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1245 | if (!adapter) { | ||
1246 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1247 | setup->i2c_bus); | ||
1248 | goto err_driver; | ||
1249 | } | ||
1250 | |||
1251 | client = i2c_new_device(adapter, &info); | ||
1252 | i2c_put_adapter(adapter); | ||
1253 | if (!client) { | ||
1254 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1255 | (unsigned int)info.addr); | ||
1256 | goto err_driver; | ||
1257 | } | ||
1258 | |||
1259 | return 0; | ||
1260 | |||
1261 | err_driver: | ||
1262 | i2c_del_driver(&aic3x_i2c_driver); | ||
1263 | return -ENODEV; | ||
1264 | } | ||
1261 | #endif | 1265 | #endif |
1262 | 1266 | ||
1263 | static int aic3x_probe(struct platform_device *pdev) | 1267 | static int aic3x_probe(struct platform_device *pdev) |
@@ -1290,12 +1294,9 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1290 | aic3x_socdev = socdev; | 1294 | aic3x_socdev = socdev; |
1291 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1295 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1292 | if (setup->i2c_address) { | 1296 | if (setup->i2c_address) { |
1293 | normal_i2c[0] = setup->i2c_address; | ||
1294 | codec->hw_write = (hw_write_t) i2c_master_send; | 1297 | codec->hw_write = (hw_write_t) i2c_master_send; |
1295 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | 1298 | codec->hw_read = (hw_read_t) aic3x_i2c_read; |
1296 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1299 | ret = aic3x_add_i2c_device(pdev, setup); |
1297 | if (ret != 0) | ||
1298 | printk(KERN_ERR "can't add i2c driver"); | ||
1299 | } | 1300 | } |
1300 | #else | 1301 | #else |
1301 | /* Add other interfaces here */ | 1302 | /* Add other interfaces here */ |
@@ -1320,6 +1321,7 @@ static int aic3x_remove(struct platform_device *pdev) | |||
1320 | snd_soc_free_pcms(socdev); | 1321 | snd_soc_free_pcms(socdev); |
1321 | snd_soc_dapm_free(socdev); | 1322 | snd_soc_dapm_free(socdev); |
1322 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1323 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1324 | i2c_unregister_device(codec->control_data); | ||
1323 | i2c_del_driver(&aic3x_i2c_driver); | 1325 | i2c_del_driver(&aic3x_i2c_driver); |
1324 | #endif | 1326 | #endif |
1325 | kfree(codec->private_data); | 1327 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d76c079b86e..00a195aa02e 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC TLV320AIC3X codec driver | 2 | * ALSA SoC TLV320AIC3X codec driver |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -224,6 +224,7 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); | |||
224 | int aic3x_headset_detected(struct snd_soc_codec *codec); | 224 | int aic3x_headset_detected(struct snd_soc_codec *codec); |
225 | 225 | ||
226 | struct aic3x_setup_data { | 226 | struct aic3x_setup_data { |
227 | int i2c_bus; | ||
227 | unsigned short i2c_address; | 228 | unsigned short i2c_address; |
228 | unsigned int gpio_func[2]; | 229 | unsigned int gpio_func[2]; |
229 | }; | 230 | }; |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 807318fbdc8..d206d7f892b 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -701,87 +701,86 @@ static struct snd_soc_device *uda1380_socdev; | |||
701 | 701 | ||
702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
703 | 703 | ||
704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | 704 | static int uda1380_i2c_probe(struct i2c_client *i2c, |
705 | 705 | const struct i2c_device_id *id) | |
706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
707 | |||
708 | /* Magic definition of all other variables and things */ | ||
709 | I2C_CLIENT_INSMOD; | ||
710 | |||
711 | static struct i2c_driver uda1380_i2c_driver; | ||
712 | static struct i2c_client client_template; | ||
713 | |||
714 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
715 | around */ | ||
716 | |||
717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
718 | { | 706 | { |
719 | struct snd_soc_device *socdev = uda1380_socdev; | 707 | struct snd_soc_device *socdev = uda1380_socdev; |
720 | struct uda1380_setup_data *setup = socdev->codec_data; | 708 | struct uda1380_setup_data *setup = socdev->codec_data; |
721 | struct snd_soc_codec *codec = socdev->codec; | 709 | struct snd_soc_codec *codec = socdev->codec; |
722 | struct i2c_client *i2c; | ||
723 | int ret; | 710 | int ret; |
724 | 711 | ||
725 | if (addr != setup->i2c_address) | ||
726 | return -ENODEV; | ||
727 | |||
728 | client_template.adapter = adap; | ||
729 | client_template.addr = addr; | ||
730 | |||
731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
732 | if (i2c == NULL) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | i2c_set_clientdata(i2c, codec); | 712 | i2c_set_clientdata(i2c, codec); |
736 | codec->control_data = i2c; | 713 | codec->control_data = i2c; |
737 | 714 | ||
738 | ret = i2c_attach_client(i2c); | ||
739 | if (ret < 0) { | ||
740 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); | ||
741 | goto err; | ||
742 | } | ||
743 | |||
744 | ret = uda1380_init(socdev, setup->dac_clk); | 715 | ret = uda1380_init(socdev, setup->dac_clk); |
745 | if (ret < 0) { | 716 | if (ret < 0) |
746 | pr_err("uda1380: failed to initialise UDA1380\n"); | 717 | pr_err("uda1380: failed to initialise UDA1380\n"); |
747 | goto err; | ||
748 | } | ||
749 | return ret; | ||
750 | 718 | ||
751 | err: | ||
752 | kfree(i2c); | ||
753 | return ret; | 719 | return ret; |
754 | } | 720 | } |
755 | 721 | ||
756 | static int uda1380_i2c_detach(struct i2c_client *client) | 722 | static int uda1380_i2c_remove(struct i2c_client *client) |
757 | { | 723 | { |
758 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 724 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
759 | i2c_detach_client(client); | ||
760 | kfree(codec->reg_cache); | 725 | kfree(codec->reg_cache); |
761 | kfree(client); | ||
762 | return 0; | 726 | return 0; |
763 | } | 727 | } |
764 | 728 | ||
765 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | 729 | static const struct i2c_device_id uda1380_i2c_id[] = { |
766 | { | 730 | { "uda1380", 0 }, |
767 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | 731 | { } |
768 | } | 732 | }; |
733 | MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); | ||
769 | 734 | ||
770 | static struct i2c_driver uda1380_i2c_driver = { | 735 | static struct i2c_driver uda1380_i2c_driver = { |
771 | .driver = { | 736 | .driver = { |
772 | .name = "UDA1380 I2C Codec", | 737 | .name = "UDA1380 I2C Codec", |
773 | .owner = THIS_MODULE, | 738 | .owner = THIS_MODULE, |
774 | }, | 739 | }, |
775 | .id = I2C_DRIVERID_UDA1380, | 740 | .probe = uda1380_i2c_probe, |
776 | .attach_adapter = uda1380_i2c_attach, | 741 | .remove = uda1380_i2c_remove, |
777 | .detach_client = uda1380_i2c_detach, | 742 | .id_table = uda1380_i2c_id, |
778 | .command = NULL, | ||
779 | }; | 743 | }; |
780 | 744 | ||
781 | static struct i2c_client client_template = { | 745 | static int uda1380_add_i2c_device(struct platform_device *pdev, |
782 | .name = "UDA1380", | 746 | const struct uda1380_setup_data *setup) |
783 | .driver = &uda1380_i2c_driver, | 747 | { |
784 | }; | 748 | struct i2c_board_info info; |
749 | struct i2c_adapter *adapter; | ||
750 | struct i2c_client *client; | ||
751 | int ret; | ||
752 | |||
753 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
754 | if (ret != 0) { | ||
755 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
756 | return ret; | ||
757 | } | ||
758 | |||
759 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
760 | info.addr = setup->i2c_address; | ||
761 | strlcpy(info.type, "uda1380", I2C_NAME_SIZE); | ||
762 | |||
763 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
764 | if (!adapter) { | ||
765 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
766 | setup->i2c_bus); | ||
767 | goto err_driver; | ||
768 | } | ||
769 | |||
770 | client = i2c_new_device(adapter, &info); | ||
771 | i2c_put_adapter(adapter); | ||
772 | if (!client) { | ||
773 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
774 | (unsigned int)info.addr); | ||
775 | goto err_driver; | ||
776 | } | ||
777 | |||
778 | return 0; | ||
779 | |||
780 | err_driver: | ||
781 | i2c_del_driver(&uda1380_i2c_driver); | ||
782 | return -ENODEV; | ||
783 | } | ||
785 | #endif | 784 | #endif |
786 | 785 | ||
787 | static int uda1380_probe(struct platform_device *pdev) | 786 | static int uda1380_probe(struct platform_device *pdev) |
@@ -789,7 +788,7 @@ static int uda1380_probe(struct platform_device *pdev) | |||
789 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 788 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
790 | struct uda1380_setup_data *setup; | 789 | struct uda1380_setup_data *setup; |
791 | struct snd_soc_codec *codec; | 790 | struct snd_soc_codec *codec; |
792 | int ret = 0; | 791 | int ret; |
793 | 792 | ||
794 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | 793 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); |
795 | 794 | ||
@@ -804,16 +803,13 @@ static int uda1380_probe(struct platform_device *pdev) | |||
804 | INIT_LIST_HEAD(&codec->dapm_paths); | 803 | INIT_LIST_HEAD(&codec->dapm_paths); |
805 | 804 | ||
806 | uda1380_socdev = socdev; | 805 | uda1380_socdev = socdev; |
806 | ret = -ENODEV; | ||
807 | |||
807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 808 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
808 | if (setup->i2c_address) { | 809 | if (setup->i2c_address) { |
809 | normal_i2c[0] = setup->i2c_address; | ||
810 | codec->hw_write = (hw_write_t)i2c_master_send; | 810 | codec->hw_write = (hw_write_t)i2c_master_send; |
811 | ret = i2c_add_driver(&uda1380_i2c_driver); | 811 | ret = uda1380_add_i2c_device(pdev, setup); |
812 | if (ret != 0) | ||
813 | printk(KERN_ERR "can't add i2c driver"); | ||
814 | } | 812 | } |
815 | #else | ||
816 | /* Add other interfaces here */ | ||
817 | #endif | 813 | #endif |
818 | 814 | ||
819 | if (ret != 0) | 815 | if (ret != 0) |
@@ -833,6 +829,7 @@ static int uda1380_remove(struct platform_device *pdev) | |||
833 | snd_soc_free_pcms(socdev); | 829 | snd_soc_free_pcms(socdev); |
834 | snd_soc_dapm_free(socdev); | 830 | snd_soc_dapm_free(socdev); |
835 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 831 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
832 | i2c_unregister_device(codec->control_data); | ||
836 | i2c_del_driver(&uda1380_i2c_driver); | 833 | i2c_del_driver(&uda1380_i2c_driver); |
837 | #endif | 834 | #endif |
838 | kfree(codec); | 835 | kfree(codec); |
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index 50c603e2c9f..c55c17a52a1 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h | |||
@@ -73,6 +73,7 @@ | |||
73 | #define R23_AGC_EN 0x0001 | 73 | #define R23_AGC_EN 0x0001 |
74 | 74 | ||
75 | struct uda1380_setup_data { | 75 | struct uda1380_setup_data { |
76 | int i2c_bus; | ||
76 | unsigned short i2c_address; | 77 | unsigned short i2c_address; |
77 | int dac_clk; | 78 | int dac_clk; |
78 | #define UDA1380_DAC_CLK_SYSCLK 0 | 79 | #define UDA1380_DAC_CLK_SYSCLK 0 |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 3d998e6a997..9a37c8d95ed 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -199,7 +199,7 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), | |||
199 | }; | 199 | }; |
200 | 200 | ||
201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | 201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { |
202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | 202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 1), |
203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | 203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), |
204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | 204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), |
205 | }; | 205 | }; |
@@ -665,88 +665,86 @@ static struct snd_soc_device *wm8510_socdev; | |||
665 | /* | 665 | /* |
666 | * WM8510 2 wire address is 0x1a | 666 | * WM8510 2 wire address is 0x1a |
667 | */ | 667 | */ |
668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | ||
669 | 668 | ||
670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 669 | static int wm8510_i2c_probe(struct i2c_client *i2c, |
671 | 670 | const struct i2c_device_id *id) | |
672 | /* Magic definition of all other variables and things */ | ||
673 | I2C_CLIENT_INSMOD; | ||
674 | |||
675 | static struct i2c_driver wm8510_i2c_driver; | ||
676 | static struct i2c_client client_template; | ||
677 | |||
678 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
679 | around */ | ||
680 | |||
681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
682 | { | 671 | { |
683 | struct snd_soc_device *socdev = wm8510_socdev; | 672 | struct snd_soc_device *socdev = wm8510_socdev; |
684 | struct wm8510_setup_data *setup = socdev->codec_data; | ||
685 | struct snd_soc_codec *codec = socdev->codec; | 673 | struct snd_soc_codec *codec = socdev->codec; |
686 | struct i2c_client *i2c; | ||
687 | int ret; | 674 | int ret; |
688 | 675 | ||
689 | if (addr != setup->i2c_address) | ||
690 | return -ENODEV; | ||
691 | |||
692 | client_template.adapter = adap; | ||
693 | client_template.addr = addr; | ||
694 | |||
695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
696 | if (i2c == NULL) | ||
697 | return -ENOMEM; | ||
698 | |||
699 | i2c_set_clientdata(i2c, codec); | 676 | i2c_set_clientdata(i2c, codec); |
700 | codec->control_data = i2c; | 677 | codec->control_data = i2c; |
701 | 678 | ||
702 | ret = i2c_attach_client(i2c); | ||
703 | if (ret < 0) { | ||
704 | pr_err("failed to attach codec at addr %x\n", addr); | ||
705 | goto err; | ||
706 | } | ||
707 | |||
708 | ret = wm8510_init(socdev); | 679 | ret = wm8510_init(socdev); |
709 | if (ret < 0) { | 680 | if (ret < 0) |
710 | pr_err("failed to initialise WM8510\n"); | 681 | pr_err("failed to initialise WM8510\n"); |
711 | goto err; | ||
712 | } | ||
713 | return ret; | ||
714 | 682 | ||
715 | err: | ||
716 | kfree(i2c); | ||
717 | return ret; | 683 | return ret; |
718 | } | 684 | } |
719 | 685 | ||
720 | static int wm8510_i2c_detach(struct i2c_client *client) | 686 | static int wm8510_i2c_remove(struct i2c_client *client) |
721 | { | 687 | { |
722 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 688 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
723 | i2c_detach_client(client); | ||
724 | kfree(codec->reg_cache); | 689 | kfree(codec->reg_cache); |
725 | kfree(client); | ||
726 | return 0; | 690 | return 0; |
727 | } | 691 | } |
728 | 692 | ||
729 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | 693 | static const struct i2c_device_id wm8510_i2c_id[] = { |
730 | { | 694 | { "wm8510", 0 }, |
731 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | 695 | { } |
732 | } | 696 | }; |
697 | MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); | ||
733 | 698 | ||
734 | /* corgi i2c codec control layer */ | ||
735 | static struct i2c_driver wm8510_i2c_driver = { | 699 | static struct i2c_driver wm8510_i2c_driver = { |
736 | .driver = { | 700 | .driver = { |
737 | .name = "WM8510 I2C Codec", | 701 | .name = "WM8510 I2C Codec", |
738 | .owner = THIS_MODULE, | 702 | .owner = THIS_MODULE, |
739 | }, | 703 | }, |
740 | .id = I2C_DRIVERID_WM8510, | 704 | .probe = wm8510_i2c_probe, |
741 | .attach_adapter = wm8510_i2c_attach, | 705 | .remove = wm8510_i2c_remove, |
742 | .detach_client = wm8510_i2c_detach, | 706 | .id_table = wm8510_i2c_id, |
743 | .command = NULL, | ||
744 | }; | 707 | }; |
745 | 708 | ||
746 | static struct i2c_client client_template = { | 709 | static int wm8510_add_i2c_device(struct platform_device *pdev, |
747 | .name = "WM8510", | 710 | const struct wm8510_setup_data *setup) |
748 | .driver = &wm8510_i2c_driver, | 711 | { |
749 | }; | 712 | struct i2c_board_info info; |
713 | struct i2c_adapter *adapter; | ||
714 | struct i2c_client *client; | ||
715 | int ret; | ||
716 | |||
717 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
718 | if (ret != 0) { | ||
719 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
724 | info.addr = setup->i2c_address; | ||
725 | strlcpy(info.type, "wm8510", I2C_NAME_SIZE); | ||
726 | |||
727 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
728 | if (!adapter) { | ||
729 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
730 | setup->i2c_bus); | ||
731 | goto err_driver; | ||
732 | } | ||
733 | |||
734 | client = i2c_new_device(adapter, &info); | ||
735 | i2c_put_adapter(adapter); | ||
736 | if (!client) { | ||
737 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
738 | (unsigned int)info.addr); | ||
739 | goto err_driver; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | |||
744 | err_driver: | ||
745 | i2c_del_driver(&wm8510_i2c_driver); | ||
746 | return -ENODEV; | ||
747 | } | ||
750 | #endif | 748 | #endif |
751 | 749 | ||
752 | static int wm8510_probe(struct platform_device *pdev) | 750 | static int wm8510_probe(struct platform_device *pdev) |
@@ -771,11 +769,8 @@ static int wm8510_probe(struct platform_device *pdev) | |||
771 | wm8510_socdev = socdev; | 769 | wm8510_socdev = socdev; |
772 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 770 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
773 | if (setup->i2c_address) { | 771 | if (setup->i2c_address) { |
774 | normal_i2c[0] = setup->i2c_address; | ||
775 | codec->hw_write = (hw_write_t)i2c_master_send; | 772 | codec->hw_write = (hw_write_t)i2c_master_send; |
776 | ret = i2c_add_driver(&wm8510_i2c_driver); | 773 | ret = wm8510_add_i2c_device(pdev, setup); |
777 | if (ret != 0) | ||
778 | printk(KERN_ERR "can't add i2c driver"); | ||
779 | } | 774 | } |
780 | #else | 775 | #else |
781 | /* Add other interfaces here */ | 776 | /* Add other interfaces here */ |
@@ -798,6 +793,7 @@ static int wm8510_remove(struct platform_device *pdev) | |||
798 | snd_soc_free_pcms(socdev); | 793 | snd_soc_free_pcms(socdev); |
799 | snd_soc_dapm_free(socdev); | 794 | snd_soc_dapm_free(socdev); |
800 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 795 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
796 | i2c_unregister_device(codec->control_data); | ||
801 | i2c_del_driver(&wm8510_i2c_driver); | 797 | i2c_del_driver(&wm8510_i2c_driver); |
802 | #endif | 798 | #endif |
803 | kfree(codec); | 799 | kfree(codec); |
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h index f5d2e42eb3f..c5368396045 100644 --- a/sound/soc/codecs/wm8510.h +++ b/sound/soc/codecs/wm8510.h | |||
@@ -94,6 +94,7 @@ | |||
94 | #define WM8510_MCLKDIV_12 (7 << 5) | 94 | #define WM8510_MCLKDIV_12 (7 << 5) |
95 | 95 | ||
96 | struct wm8510_setup_data { | 96 | struct wm8510_setup_data { |
97 | int i2c_bus; | ||
97 | unsigned short i2c_address; | 98 | unsigned short i2c_address; |
98 | }; | 99 | }; |
99 | 100 | ||
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c new file mode 100644 index 00000000000..df1ffbe305b --- /dev/null +++ b/sound/soc/codecs/wm8580.c | |||
@@ -0,0 +1,1055 @@ | |||
1 | /* | ||
2 | * wm8580.c -- WM8580 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * Notes: | ||
12 | * The WM8580 is a multichannel codec with S/PDIF support, featuring six | ||
13 | * DAC channels and two ADC channels. | ||
14 | * | ||
15 | * Currently only the primary audio interface is supported - S/PDIF and | ||
16 | * the secondary audio interfaces are not. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | #include <sound/tlv.h> | ||
34 | #include <sound/initval.h> | ||
35 | #include <asm/div64.h> | ||
36 | |||
37 | #include "wm8580.h" | ||
38 | |||
39 | #define AUDIO_NAME "wm8580" | ||
40 | #define WM8580_VERSION "0.1" | ||
41 | |||
42 | struct pll_state { | ||
43 | unsigned int in; | ||
44 | unsigned int out; | ||
45 | }; | ||
46 | |||
47 | /* codec private data */ | ||
48 | struct wm8580_priv { | ||
49 | struct pll_state a; | ||
50 | struct pll_state b; | ||
51 | }; | ||
52 | |||
53 | /* WM8580 register space */ | ||
54 | #define WM8580_PLLA1 0x00 | ||
55 | #define WM8580_PLLA2 0x01 | ||
56 | #define WM8580_PLLA3 0x02 | ||
57 | #define WM8580_PLLA4 0x03 | ||
58 | #define WM8580_PLLB1 0x04 | ||
59 | #define WM8580_PLLB2 0x05 | ||
60 | #define WM8580_PLLB3 0x06 | ||
61 | #define WM8580_PLLB4 0x07 | ||
62 | #define WM8580_CLKSEL 0x08 | ||
63 | #define WM8580_PAIF1 0x09 | ||
64 | #define WM8580_PAIF2 0x0A | ||
65 | #define WM8580_SAIF1 0x0B | ||
66 | #define WM8580_PAIF3 0x0C | ||
67 | #define WM8580_PAIF4 0x0D | ||
68 | #define WM8580_SAIF2 0x0E | ||
69 | #define WM8580_DAC_CONTROL1 0x0F | ||
70 | #define WM8580_DAC_CONTROL2 0x10 | ||
71 | #define WM8580_DAC_CONTROL3 0x11 | ||
72 | #define WM8580_DAC_CONTROL4 0x12 | ||
73 | #define WM8580_DAC_CONTROL5 0x13 | ||
74 | #define WM8580_DIGITAL_ATTENUATION_DACL1 0x14 | ||
75 | #define WM8580_DIGITAL_ATTENUATION_DACR1 0x15 | ||
76 | #define WM8580_DIGITAL_ATTENUATION_DACL2 0x16 | ||
77 | #define WM8580_DIGITAL_ATTENUATION_DACR2 0x17 | ||
78 | #define WM8580_DIGITAL_ATTENUATION_DACL3 0x18 | ||
79 | #define WM8580_DIGITAL_ATTENUATION_DACR3 0x19 | ||
80 | #define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C | ||
81 | #define WM8580_ADC_CONTROL1 0x1D | ||
82 | #define WM8580_SPDTXCHAN0 0x1E | ||
83 | #define WM8580_SPDTXCHAN1 0x1F | ||
84 | #define WM8580_SPDTXCHAN2 0x20 | ||
85 | #define WM8580_SPDTXCHAN3 0x21 | ||
86 | #define WM8580_SPDTXCHAN4 0x22 | ||
87 | #define WM8580_SPDTXCHAN5 0x23 | ||
88 | #define WM8580_SPDMODE 0x24 | ||
89 | #define WM8580_INTMASK 0x25 | ||
90 | #define WM8580_GPO1 0x26 | ||
91 | #define WM8580_GPO2 0x27 | ||
92 | #define WM8580_GPO3 0x28 | ||
93 | #define WM8580_GPO4 0x29 | ||
94 | #define WM8580_GPO5 0x2A | ||
95 | #define WM8580_INTSTAT 0x2B | ||
96 | #define WM8580_SPDRXCHAN1 0x2C | ||
97 | #define WM8580_SPDRXCHAN2 0x2D | ||
98 | #define WM8580_SPDRXCHAN3 0x2E | ||
99 | #define WM8580_SPDRXCHAN4 0x2F | ||
100 | #define WM8580_SPDRXCHAN5 0x30 | ||
101 | #define WM8580_SPDSTAT 0x31 | ||
102 | #define WM8580_PWRDN1 0x32 | ||
103 | #define WM8580_PWRDN2 0x33 | ||
104 | #define WM8580_READBACK 0x34 | ||
105 | #define WM8580_RESET 0x35 | ||
106 | |||
107 | /* PLLB4 (register 7h) */ | ||
108 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | ||
109 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | ||
110 | #define WM8580_PLLB4_MCLKOUTSRC_PLLB 0x40 | ||
111 | #define WM8580_PLLB4_MCLKOUTSRC_OSC 0x60 | ||
112 | |||
113 | #define WM8580_PLLB4_CLKOUTSRC_MASK 0x180 | ||
114 | #define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080 | ||
115 | #define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100 | ||
116 | #define WM8580_PLLB4_CLKOUTSRC_OSCCLK 0x180 | ||
117 | |||
118 | /* CLKSEL (register 8h) */ | ||
119 | #define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03 | ||
120 | #define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01 | ||
121 | #define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02 | ||
122 | |||
123 | /* AIF control 1 (registers 9h-bh) */ | ||
124 | #define WM8580_AIF_RATE_MASK 0x7 | ||
125 | #define WM8580_AIF_RATE_128 0x0 | ||
126 | #define WM8580_AIF_RATE_192 0x1 | ||
127 | #define WM8580_AIF_RATE_256 0x2 | ||
128 | #define WM8580_AIF_RATE_384 0x3 | ||
129 | #define WM8580_AIF_RATE_512 0x4 | ||
130 | #define WM8580_AIF_RATE_768 0x5 | ||
131 | #define WM8580_AIF_RATE_1152 0x6 | ||
132 | |||
133 | #define WM8580_AIF_BCLKSEL_MASK 0x18 | ||
134 | #define WM8580_AIF_BCLKSEL_64 0x00 | ||
135 | #define WM8580_AIF_BCLKSEL_128 0x08 | ||
136 | #define WM8580_AIF_BCLKSEL_256 0x10 | ||
137 | #define WM8580_AIF_BCLKSEL_SYSCLK 0x18 | ||
138 | |||
139 | #define WM8580_AIF_MS 0x20 | ||
140 | |||
141 | #define WM8580_AIF_CLKSRC_MASK 0xc0 | ||
142 | #define WM8580_AIF_CLKSRC_PLLA 0x40 | ||
143 | #define WM8580_AIF_CLKSRC_PLLB 0x40 | ||
144 | #define WM8580_AIF_CLKSRC_MCLK 0xc0 | ||
145 | |||
146 | /* AIF control 2 (registers ch-eh) */ | ||
147 | #define WM8580_AIF_FMT_MASK 0x03 | ||
148 | #define WM8580_AIF_FMT_RIGHTJ 0x00 | ||
149 | #define WM8580_AIF_FMT_LEFTJ 0x01 | ||
150 | #define WM8580_AIF_FMT_I2S 0x02 | ||
151 | #define WM8580_AIF_FMT_DSP 0x03 | ||
152 | |||
153 | #define WM8580_AIF_LENGTH_MASK 0x0c | ||
154 | #define WM8580_AIF_LENGTH_16 0x00 | ||
155 | #define WM8580_AIF_LENGTH_20 0x04 | ||
156 | #define WM8580_AIF_LENGTH_24 0x08 | ||
157 | #define WM8580_AIF_LENGTH_32 0x0c | ||
158 | |||
159 | #define WM8580_AIF_LRP 0x10 | ||
160 | #define WM8580_AIF_BCP 0x20 | ||
161 | |||
162 | /* Powerdown Register 1 (register 32h) */ | ||
163 | #define WM8580_PWRDN1_PWDN 0x001 | ||
164 | #define WM8580_PWRDN1_ALLDACPD 0x040 | ||
165 | |||
166 | /* Powerdown Register 2 (register 33h) */ | ||
167 | #define WM8580_PWRDN2_OSSCPD 0x001 | ||
168 | #define WM8580_PWRDN2_PLLAPD 0x002 | ||
169 | #define WM8580_PWRDN2_PLLBPD 0x004 | ||
170 | #define WM8580_PWRDN2_SPDIFPD 0x008 | ||
171 | #define WM8580_PWRDN2_SPDIFTXD 0x010 | ||
172 | #define WM8580_PWRDN2_SPDIFRXD 0x020 | ||
173 | |||
174 | #define WM8580_DAC_CONTROL5_MUTEALL 0x10 | ||
175 | |||
176 | /* | ||
177 | * wm8580 register cache | ||
178 | * We can't read the WM8580 register space when we | ||
179 | * are using 2 wire for device control, so we cache them instead. | ||
180 | */ | ||
181 | static const u16 wm8580_reg[] = { | ||
182 | 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ | ||
183 | 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ | ||
184 | 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/ | ||
185 | 0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ | ||
186 | 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ | ||
187 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ | ||
188 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/ | ||
189 | 0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/ | ||
190 | 0x0000, 0x0000, 0x0031, 0x000b, /*R35*/ | ||
191 | 0x0039, 0x0000, 0x0010, 0x0032, /*R39*/ | ||
192 | 0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/ | ||
193 | 0x0000, 0x0000, 0x0000, 0x0000, /*R47*/ | ||
194 | 0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/ | ||
195 | 0x0000, 0x0000 /*R53*/ | ||
196 | }; | ||
197 | |||
198 | /* | ||
199 | * read wm8580 register cache | ||
200 | */ | ||
201 | static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, | ||
202 | unsigned int reg) | ||
203 | { | ||
204 | u16 *cache = codec->reg_cache; | ||
205 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | ||
206 | return cache[reg]; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * write wm8580 register cache | ||
211 | */ | ||
212 | static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec, | ||
213 | unsigned int reg, unsigned int value) | ||
214 | { | ||
215 | u16 *cache = codec->reg_cache; | ||
216 | |||
217 | cache[reg] = value; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * write to the WM8580 register space | ||
222 | */ | ||
223 | static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, | ||
224 | unsigned int value) | ||
225 | { | ||
226 | u8 data[2]; | ||
227 | |||
228 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | ||
229 | |||
230 | /* Registers are 9 bits wide */ | ||
231 | value &= 0x1ff; | ||
232 | |||
233 | switch (reg) { | ||
234 | case WM8580_RESET: | ||
235 | /* Uncached */ | ||
236 | break; | ||
237 | default: | ||
238 | if (value == wm8580_read_reg_cache(codec, reg)) | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | /* data is | ||
243 | * D15..D9 WM8580 register offset | ||
244 | * D8...D0 register data | ||
245 | */ | ||
246 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
247 | data[1] = value & 0x00ff; | ||
248 | |||
249 | wm8580_write_reg_cache(codec, reg, value); | ||
250 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
251 | return 0; | ||
252 | else | ||
253 | return -EIO; | ||
254 | } | ||
255 | |||
256 | static inline unsigned int wm8580_read(struct snd_soc_codec *codec, | ||
257 | unsigned int reg) | ||
258 | { | ||
259 | switch (reg) { | ||
260 | default: | ||
261 | return wm8580_read_reg_cache(codec, reg); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | ||
266 | |||
267 | static int wm8580_out_vu(struct snd_kcontrol *kcontrol, | ||
268 | struct snd_ctl_elem_value *ucontrol) | ||
269 | { | ||
270 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
271 | int reg = kcontrol->private_value & 0xff; | ||
272 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
273 | int ret; | ||
274 | u16 val; | ||
275 | |||
276 | /* Clear the register cache so we write without VU set */ | ||
277 | wm8580_write_reg_cache(codec, reg, 0); | ||
278 | wm8580_write_reg_cache(codec, reg2, 0); | ||
279 | |||
280 | ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); | ||
281 | if (ret < 0) | ||
282 | return ret; | ||
283 | |||
284 | /* Now write again with the volume update bit set */ | ||
285 | val = wm8580_read_reg_cache(codec, reg); | ||
286 | wm8580_write(codec, reg, val | 0x0100); | ||
287 | |||
288 | val = wm8580_read_reg_cache(codec, reg2); | ||
289 | wm8580_write(codec, reg2, val | 0x0100); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | #define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \ | ||
295 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
296 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
297 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
298 | .tlv.p = (tlv_array), \ | ||
299 | .info = snd_soc_info_volsw_2r, \ | ||
300 | .get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \ | ||
301 | .private_value = (reg_left) | ((shift) << 8) | \ | ||
302 | ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) } | ||
303 | |||
304 | static const struct snd_kcontrol_new wm8580_snd_controls[] = { | ||
305 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume", | ||
306 | WM8580_DIGITAL_ATTENUATION_DACL1, | ||
307 | WM8580_DIGITAL_ATTENUATION_DACR1, | ||
308 | 0, 0xff, 0, dac_tlv), | ||
309 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume", | ||
310 | WM8580_DIGITAL_ATTENUATION_DACL2, | ||
311 | WM8580_DIGITAL_ATTENUATION_DACR2, | ||
312 | 0, 0xff, 0, dac_tlv), | ||
313 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume", | ||
314 | WM8580_DIGITAL_ATTENUATION_DACL3, | ||
315 | WM8580_DIGITAL_ATTENUATION_DACR3, | ||
316 | 0, 0xff, 0, dac_tlv), | ||
317 | |||
318 | SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0), | ||
319 | SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0), | ||
320 | SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0), | ||
321 | |||
322 | SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4, 0, 1, 1, 0), | ||
323 | SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4, 2, 3, 1, 0), | ||
324 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), | ||
325 | |||
326 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), | ||
327 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0), | ||
328 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0), | ||
329 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0), | ||
330 | |||
331 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | ||
332 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | ||
333 | }; | ||
334 | |||
335 | /* Add non-DAPM controls */ | ||
336 | static int wm8580_add_controls(struct snd_soc_codec *codec) | ||
337 | { | ||
338 | int err, i; | ||
339 | |||
340 | for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) { | ||
341 | err = snd_ctl_add(codec->card, | ||
342 | snd_soc_cnew(&wm8580_snd_controls[i], | ||
343 | codec, NULL)); | ||
344 | if (err < 0) | ||
345 | return err; | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | ||
350 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), | ||
351 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), | ||
352 | SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1), | ||
353 | |||
354 | SND_SOC_DAPM_OUTPUT("VOUT1L"), | ||
355 | SND_SOC_DAPM_OUTPUT("VOUT1R"), | ||
356 | SND_SOC_DAPM_OUTPUT("VOUT2L"), | ||
357 | SND_SOC_DAPM_OUTPUT("VOUT2R"), | ||
358 | SND_SOC_DAPM_OUTPUT("VOUT3L"), | ||
359 | SND_SOC_DAPM_OUTPUT("VOUT3R"), | ||
360 | |||
361 | SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1), | ||
362 | |||
363 | SND_SOC_DAPM_INPUT("AINL"), | ||
364 | SND_SOC_DAPM_INPUT("AINR"), | ||
365 | }; | ||
366 | |||
367 | static const struct snd_soc_dapm_route audio_map[] = { | ||
368 | { "VOUT1L", NULL, "DAC1" }, | ||
369 | { "VOUT1R", NULL, "DAC1" }, | ||
370 | |||
371 | { "VOUT2L", NULL, "DAC2" }, | ||
372 | { "VOUT2R", NULL, "DAC2" }, | ||
373 | |||
374 | { "VOUT3L", NULL, "DAC3" }, | ||
375 | { "VOUT3R", NULL, "DAC3" }, | ||
376 | |||
377 | { "ADC", NULL, "AINL" }, | ||
378 | { "ADC", NULL, "AINR" }, | ||
379 | }; | ||
380 | |||
381 | static int wm8580_add_widgets(struct snd_soc_codec *codec) | ||
382 | { | ||
383 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets, | ||
384 | ARRAY_SIZE(wm8580_dapm_widgets)); | ||
385 | |||
386 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
387 | |||
388 | snd_soc_dapm_new_widgets(codec); | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /* PLL divisors */ | ||
393 | struct _pll_div { | ||
394 | u32 prescale:1; | ||
395 | u32 postscale:1; | ||
396 | u32 freqmode:2; | ||
397 | u32 n:4; | ||
398 | u32 k:24; | ||
399 | }; | ||
400 | |||
401 | /* The size in bits of the pll divide */ | ||
402 | #define FIXED_PLL_SIZE (1 << 22) | ||
403 | |||
404 | /* PLL rate to output rate divisions */ | ||
405 | static struct { | ||
406 | unsigned int div; | ||
407 | unsigned int freqmode; | ||
408 | unsigned int postscale; | ||
409 | } post_table[] = { | ||
410 | { 2, 0, 0 }, | ||
411 | { 4, 0, 1 }, | ||
412 | { 4, 1, 0 }, | ||
413 | { 8, 1, 1 }, | ||
414 | { 8, 2, 0 }, | ||
415 | { 16, 2, 1 }, | ||
416 | { 12, 3, 0 }, | ||
417 | { 24, 3, 1 } | ||
418 | }; | ||
419 | |||
420 | static int pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
421 | unsigned int source) | ||
422 | { | ||
423 | u64 Kpart; | ||
424 | unsigned int K, Ndiv, Nmod; | ||
425 | int i; | ||
426 | |||
427 | pr_debug("wm8580: PLL %dHz->%dHz\n", source, target); | ||
428 | |||
429 | /* Scale the output frequency up; the PLL should run in the | ||
430 | * region of 90-100MHz. | ||
431 | */ | ||
432 | for (i = 0; i < ARRAY_SIZE(post_table); i++) { | ||
433 | if (target * post_table[i].div >= 90000000 && | ||
434 | target * post_table[i].div <= 100000000) { | ||
435 | pll_div->freqmode = post_table[i].freqmode; | ||
436 | pll_div->postscale = post_table[i].postscale; | ||
437 | target *= post_table[i].div; | ||
438 | break; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | if (i == ARRAY_SIZE(post_table)) { | ||
443 | printk(KERN_ERR "wm8580: Unable to scale output frequency " | ||
444 | "%u\n", target); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | Ndiv = target / source; | ||
449 | |||
450 | if (Ndiv < 5) { | ||
451 | source /= 2; | ||
452 | pll_div->prescale = 1; | ||
453 | Ndiv = target / source; | ||
454 | } else | ||
455 | pll_div->prescale = 0; | ||
456 | |||
457 | if ((Ndiv < 5) || (Ndiv > 13)) { | ||
458 | printk(KERN_ERR | ||
459 | "WM8580 N=%d outside supported range\n", Ndiv); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | pll_div->n = Ndiv; | ||
464 | Nmod = target % source; | ||
465 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
466 | |||
467 | do_div(Kpart, source); | ||
468 | |||
469 | K = Kpart & 0xFFFFFFFF; | ||
470 | |||
471 | pll_div->k = K; | ||
472 | |||
473 | pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n", | ||
474 | pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode, | ||
475 | pll_div->postscale); | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
481 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
482 | { | ||
483 | int offset; | ||
484 | struct snd_soc_codec *codec = codec_dai->codec; | ||
485 | struct wm8580_priv *wm8580 = codec->private_data; | ||
486 | struct pll_state *state; | ||
487 | struct _pll_div pll_div; | ||
488 | unsigned int reg; | ||
489 | unsigned int pwr_mask; | ||
490 | int ret; | ||
491 | |||
492 | /* GCC isn't able to work out the ifs below for initialising/using | ||
493 | * pll_div so suppress warnings. | ||
494 | */ | ||
495 | memset(&pll_div, 0, sizeof(pll_div)); | ||
496 | |||
497 | switch (pll_id) { | ||
498 | case WM8580_PLLA: | ||
499 | state = &wm8580->a; | ||
500 | offset = 0; | ||
501 | pwr_mask = WM8580_PWRDN2_PLLAPD; | ||
502 | break; | ||
503 | case WM8580_PLLB: | ||
504 | state = &wm8580->b; | ||
505 | offset = 4; | ||
506 | pwr_mask = WM8580_PWRDN2_PLLBPD; | ||
507 | break; | ||
508 | default: | ||
509 | return -ENODEV; | ||
510 | } | ||
511 | |||
512 | if (freq_in && freq_out) { | ||
513 | ret = pll_factors(&pll_div, freq_out, freq_in); | ||
514 | if (ret != 0) | ||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | state->in = freq_in; | ||
519 | state->out = freq_out; | ||
520 | |||
521 | /* Always disable the PLL - it is not safe to leave it running | ||
522 | * while reprogramming it. | ||
523 | */ | ||
524 | reg = wm8580_read(codec, WM8580_PWRDN2); | ||
525 | wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask); | ||
526 | |||
527 | if (!freq_in || !freq_out) | ||
528 | return 0; | ||
529 | |||
530 | wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); | ||
531 | wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); | ||
532 | wm8580_write(codec, WM8580_PLLA3 + offset, | ||
533 | (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); | ||
534 | |||
535 | reg = wm8580_read(codec, WM8580_PLLA4 + offset); | ||
536 | reg &= ~0x3f; | ||
537 | reg |= pll_div.prescale | pll_div.postscale << 1 | | ||
538 | pll_div.freqmode << 4; | ||
539 | |||
540 | wm8580_write(codec, WM8580_PLLA4 + offset, reg); | ||
541 | |||
542 | /* All done, turn it on */ | ||
543 | reg = wm8580_read(codec, WM8580_PWRDN2); | ||
544 | wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | /* | ||
550 | * Set PCM DAI bit size and sample rate. | ||
551 | */ | ||
552 | static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, | ||
553 | struct snd_pcm_hw_params *params) | ||
554 | { | ||
555 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
556 | struct snd_soc_dai_link *dai = rtd->dai; | ||
557 | struct snd_soc_device *socdev = rtd->socdev; | ||
558 | struct snd_soc_codec *codec = socdev->codec; | ||
559 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); | ||
560 | |||
561 | paifb &= ~WM8580_AIF_LENGTH_MASK; | ||
562 | /* bit size */ | ||
563 | switch (params_format(params)) { | ||
564 | case SNDRV_PCM_FORMAT_S16_LE: | ||
565 | break; | ||
566 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
567 | paifb |= WM8580_AIF_LENGTH_20; | ||
568 | break; | ||
569 | case SNDRV_PCM_FORMAT_S24_LE: | ||
570 | paifb |= WM8580_AIF_LENGTH_24; | ||
571 | break; | ||
572 | case SNDRV_PCM_FORMAT_S32_LE: | ||
573 | paifb |= WM8580_AIF_LENGTH_24; | ||
574 | break; | ||
575 | default: | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
579 | wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, | ||
584 | unsigned int fmt) | ||
585 | { | ||
586 | struct snd_soc_codec *codec = codec_dai->codec; | ||
587 | unsigned int aifa; | ||
588 | unsigned int aifb; | ||
589 | int can_invert_lrclk; | ||
590 | |||
591 | aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id); | ||
592 | aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id); | ||
593 | |||
594 | aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); | ||
595 | |||
596 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
597 | case SND_SOC_DAIFMT_CBS_CFS: | ||
598 | aifa &= ~WM8580_AIF_MS; | ||
599 | break; | ||
600 | case SND_SOC_DAIFMT_CBM_CFM: | ||
601 | aifa |= WM8580_AIF_MS; | ||
602 | break; | ||
603 | default: | ||
604 | return -EINVAL; | ||
605 | } | ||
606 | |||
607 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
608 | case SND_SOC_DAIFMT_I2S: | ||
609 | can_invert_lrclk = 1; | ||
610 | aifb |= WM8580_AIF_FMT_I2S; | ||
611 | break; | ||
612 | case SND_SOC_DAIFMT_RIGHT_J: | ||
613 | can_invert_lrclk = 1; | ||
614 | aifb |= WM8580_AIF_FMT_RIGHTJ; | ||
615 | break; | ||
616 | case SND_SOC_DAIFMT_LEFT_J: | ||
617 | can_invert_lrclk = 1; | ||
618 | aifb |= WM8580_AIF_FMT_LEFTJ; | ||
619 | break; | ||
620 | case SND_SOC_DAIFMT_DSP_A: | ||
621 | can_invert_lrclk = 0; | ||
622 | aifb |= WM8580_AIF_FMT_DSP; | ||
623 | break; | ||
624 | case SND_SOC_DAIFMT_DSP_B: | ||
625 | can_invert_lrclk = 0; | ||
626 | aifb |= WM8580_AIF_FMT_DSP; | ||
627 | aifb |= WM8580_AIF_LRP; | ||
628 | break; | ||
629 | default: | ||
630 | return -EINVAL; | ||
631 | } | ||
632 | |||
633 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
634 | case SND_SOC_DAIFMT_NB_NF: | ||
635 | break; | ||
636 | |||
637 | case SND_SOC_DAIFMT_IB_IF: | ||
638 | if (!can_invert_lrclk) | ||
639 | return -EINVAL; | ||
640 | aifb |= WM8580_AIF_BCP; | ||
641 | aifb |= WM8580_AIF_LRP; | ||
642 | break; | ||
643 | |||
644 | case SND_SOC_DAIFMT_IB_NF: | ||
645 | aifb |= WM8580_AIF_BCP; | ||
646 | break; | ||
647 | |||
648 | case SND_SOC_DAIFMT_NB_IF: | ||
649 | if (!can_invert_lrclk) | ||
650 | return -EINVAL; | ||
651 | aifb |= WM8580_AIF_LRP; | ||
652 | break; | ||
653 | |||
654 | default: | ||
655 | return -EINVAL; | ||
656 | } | ||
657 | |||
658 | wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); | ||
659 | wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
665 | int div_id, int div) | ||
666 | { | ||
667 | struct snd_soc_codec *codec = codec_dai->codec; | ||
668 | unsigned int reg; | ||
669 | |||
670 | switch (div_id) { | ||
671 | case WM8580_MCLK: | ||
672 | reg = wm8580_read(codec, WM8580_PLLB4); | ||
673 | reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; | ||
674 | |||
675 | switch (div) { | ||
676 | case WM8580_CLKSRC_MCLK: | ||
677 | /* Input */ | ||
678 | break; | ||
679 | |||
680 | case WM8580_CLKSRC_PLLA: | ||
681 | reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA; | ||
682 | break; | ||
683 | case WM8580_CLKSRC_PLLB: | ||
684 | reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB; | ||
685 | break; | ||
686 | |||
687 | case WM8580_CLKSRC_OSC: | ||
688 | reg |= WM8580_PLLB4_MCLKOUTSRC_OSC; | ||
689 | break; | ||
690 | |||
691 | default: | ||
692 | return -EINVAL; | ||
693 | } | ||
694 | wm8580_write(codec, WM8580_PLLB4, reg); | ||
695 | break; | ||
696 | |||
697 | case WM8580_DAC_CLKSEL: | ||
698 | reg = wm8580_read(codec, WM8580_CLKSEL); | ||
699 | reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; | ||
700 | |||
701 | switch (div) { | ||
702 | case WM8580_CLKSRC_MCLK: | ||
703 | break; | ||
704 | |||
705 | case WM8580_CLKSRC_PLLA: | ||
706 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA; | ||
707 | break; | ||
708 | |||
709 | case WM8580_CLKSRC_PLLB: | ||
710 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB; | ||
711 | break; | ||
712 | |||
713 | default: | ||
714 | return -EINVAL; | ||
715 | } | ||
716 | wm8580_write(codec, WM8580_CLKSEL, reg); | ||
717 | break; | ||
718 | |||
719 | case WM8580_CLKOUTSRC: | ||
720 | reg = wm8580_read(codec, WM8580_PLLB4); | ||
721 | reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; | ||
722 | |||
723 | switch (div) { | ||
724 | case WM8580_CLKSRC_NONE: | ||
725 | break; | ||
726 | |||
727 | case WM8580_CLKSRC_PLLA: | ||
728 | reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK; | ||
729 | break; | ||
730 | |||
731 | case WM8580_CLKSRC_PLLB: | ||
732 | reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK; | ||
733 | break; | ||
734 | |||
735 | case WM8580_CLKSRC_OSC: | ||
736 | reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK; | ||
737 | break; | ||
738 | |||
739 | default: | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | wm8580_write(codec, WM8580_PLLB4, reg); | ||
743 | break; | ||
744 | |||
745 | default: | ||
746 | return -EINVAL; | ||
747 | } | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
753 | { | ||
754 | struct snd_soc_codec *codec = codec_dai->codec; | ||
755 | unsigned int reg; | ||
756 | |||
757 | reg = wm8580_read(codec, WM8580_DAC_CONTROL5); | ||
758 | |||
759 | if (mute) | ||
760 | reg |= WM8580_DAC_CONTROL5_MUTEALL; | ||
761 | else | ||
762 | reg &= ~WM8580_DAC_CONTROL5_MUTEALL; | ||
763 | |||
764 | wm8580_write(codec, WM8580_DAC_CONTROL5, reg); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int wm8580_set_bias_level(struct snd_soc_codec *codec, | ||
770 | enum snd_soc_bias_level level) | ||
771 | { | ||
772 | u16 reg; | ||
773 | switch (level) { | ||
774 | case SND_SOC_BIAS_ON: | ||
775 | case SND_SOC_BIAS_PREPARE: | ||
776 | case SND_SOC_BIAS_STANDBY: | ||
777 | break; | ||
778 | case SND_SOC_BIAS_OFF: | ||
779 | reg = wm8580_read(codec, WM8580_PWRDN1); | ||
780 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | ||
781 | break; | ||
782 | } | ||
783 | codec->bias_level = level; | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
788 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
789 | |||
790 | struct snd_soc_dai wm8580_dai[] = { | ||
791 | { | ||
792 | .name = "WM8580 PAIFRX", | ||
793 | .id = 0, | ||
794 | .playback = { | ||
795 | .stream_name = "Playback", | ||
796 | .channels_min = 1, | ||
797 | .channels_max = 6, | ||
798 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
799 | .formats = WM8580_FORMATS, | ||
800 | }, | ||
801 | .ops = { | ||
802 | .hw_params = wm8580_paif_hw_params, | ||
803 | }, | ||
804 | .dai_ops = { | ||
805 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
806 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
807 | .set_pll = wm8580_set_dai_pll, | ||
808 | .digital_mute = wm8580_digital_mute, | ||
809 | }, | ||
810 | }, | ||
811 | { | ||
812 | .name = "WM8580 PAIFTX", | ||
813 | .id = 1, | ||
814 | .capture = { | ||
815 | .stream_name = "Capture", | ||
816 | .channels_min = 2, | ||
817 | .channels_max = 2, | ||
818 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
819 | .formats = WM8580_FORMATS, | ||
820 | }, | ||
821 | .ops = { | ||
822 | .hw_params = wm8580_paif_hw_params, | ||
823 | }, | ||
824 | .dai_ops = { | ||
825 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
826 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
827 | .set_pll = wm8580_set_dai_pll, | ||
828 | }, | ||
829 | }, | ||
830 | }; | ||
831 | EXPORT_SYMBOL_GPL(wm8580_dai); | ||
832 | |||
833 | /* | ||
834 | * initialise the WM8580 driver | ||
835 | * register the mixer and dsp interfaces with the kernel | ||
836 | */ | ||
837 | static int wm8580_init(struct snd_soc_device *socdev) | ||
838 | { | ||
839 | struct snd_soc_codec *codec = socdev->codec; | ||
840 | int ret = 0; | ||
841 | |||
842 | codec->name = "WM8580"; | ||
843 | codec->owner = THIS_MODULE; | ||
844 | codec->read = wm8580_read_reg_cache; | ||
845 | codec->write = wm8580_write; | ||
846 | codec->set_bias_level = wm8580_set_bias_level; | ||
847 | codec->dai = wm8580_dai; | ||
848 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
849 | codec->reg_cache_size = ARRAY_SIZE(wm8580_reg); | ||
850 | codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg), | ||
851 | GFP_KERNEL); | ||
852 | |||
853 | if (codec->reg_cache == NULL) | ||
854 | return -ENOMEM; | ||
855 | |||
856 | /* Get the codec into a known state */ | ||
857 | wm8580_write(codec, WM8580_RESET, 0); | ||
858 | |||
859 | /* Power up and get individual control of the DACs */ | ||
860 | wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) & | ||
861 | ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD)); | ||
862 | |||
863 | /* Make VMID high impedence */ | ||
864 | wm8580_write(codec, WM8580_ADC_CONTROL1, | ||
865 | wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100); | ||
866 | |||
867 | /* register pcms */ | ||
868 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, | ||
869 | SNDRV_DEFAULT_STR1); | ||
870 | if (ret < 0) { | ||
871 | printk(KERN_ERR "wm8580: failed to create pcms\n"); | ||
872 | goto pcm_err; | ||
873 | } | ||
874 | |||
875 | wm8580_add_controls(codec); | ||
876 | wm8580_add_widgets(codec); | ||
877 | |||
878 | ret = snd_soc_register_card(socdev); | ||
879 | if (ret < 0) { | ||
880 | printk(KERN_ERR "wm8580: failed to register card\n"); | ||
881 | goto card_err; | ||
882 | } | ||
883 | return ret; | ||
884 | |||
885 | card_err: | ||
886 | snd_soc_free_pcms(socdev); | ||
887 | snd_soc_dapm_free(socdev); | ||
888 | pcm_err: | ||
889 | kfree(codec->reg_cache); | ||
890 | return ret; | ||
891 | } | ||
892 | |||
893 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
894 | around */ | ||
895 | static struct snd_soc_device *wm8580_socdev; | ||
896 | |||
897 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
898 | |||
899 | /* | ||
900 | * WM8580 2 wire address is determined by GPIO5 | ||
901 | * state during powerup. | ||
902 | * low = 0x1a | ||
903 | * high = 0x1b | ||
904 | */ | ||
905 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
906 | |||
907 | /* Magic definition of all other variables and things */ | ||
908 | I2C_CLIENT_INSMOD; | ||
909 | |||
910 | static struct i2c_driver wm8580_i2c_driver; | ||
911 | static struct i2c_client client_template; | ||
912 | |||
913 | static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
914 | { | ||
915 | struct snd_soc_device *socdev = wm8580_socdev; | ||
916 | struct wm8580_setup_data *setup = socdev->codec_data; | ||
917 | struct snd_soc_codec *codec = socdev->codec; | ||
918 | struct i2c_client *i2c; | ||
919 | int ret; | ||
920 | |||
921 | if (addr != setup->i2c_address) | ||
922 | return -ENODEV; | ||
923 | |||
924 | client_template.adapter = adap; | ||
925 | client_template.addr = addr; | ||
926 | |||
927 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
928 | if (i2c == NULL) { | ||
929 | kfree(codec); | ||
930 | return -ENOMEM; | ||
931 | } | ||
932 | i2c_set_clientdata(i2c, codec); | ||
933 | codec->control_data = i2c; | ||
934 | |||
935 | ret = i2c_attach_client(i2c); | ||
936 | if (ret < 0) { | ||
937 | dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); | ||
938 | goto err; | ||
939 | } | ||
940 | |||
941 | ret = wm8580_init(socdev); | ||
942 | if (ret < 0) { | ||
943 | dev_err(&i2c->dev, "failed to initialise WM8580\n"); | ||
944 | goto err; | ||
945 | } | ||
946 | |||
947 | return ret; | ||
948 | |||
949 | err: | ||
950 | kfree(codec); | ||
951 | kfree(i2c); | ||
952 | return ret; | ||
953 | } | ||
954 | |||
955 | static int wm8580_i2c_detach(struct i2c_client *client) | ||
956 | { | ||
957 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
958 | i2c_detach_client(client); | ||
959 | kfree(codec->reg_cache); | ||
960 | kfree(client); | ||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | static int wm8580_i2c_attach(struct i2c_adapter *adap) | ||
965 | { | ||
966 | return i2c_probe(adap, &addr_data, wm8580_codec_probe); | ||
967 | } | ||
968 | |||
969 | /* corgi i2c codec control layer */ | ||
970 | static struct i2c_driver wm8580_i2c_driver = { | ||
971 | .driver = { | ||
972 | .name = "WM8580 I2C Codec", | ||
973 | .owner = THIS_MODULE, | ||
974 | }, | ||
975 | .attach_adapter = wm8580_i2c_attach, | ||
976 | .detach_client = wm8580_i2c_detach, | ||
977 | .command = NULL, | ||
978 | }; | ||
979 | |||
980 | static struct i2c_client client_template = { | ||
981 | .name = "WM8580", | ||
982 | .driver = &wm8580_i2c_driver, | ||
983 | }; | ||
984 | #endif | ||
985 | |||
986 | static int wm8580_probe(struct platform_device *pdev) | ||
987 | { | ||
988 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
989 | struct wm8580_setup_data *setup; | ||
990 | struct snd_soc_codec *codec; | ||
991 | struct wm8580_priv *wm8580; | ||
992 | int ret = 0; | ||
993 | |||
994 | pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION); | ||
995 | |||
996 | setup = socdev->codec_data; | ||
997 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
998 | if (codec == NULL) | ||
999 | return -ENOMEM; | ||
1000 | |||
1001 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
1002 | if (wm8580 == NULL) { | ||
1003 | kfree(codec); | ||
1004 | return -ENOMEM; | ||
1005 | } | ||
1006 | |||
1007 | codec->private_data = wm8580; | ||
1008 | socdev->codec = codec; | ||
1009 | mutex_init(&codec->mutex); | ||
1010 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1011 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1012 | wm8580_socdev = socdev; | ||
1013 | |||
1014 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1015 | if (setup->i2c_address) { | ||
1016 | normal_i2c[0] = setup->i2c_address; | ||
1017 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1018 | ret = i2c_add_driver(&wm8580_i2c_driver); | ||
1019 | if (ret != 0) | ||
1020 | printk(KERN_ERR "can't add i2c driver"); | ||
1021 | } | ||
1022 | #else | ||
1023 | /* Add other interfaces here */ | ||
1024 | #endif | ||
1025 | return ret; | ||
1026 | } | ||
1027 | |||
1028 | /* power down chip */ | ||
1029 | static int wm8580_remove(struct platform_device *pdev) | ||
1030 | { | ||
1031 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1032 | struct snd_soc_codec *codec = socdev->codec; | ||
1033 | |||
1034 | if (codec->control_data) | ||
1035 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1036 | snd_soc_free_pcms(socdev); | ||
1037 | snd_soc_dapm_free(socdev); | ||
1038 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1039 | i2c_del_driver(&wm8580_i2c_driver); | ||
1040 | #endif | ||
1041 | kfree(codec->private_data); | ||
1042 | kfree(codec); | ||
1043 | |||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
1048 | .probe = wm8580_probe, | ||
1049 | .remove = wm8580_remove, | ||
1050 | }; | ||
1051 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
1052 | |||
1053 | MODULE_DESCRIPTION("ASoC WM8580 driver"); | ||
1054 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
1055 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h new file mode 100644 index 00000000000..589ddaba21d --- /dev/null +++ b/sound/soc/codecs/wm8580.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * wm8580.h -- audio driver for WM8580 | ||
3 | * | ||
4 | * Copyright 2008 Samsung Electronics. | ||
5 | * Author: Ryu Euiyoul | ||
6 | * ryu.real@gmail.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef _WM8580_H | ||
16 | #define _WM8580_H | ||
17 | |||
18 | #define WM8580_PLLA 1 | ||
19 | #define WM8580_PLLB 2 | ||
20 | |||
21 | #define WM8580_MCLK 1 | ||
22 | #define WM8580_DAC_CLKSEL 2 | ||
23 | #define WM8580_CLKOUTSRC 3 | ||
24 | |||
25 | #define WM8580_CLKSRC_MCLK 1 | ||
26 | #define WM8580_CLKSRC_PLLA 2 | ||
27 | #define WM8580_CLKSRC_PLLB 3 | ||
28 | #define WM8580_CLKSRC_OSC 4 | ||
29 | #define WM8580_CLKSRC_NONE 5 | ||
30 | |||
31 | struct wm8580_setup_data { | ||
32 | unsigned short i2c_address; | ||
33 | }; | ||
34 | |||
35 | #define WM8580_DAI_PAIFRX 0 | ||
36 | #define WM8580_DAI_PAIFTX 1 | ||
37 | |||
38 | extern struct snd_soc_dai wm8580_dai[]; | ||
39 | extern struct snd_soc_codec_device soc_codec_dev_wm8580; | ||
40 | |||
41 | #endif | ||
42 | |||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9402fcaf04f..7b64d9a7ff7 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
@@ -570,88 +571,144 @@ static struct snd_soc_device *wm8731_socdev; | |||
570 | * low = 0x1a | 571 | * low = 0x1a |
571 | * high = 0x1b | 572 | * high = 0x1b |
572 | */ | 573 | */ |
573 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
574 | 574 | ||
575 | /* Magic definition of all other variables and things */ | 575 | static int wm8731_i2c_probe(struct i2c_client *i2c, |
576 | I2C_CLIENT_INSMOD; | 576 | const struct i2c_device_id *id) |
577 | |||
578 | static struct i2c_driver wm8731_i2c_driver; | ||
579 | static struct i2c_client client_template; | ||
580 | |||
581 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
582 | around */ | ||
583 | |||
584 | static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
585 | { | 577 | { |
586 | struct snd_soc_device *socdev = wm8731_socdev; | 578 | struct snd_soc_device *socdev = wm8731_socdev; |
587 | struct wm8731_setup_data *setup = socdev->codec_data; | ||
588 | struct snd_soc_codec *codec = socdev->codec; | 579 | struct snd_soc_codec *codec = socdev->codec; |
589 | struct i2c_client *i2c; | ||
590 | int ret; | 580 | int ret; |
591 | 581 | ||
592 | if (addr != setup->i2c_address) | ||
593 | return -ENODEV; | ||
594 | |||
595 | client_template.adapter = adap; | ||
596 | client_template.addr = addr; | ||
597 | |||
598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
599 | if (i2c == NULL) | ||
600 | return -ENOMEM; | ||
601 | |||
602 | i2c_set_clientdata(i2c, codec); | 582 | i2c_set_clientdata(i2c, codec); |
603 | codec->control_data = i2c; | 583 | codec->control_data = i2c; |
604 | 584 | ||
605 | ret = i2c_attach_client(i2c); | ||
606 | if (ret < 0) { | ||
607 | pr_err("failed to attach codec at addr %x\n", addr); | ||
608 | goto err; | ||
609 | } | ||
610 | |||
611 | ret = wm8731_init(socdev); | 585 | ret = wm8731_init(socdev); |
612 | if (ret < 0) { | 586 | if (ret < 0) |
613 | pr_err("failed to initialise WM8731\n"); | 587 | pr_err("failed to initialise WM8731\n"); |
614 | goto err; | ||
615 | } | ||
616 | return ret; | ||
617 | 588 | ||
618 | err: | ||
619 | kfree(i2c); | ||
620 | return ret; | 589 | return ret; |
621 | } | 590 | } |
622 | 591 | ||
623 | static int wm8731_i2c_detach(struct i2c_client *client) | 592 | static int wm8731_i2c_remove(struct i2c_client *client) |
624 | { | 593 | { |
625 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 594 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
626 | i2c_detach_client(client); | ||
627 | kfree(codec->reg_cache); | 595 | kfree(codec->reg_cache); |
628 | kfree(client); | ||
629 | return 0; | 596 | return 0; |
630 | } | 597 | } |
631 | 598 | ||
632 | static int wm8731_i2c_attach(struct i2c_adapter *adap) | 599 | static const struct i2c_device_id wm8731_i2c_id[] = { |
633 | { | 600 | { "wm8731", 0 }, |
634 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); | 601 | { } |
635 | } | 602 | }; |
603 | MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); | ||
636 | 604 | ||
637 | /* corgi i2c codec control layer */ | ||
638 | static struct i2c_driver wm8731_i2c_driver = { | 605 | static struct i2c_driver wm8731_i2c_driver = { |
639 | .driver = { | 606 | .driver = { |
640 | .name = "WM8731 I2C Codec", | 607 | .name = "WM8731 I2C Codec", |
641 | .owner = THIS_MODULE, | 608 | .owner = THIS_MODULE, |
642 | }, | 609 | }, |
643 | .id = I2C_DRIVERID_WM8731, | 610 | .probe = wm8731_i2c_probe, |
644 | .attach_adapter = wm8731_i2c_attach, | 611 | .remove = wm8731_i2c_remove, |
645 | .detach_client = wm8731_i2c_detach, | 612 | .id_table = wm8731_i2c_id, |
646 | .command = NULL, | ||
647 | }; | 613 | }; |
648 | 614 | ||
649 | static struct i2c_client client_template = { | 615 | static int wm8731_add_i2c_device(struct platform_device *pdev, |
650 | .name = "WM8731", | 616 | const struct wm8731_setup_data *setup) |
651 | .driver = &wm8731_i2c_driver, | 617 | { |
652 | }; | 618 | struct i2c_board_info info; |
619 | struct i2c_adapter *adapter; | ||
620 | struct i2c_client *client; | ||
621 | int ret; | ||
622 | |||
623 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
624 | if (ret != 0) { | ||
625 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
630 | info.addr = setup->i2c_address; | ||
631 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
632 | |||
633 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
634 | if (!adapter) { | ||
635 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
636 | setup->i2c_bus); | ||
637 | goto err_driver; | ||
638 | } | ||
639 | |||
640 | client = i2c_new_device(adapter, &info); | ||
641 | i2c_put_adapter(adapter); | ||
642 | if (!client) { | ||
643 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
644 | (unsigned int)info.addr); | ||
645 | goto err_driver; | ||
646 | } | ||
647 | |||
648 | return 0; | ||
649 | |||
650 | err_driver: | ||
651 | i2c_del_driver(&wm8731_i2c_driver); | ||
652 | return -ENODEV; | ||
653 | } | ||
653 | #endif | 654 | #endif |
654 | 655 | ||
656 | #if defined(CONFIG_SPI_MASTER) | ||
657 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | ||
658 | { | ||
659 | struct snd_soc_device *socdev = wm8731_socdev; | ||
660 | struct snd_soc_codec *codec = socdev->codec; | ||
661 | int ret; | ||
662 | |||
663 | codec->control_data = spi; | ||
664 | |||
665 | ret = wm8731_init(socdev); | ||
666 | if (ret < 0) | ||
667 | dev_err(&spi->dev, "failed to initialise WM8731\n"); | ||
668 | |||
669 | return ret; | ||
670 | } | ||
671 | |||
672 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
673 | { | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static struct spi_driver wm8731_spi_driver = { | ||
678 | .driver = { | ||
679 | .name = "wm8731", | ||
680 | .bus = &spi_bus_type, | ||
681 | .owner = THIS_MODULE, | ||
682 | }, | ||
683 | .probe = wm8731_spi_probe, | ||
684 | .remove = __devexit_p(wm8731_spi_remove), | ||
685 | }; | ||
686 | |||
687 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | ||
688 | { | ||
689 | struct spi_transfer t; | ||
690 | struct spi_message m; | ||
691 | u8 msg[2]; | ||
692 | |||
693 | if (len <= 0) | ||
694 | return 0; | ||
695 | |||
696 | msg[0] = data[0]; | ||
697 | msg[1] = data[1]; | ||
698 | |||
699 | spi_message_init(&m); | ||
700 | memset(&t, 0, (sizeof t)); | ||
701 | |||
702 | t.tx_buf = &msg[0]; | ||
703 | t.len = len; | ||
704 | |||
705 | spi_message_add_tail(&t, &m); | ||
706 | spi_sync(spi, &m); | ||
707 | |||
708 | return len; | ||
709 | } | ||
710 | #endif /* CONFIG_SPI_MASTER */ | ||
711 | |||
655 | static int wm8731_probe(struct platform_device *pdev) | 712 | static int wm8731_probe(struct platform_device *pdev) |
656 | { | 713 | { |
657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 714 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -680,16 +737,21 @@ static int wm8731_probe(struct platform_device *pdev) | |||
680 | INIT_LIST_HEAD(&codec->dapm_paths); | 737 | INIT_LIST_HEAD(&codec->dapm_paths); |
681 | 738 | ||
682 | wm8731_socdev = socdev; | 739 | wm8731_socdev = socdev; |
740 | ret = -ENODEV; | ||
741 | |||
683 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 742 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
684 | if (setup->i2c_address) { | 743 | if (setup->i2c_address) { |
685 | normal_i2c[0] = setup->i2c_address; | ||
686 | codec->hw_write = (hw_write_t)i2c_master_send; | 744 | codec->hw_write = (hw_write_t)i2c_master_send; |
687 | ret = i2c_add_driver(&wm8731_i2c_driver); | 745 | ret = wm8731_add_i2c_device(pdev, setup); |
746 | } | ||
747 | #endif | ||
748 | #if defined(CONFIG_SPI_MASTER) | ||
749 | if (setup->spi) { | ||
750 | codec->hw_write = (hw_write_t)wm8731_spi_write; | ||
751 | ret = spi_register_driver(&wm8731_spi_driver); | ||
688 | if (ret != 0) | 752 | if (ret != 0) |
689 | printk(KERN_ERR "can't add i2c driver"); | 753 | printk(KERN_ERR "can't add spi driver"); |
690 | } | 754 | } |
691 | #else | ||
692 | /* Add other interfaces here */ | ||
693 | #endif | 755 | #endif |
694 | 756 | ||
695 | if (ret != 0) { | 757 | if (ret != 0) { |
@@ -711,8 +773,12 @@ static int wm8731_remove(struct platform_device *pdev) | |||
711 | snd_soc_free_pcms(socdev); | 773 | snd_soc_free_pcms(socdev); |
712 | snd_soc_dapm_free(socdev); | 774 | snd_soc_dapm_free(socdev); |
713 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 775 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
776 | i2c_unregister_device(codec->control_data); | ||
714 | i2c_del_driver(&wm8731_i2c_driver); | 777 | i2c_del_driver(&wm8731_i2c_driver); |
715 | #endif | 778 | #endif |
779 | #if defined(CONFIG_SPI_MASTER) | ||
780 | spi_unregister_driver(&wm8731_spi_driver); | ||
781 | #endif | ||
716 | kfree(codec->private_data); | 782 | kfree(codec->private_data); |
717 | kfree(codec); | 783 | kfree(codec); |
718 | 784 | ||
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 99f2e3c60e3..95190e9c0c1 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h | |||
@@ -35,6 +35,8 @@ | |||
35 | #define WM8731_DAI 0 | 35 | #define WM8731_DAI 0 |
36 | 36 | ||
37 | struct wm8731_setup_data { | 37 | struct wm8731_setup_data { |
38 | int spi; | ||
39 | int i2c_bus; | ||
38 | unsigned short i2c_address; | 40 | unsigned short i2c_address; |
39 | }; | 41 | }; |
40 | 42 | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index dd1f55404b2..4892e398a59 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | ||
22 | #include <sound/core.h> | 23 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
@@ -841,88 +842,147 @@ static struct snd_soc_device *wm8750_socdev; | |||
841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 842 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
842 | 843 | ||
843 | /* | 844 | /* |
844 | * WM8731 2 wire address is determined by GPIO5 | 845 | * WM8750 2 wire address is determined by GPIO5 |
845 | * state during powerup. | 846 | * state during powerup. |
846 | * low = 0x1a | 847 | * low = 0x1a |
847 | * high = 0x1b | 848 | * high = 0x1b |
848 | */ | 849 | */ |
849 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
850 | 850 | ||
851 | /* Magic definition of all other variables and things */ | 851 | static int wm8750_i2c_probe(struct i2c_client *i2c, |
852 | I2C_CLIENT_INSMOD; | 852 | const struct i2c_device_id *id) |
853 | |||
854 | static struct i2c_driver wm8750_i2c_driver; | ||
855 | static struct i2c_client client_template; | ||
856 | |||
857 | static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
858 | { | 853 | { |
859 | struct snd_soc_device *socdev = wm8750_socdev; | 854 | struct snd_soc_device *socdev = wm8750_socdev; |
860 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
861 | struct snd_soc_codec *codec = socdev->codec; | 855 | struct snd_soc_codec *codec = socdev->codec; |
862 | struct i2c_client *i2c; | ||
863 | int ret; | 856 | int ret; |
864 | 857 | ||
865 | if (addr != setup->i2c_address) | ||
866 | return -ENODEV; | ||
867 | |||
868 | client_template.adapter = adap; | ||
869 | client_template.addr = addr; | ||
870 | |||
871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
872 | if (i2c == NULL) | ||
873 | return -ENOMEM; | ||
874 | |||
875 | i2c_set_clientdata(i2c, codec); | 858 | i2c_set_clientdata(i2c, codec); |
876 | codec->control_data = i2c; | 859 | codec->control_data = i2c; |
877 | 860 | ||
878 | ret = i2c_attach_client(i2c); | ||
879 | if (ret < 0) { | ||
880 | pr_err("failed to attach codec at addr %x\n", addr); | ||
881 | goto err; | ||
882 | } | ||
883 | |||
884 | ret = wm8750_init(socdev); | 861 | ret = wm8750_init(socdev); |
885 | if (ret < 0) { | 862 | if (ret < 0) |
886 | pr_err("failed to initialise WM8750\n"); | 863 | pr_err("failed to initialise WM8750\n"); |
887 | goto err; | ||
888 | } | ||
889 | return ret; | ||
890 | 864 | ||
891 | err: | ||
892 | kfree(i2c); | ||
893 | return ret; | 865 | return ret; |
894 | } | 866 | } |
895 | 867 | ||
896 | static int wm8750_i2c_detach(struct i2c_client *client) | 868 | static int wm8750_i2c_remove(struct i2c_client *client) |
897 | { | 869 | { |
898 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 870 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
899 | i2c_detach_client(client); | ||
900 | kfree(codec->reg_cache); | 871 | kfree(codec->reg_cache); |
901 | kfree(client); | ||
902 | return 0; | 872 | return 0; |
903 | } | 873 | } |
904 | 874 | ||
905 | static int wm8750_i2c_attach(struct i2c_adapter *adap) | 875 | static const struct i2c_device_id wm8750_i2c_id[] = { |
906 | { | 876 | { "wm8750", 0 }, |
907 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); | 877 | { } |
908 | } | 878 | }; |
879 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | ||
909 | 880 | ||
910 | /* corgi i2c codec control layer */ | ||
911 | static struct i2c_driver wm8750_i2c_driver = { | 881 | static struct i2c_driver wm8750_i2c_driver = { |
912 | .driver = { | 882 | .driver = { |
913 | .name = "WM8750 I2C Codec", | 883 | .name = "WM8750 I2C Codec", |
914 | .owner = THIS_MODULE, | 884 | .owner = THIS_MODULE, |
915 | }, | 885 | }, |
916 | .id = I2C_DRIVERID_WM8750, | 886 | .probe = wm8750_i2c_probe, |
917 | .attach_adapter = wm8750_i2c_attach, | 887 | .remove = wm8750_i2c_remove, |
918 | .detach_client = wm8750_i2c_detach, | 888 | .id_table = wm8750_i2c_id, |
919 | .command = NULL, | ||
920 | }; | 889 | }; |
921 | 890 | ||
922 | static struct i2c_client client_template = { | 891 | static int wm8750_add_i2c_device(struct platform_device *pdev, |
923 | .name = "WM8750", | 892 | const struct wm8750_setup_data *setup) |
924 | .driver = &wm8750_i2c_driver, | 893 | { |
894 | struct i2c_board_info info; | ||
895 | struct i2c_adapter *adapter; | ||
896 | struct i2c_client *client; | ||
897 | int ret; | ||
898 | |||
899 | ret = i2c_add_driver(&wm8750_i2c_driver); | ||
900 | if (ret != 0) { | ||
901 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
906 | info.addr = setup->i2c_address; | ||
907 | strlcpy(info.type, "wm8750", I2C_NAME_SIZE); | ||
908 | |||
909 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
910 | if (!adapter) { | ||
911 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
912 | setup->i2c_bus); | ||
913 | goto err_driver; | ||
914 | } | ||
915 | |||
916 | client = i2c_new_device(adapter, &info); | ||
917 | i2c_put_adapter(adapter); | ||
918 | if (!client) { | ||
919 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
920 | (unsigned int)info.addr); | ||
921 | goto err_driver; | ||
922 | } | ||
923 | |||
924 | return 0; | ||
925 | |||
926 | err_driver: | ||
927 | i2c_del_driver(&wm8750_i2c_driver); | ||
928 | return -ENODEV; | ||
929 | } | ||
930 | #endif | ||
931 | |||
932 | #if defined(CONFIG_SPI_MASTER) | ||
933 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | ||
934 | { | ||
935 | struct snd_soc_device *socdev = wm8750_socdev; | ||
936 | struct snd_soc_codec *codec = socdev->codec; | ||
937 | int ret; | ||
938 | |||
939 | codec->control_data = spi; | ||
940 | |||
941 | ret = wm8750_init(socdev); | ||
942 | if (ret < 0) | ||
943 | dev_err(&spi->dev, "failed to initialise WM8750\n"); | ||
944 | |||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | static int __devexit wm8750_spi_remove(struct spi_device *spi) | ||
949 | { | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static struct spi_driver wm8750_spi_driver = { | ||
954 | .driver = { | ||
955 | .name = "wm8750", | ||
956 | .bus = &spi_bus_type, | ||
957 | .owner = THIS_MODULE, | ||
958 | }, | ||
959 | .probe = wm8750_spi_probe, | ||
960 | .remove = __devexit_p(wm8750_spi_remove), | ||
925 | }; | 961 | }; |
962 | |||
963 | static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) | ||
964 | { | ||
965 | struct spi_transfer t; | ||
966 | struct spi_message m; | ||
967 | u8 msg[2]; | ||
968 | |||
969 | if (len <= 0) | ||
970 | return 0; | ||
971 | |||
972 | msg[0] = data[0]; | ||
973 | msg[1] = data[1]; | ||
974 | |||
975 | spi_message_init(&m); | ||
976 | memset(&t, 0, (sizeof t)); | ||
977 | |||
978 | t.tx_buf = &msg[0]; | ||
979 | t.len = len; | ||
980 | |||
981 | spi_message_add_tail(&t, &m); | ||
982 | spi_sync(spi, &m); | ||
983 | |||
984 | return len; | ||
985 | } | ||
926 | #endif | 986 | #endif |
927 | 987 | ||
928 | static int wm8750_probe(struct platform_device *pdev) | 988 | static int wm8750_probe(struct platform_device *pdev) |
@@ -931,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
931 | struct wm8750_setup_data *setup = socdev->codec_data; | 991 | struct wm8750_setup_data *setup = socdev->codec_data; |
932 | struct snd_soc_codec *codec; | 992 | struct snd_soc_codec *codec; |
933 | struct wm8750_priv *wm8750; | 993 | struct wm8750_priv *wm8750; |
934 | int ret = 0; | 994 | int ret; |
935 | 995 | ||
936 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); | 996 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
937 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 997 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -952,16 +1012,21 @@ static int wm8750_probe(struct platform_device *pdev) | |||
952 | wm8750_socdev = socdev; | 1012 | wm8750_socdev = socdev; |
953 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | 1013 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); |
954 | 1014 | ||
1015 | ret = -ENODEV; | ||
1016 | |||
955 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1017 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
956 | if (setup->i2c_address) { | 1018 | if (setup->i2c_address) { |
957 | normal_i2c[0] = setup->i2c_address; | ||
958 | codec->hw_write = (hw_write_t)i2c_master_send; | 1019 | codec->hw_write = (hw_write_t)i2c_master_send; |
959 | ret = i2c_add_driver(&wm8750_i2c_driver); | 1020 | ret = wm8750_add_i2c_device(pdev, setup); |
1021 | } | ||
1022 | #endif | ||
1023 | #if defined(CONFIG_SPI_MASTER) | ||
1024 | if (setup->spi) { | ||
1025 | codec->hw_write = (hw_write_t)wm8750_spi_write; | ||
1026 | ret = spi_register_driver(&wm8750_spi_driver); | ||
960 | if (ret != 0) | 1027 | if (ret != 0) |
961 | printk(KERN_ERR "can't add i2c driver"); | 1028 | printk(KERN_ERR "can't add spi driver"); |
962 | } | 1029 | } |
963 | #else | ||
964 | /* Add other interfaces here */ | ||
965 | #endif | 1030 | #endif |
966 | 1031 | ||
967 | if (ret != 0) { | 1032 | if (ret != 0) { |
@@ -1002,8 +1067,12 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1002 | snd_soc_free_pcms(socdev); | 1067 | snd_soc_free_pcms(socdev); |
1003 | snd_soc_dapm_free(socdev); | 1068 | snd_soc_dapm_free(socdev); |
1004 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1069 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1070 | i2c_unregister_device(codec->control_data); | ||
1005 | i2c_del_driver(&wm8750_i2c_driver); | 1071 | i2c_del_driver(&wm8750_i2c_driver); |
1006 | #endif | 1072 | #endif |
1073 | #if defined(CONFIG_SPI_MASTER) | ||
1074 | spi_unregister_driver(&wm8750_spi_driver); | ||
1075 | #endif | ||
1007 | kfree(codec->private_data); | 1076 | kfree(codec->private_data); |
1008 | kfree(codec); | 1077 | kfree(codec); |
1009 | 1078 | ||
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index 8ef30e628b2..1dc100e19cf 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h | |||
@@ -58,6 +58,8 @@ | |||
58 | #define WM8750_SYSCLK 0 | 58 | #define WM8750_SYSCLK 0 |
59 | 59 | ||
60 | struct wm8750_setup_data { | 60 | struct wm8750_setup_data { |
61 | int spi; | ||
62 | int i2c_bus; | ||
61 | unsigned short i2c_address; | 63 | unsigned short i2c_address; |
62 | }; | 64 | }; |
63 | 65 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5761164fe16..8c4df44f334 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -583,7 +583,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 583 | ||
584 | /* out 4 */ | 584 | /* out 4 */ |
585 | {"Out4 Mux", "VREF", "VREF"}, | 585 | {"Out4 Mux", "VREF", "VREF"}, |
586 | {"Out4 Mux", "Capture ST", "Capture ST Mixer"}, | 586 | {"Out4 Mux", "Capture ST", "Playback Mixer"}, |
587 | {"Out4 Mux", "LOUT2", "LOUT2"}, | 587 | {"Out4 Mux", "LOUT2", "LOUT2"}, |
588 | {"Out 4", NULL, "Out4 Mux"}, | 588 | {"Out 4", NULL, "Out4 Mux"}, |
589 | {"OUT4", NULL, "Out 4"}, | 589 | {"OUT4", NULL, "Out 4"}, |
@@ -607,7 +607,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
607 | /* Capture Right Mux */ | 607 | /* Capture Right Mux */ |
608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, | 608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, |
609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, | 609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, |
610 | {"Capture Right Mux", "Sidetone", "Capture ST Mixer"}, | 610 | {"Capture Right Mux", "Sidetone", "Playback Mixer"}, |
611 | 611 | ||
612 | /* Mono Capture mixer-mux */ | 612 | /* Mono Capture mixer-mux */ |
613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, | 613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, |
@@ -1637,84 +1637,86 @@ static struct snd_soc_device *wm8753_socdev; | |||
1637 | * low = 0x1a | 1637 | * low = 0x1a |
1638 | * high = 0x1b | 1638 | * high = 0x1b |
1639 | */ | 1639 | */ |
1640 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1641 | 1640 | ||
1642 | /* Magic definition of all other variables and things */ | 1641 | static int wm8753_i2c_probe(struct i2c_client *i2c, |
1643 | I2C_CLIENT_INSMOD; | 1642 | const struct i2c_device_id *id) |
1644 | |||
1645 | static struct i2c_driver wm8753_i2c_driver; | ||
1646 | static struct i2c_client client_template; | ||
1647 | |||
1648 | static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1649 | { | 1643 | { |
1650 | struct snd_soc_device *socdev = wm8753_socdev; | 1644 | struct snd_soc_device *socdev = wm8753_socdev; |
1651 | struct wm8753_setup_data *setup = socdev->codec_data; | ||
1652 | struct snd_soc_codec *codec = socdev->codec; | 1645 | struct snd_soc_codec *codec = socdev->codec; |
1653 | struct i2c_client *i2c; | ||
1654 | int ret; | 1646 | int ret; |
1655 | 1647 | ||
1656 | if (addr != setup->i2c_address) | ||
1657 | return -ENODEV; | ||
1658 | |||
1659 | client_template.adapter = adap; | ||
1660 | client_template.addr = addr; | ||
1661 | |||
1662 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1663 | if (!i2c) | ||
1664 | return -ENOMEM; | ||
1665 | |||
1666 | i2c_set_clientdata(i2c, codec); | 1648 | i2c_set_clientdata(i2c, codec); |
1667 | codec->control_data = i2c; | 1649 | codec->control_data = i2c; |
1668 | 1650 | ||
1669 | ret = i2c_attach_client(i2c); | ||
1670 | if (ret < 0) { | ||
1671 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1672 | goto err; | ||
1673 | } | ||
1674 | |||
1675 | ret = wm8753_init(socdev); | 1651 | ret = wm8753_init(socdev); |
1676 | if (ret < 0) { | 1652 | if (ret < 0) |
1677 | pr_err("failed to initialise WM8753\n"); | 1653 | pr_err("failed to initialise WM8753\n"); |
1678 | goto err; | ||
1679 | } | ||
1680 | |||
1681 | return ret; | ||
1682 | 1654 | ||
1683 | err: | ||
1684 | kfree(i2c); | ||
1685 | return ret; | 1655 | return ret; |
1686 | } | 1656 | } |
1687 | 1657 | ||
1688 | static int wm8753_i2c_detach(struct i2c_client *client) | 1658 | static int wm8753_i2c_remove(struct i2c_client *client) |
1689 | { | 1659 | { |
1690 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1660 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1691 | i2c_detach_client(client); | ||
1692 | kfree(codec->reg_cache); | 1661 | kfree(codec->reg_cache); |
1693 | kfree(client); | ||
1694 | return 0; | 1662 | return 0; |
1695 | } | 1663 | } |
1696 | 1664 | ||
1697 | static int wm8753_i2c_attach(struct i2c_adapter *adap) | 1665 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1698 | { | 1666 | { "wm8753", 0 }, |
1699 | return i2c_probe(adap, &addr_data, wm8753_codec_probe); | 1667 | { } |
1700 | } | 1668 | }; |
1669 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1701 | 1670 | ||
1702 | /* corgi i2c codec control layer */ | ||
1703 | static struct i2c_driver wm8753_i2c_driver = { | 1671 | static struct i2c_driver wm8753_i2c_driver = { |
1704 | .driver = { | 1672 | .driver = { |
1705 | .name = "WM8753 I2C Codec", | 1673 | .name = "WM8753 I2C Codec", |
1706 | .owner = THIS_MODULE, | 1674 | .owner = THIS_MODULE, |
1707 | }, | 1675 | }, |
1708 | .id = I2C_DRIVERID_WM8753, | 1676 | .probe = wm8753_i2c_probe, |
1709 | .attach_adapter = wm8753_i2c_attach, | 1677 | .remove = wm8753_i2c_remove, |
1710 | .detach_client = wm8753_i2c_detach, | 1678 | .id_table = wm8753_i2c_id, |
1711 | .command = NULL, | ||
1712 | }; | 1679 | }; |
1713 | 1680 | ||
1714 | static struct i2c_client client_template = { | 1681 | static int wm8753_add_i2c_device(struct platform_device *pdev, |
1715 | .name = "WM8753", | 1682 | const struct wm8753_setup_data *setup) |
1716 | .driver = &wm8753_i2c_driver, | 1683 | { |
1717 | }; | 1684 | struct i2c_board_info info; |
1685 | struct i2c_adapter *adapter; | ||
1686 | struct i2c_client *client; | ||
1687 | int ret; | ||
1688 | |||
1689 | ret = i2c_add_driver(&wm8753_i2c_driver); | ||
1690 | if (ret != 0) { | ||
1691 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1692 | return ret; | ||
1693 | } | ||
1694 | |||
1695 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1696 | info.addr = setup->i2c_address; | ||
1697 | strlcpy(info.type, "wm8753", I2C_NAME_SIZE); | ||
1698 | |||
1699 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1700 | if (!adapter) { | ||
1701 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1702 | setup->i2c_bus); | ||
1703 | goto err_driver; | ||
1704 | } | ||
1705 | |||
1706 | client = i2c_new_device(adapter, &info); | ||
1707 | i2c_put_adapter(adapter); | ||
1708 | if (!client) { | ||
1709 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1710 | (unsigned int)info.addr); | ||
1711 | goto err_driver; | ||
1712 | } | ||
1713 | |||
1714 | return 0; | ||
1715 | |||
1716 | err_driver: | ||
1717 | i2c_del_driver(&wm8753_i2c_driver); | ||
1718 | return -ENODEV; | ||
1719 | } | ||
1718 | #endif | 1720 | #endif |
1719 | 1721 | ||
1720 | static int wm8753_probe(struct platform_device *pdev) | 1722 | static int wm8753_probe(struct platform_device *pdev) |
@@ -1748,11 +1750,8 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1748 | 1750 | ||
1749 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1751 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1750 | if (setup->i2c_address) { | 1752 | if (setup->i2c_address) { |
1751 | normal_i2c[0] = setup->i2c_address; | ||
1752 | codec->hw_write = (hw_write_t)i2c_master_send; | 1753 | codec->hw_write = (hw_write_t)i2c_master_send; |
1753 | ret = i2c_add_driver(&wm8753_i2c_driver); | 1754 | ret = wm8753_add_i2c_device(pdev, setup); |
1754 | if (ret != 0) | ||
1755 | printk(KERN_ERR "can't add i2c driver"); | ||
1756 | } | 1755 | } |
1757 | #else | 1756 | #else |
1758 | /* Add other interfaces here */ | 1757 | /* Add other interfaces here */ |
@@ -1796,6 +1795,7 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1796 | snd_soc_free_pcms(socdev); | 1795 | snd_soc_free_pcms(socdev); |
1797 | snd_soc_dapm_free(socdev); | 1796 | snd_soc_dapm_free(socdev); |
1798 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1797 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1798 | i2c_unregister_device(codec->control_data); | ||
1799 | i2c_del_driver(&wm8753_i2c_driver); | 1799 | i2c_del_driver(&wm8753_i2c_driver); |
1800 | #endif | 1800 | #endif |
1801 | kfree(codec->private_data); | 1801 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 44f5f1ff0cc..7defde069f1 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -79,6 +79,7 @@ | |||
79 | #define WM8753_ADCTL2 0x3f | 79 | #define WM8753_ADCTL2 0x3f |
80 | 80 | ||
81 | struct wm8753_setup_data { | 81 | struct wm8753_setup_data { |
82 | int i2c_bus; | ||
82 | unsigned short i2c_address; | 83 | unsigned short i2c_address; |
83 | }; | 84 | }; |
84 | 85 | ||
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c new file mode 100644 index 00000000000..0b8c6d38b48 --- /dev/null +++ b/sound/soc/codecs/wm8900.c | |||
@@ -0,0 +1,1542 @@ | |||
1 | /* | ||
2 | * wm8900.c -- WM8900 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2007, 2008 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * TODO: | ||
13 | * - Tristating. | ||
14 | * - TDM. | ||
15 | * - Jack detect. | ||
16 | * - FLL source configuration, currently only MCLK is supported. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | #include <sound/initval.h> | ||
34 | #include <sound/tlv.h> | ||
35 | |||
36 | #include "wm8900.h" | ||
37 | |||
38 | /* WM8900 register space */ | ||
39 | #define WM8900_REG_RESET 0x0 | ||
40 | #define WM8900_REG_ID 0x0 | ||
41 | #define WM8900_REG_POWER1 0x1 | ||
42 | #define WM8900_REG_POWER2 0x2 | ||
43 | #define WM8900_REG_POWER3 0x3 | ||
44 | #define WM8900_REG_AUDIO1 0x4 | ||
45 | #define WM8900_REG_AUDIO2 0x5 | ||
46 | #define WM8900_REG_CLOCKING1 0x6 | ||
47 | #define WM8900_REG_CLOCKING2 0x7 | ||
48 | #define WM8900_REG_AUDIO3 0x8 | ||
49 | #define WM8900_REG_AUDIO4 0x9 | ||
50 | #define WM8900_REG_DACCTRL 0xa | ||
51 | #define WM8900_REG_LDAC_DV 0xb | ||
52 | #define WM8900_REG_RDAC_DV 0xc | ||
53 | #define WM8900_REG_SIDETONE 0xd | ||
54 | #define WM8900_REG_ADCCTRL 0xe | ||
55 | #define WM8900_REG_LADC_DV 0xf | ||
56 | #define WM8900_REG_RADC_DV 0x10 | ||
57 | #define WM8900_REG_GPIO 0x12 | ||
58 | #define WM8900_REG_INCTL 0x15 | ||
59 | #define WM8900_REG_LINVOL 0x16 | ||
60 | #define WM8900_REG_RINVOL 0x17 | ||
61 | #define WM8900_REG_INBOOSTMIX1 0x18 | ||
62 | #define WM8900_REG_INBOOSTMIX2 0x19 | ||
63 | #define WM8900_REG_ADCPATH 0x1a | ||
64 | #define WM8900_REG_AUXBOOST 0x1b | ||
65 | #define WM8900_REG_ADDCTL 0x1e | ||
66 | #define WM8900_REG_FLLCTL1 0x24 | ||
67 | #define WM8900_REG_FLLCTL2 0x25 | ||
68 | #define WM8900_REG_FLLCTL3 0x26 | ||
69 | #define WM8900_REG_FLLCTL4 0x27 | ||
70 | #define WM8900_REG_FLLCTL5 0x28 | ||
71 | #define WM8900_REG_FLLCTL6 0x29 | ||
72 | #define WM8900_REG_LOUTMIXCTL1 0x2c | ||
73 | #define WM8900_REG_ROUTMIXCTL1 0x2d | ||
74 | #define WM8900_REG_BYPASS1 0x2e | ||
75 | #define WM8900_REG_BYPASS2 0x2f | ||
76 | #define WM8900_REG_AUXOUT_CTL 0x30 | ||
77 | #define WM8900_REG_LOUT1CTL 0x33 | ||
78 | #define WM8900_REG_ROUT1CTL 0x34 | ||
79 | #define WM8900_REG_LOUT2CTL 0x35 | ||
80 | #define WM8900_REG_ROUT2CTL 0x36 | ||
81 | #define WM8900_REG_HPCTL1 0x3a | ||
82 | #define WM8900_REG_OUTBIASCTL 0x73 | ||
83 | |||
84 | #define WM8900_MAXREG 0x80 | ||
85 | |||
86 | #define WM8900_REG_ADDCTL_OUT1_DIS 0x80 | ||
87 | #define WM8900_REG_ADDCTL_OUT2_DIS 0x40 | ||
88 | #define WM8900_REG_ADDCTL_VMID_DIS 0x20 | ||
89 | #define WM8900_REG_ADDCTL_BIAS_SRC 0x10 | ||
90 | #define WM8900_REG_ADDCTL_VMID_SOFTST 0x04 | ||
91 | #define WM8900_REG_ADDCTL_TEMP_SD 0x02 | ||
92 | |||
93 | #define WM8900_REG_GPIO_TEMP_ENA 0x2 | ||
94 | |||
95 | #define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100 | ||
96 | #define WM8900_REG_POWER1_BIAS_ENA 0x0008 | ||
97 | #define WM8900_REG_POWER1_VMID_BUF_ENA 0x0004 | ||
98 | #define WM8900_REG_POWER1_FLL_ENA 0x0040 | ||
99 | |||
100 | #define WM8900_REG_POWER2_SYSCLK_ENA 0x8000 | ||
101 | #define WM8900_REG_POWER2_ADCL_ENA 0x0002 | ||
102 | #define WM8900_REG_POWER2_ADCR_ENA 0x0001 | ||
103 | |||
104 | #define WM8900_REG_POWER3_DACL_ENA 0x0002 | ||
105 | #define WM8900_REG_POWER3_DACR_ENA 0x0001 | ||
106 | |||
107 | #define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018 | ||
108 | #define WM8900_REG_AUDIO1_LRCLK_INV 0x0080 | ||
109 | #define WM8900_REG_AUDIO1_BCLK_INV 0x0100 | ||
110 | |||
111 | #define WM8900_REG_CLOCKING1_BCLK_DIR 0x1 | ||
112 | #define WM8900_REG_CLOCKING1_MCLK_SRC 0x100 | ||
113 | #define WM8900_REG_CLOCKING1_BCLK_MASK (~0x01e) | ||
114 | #define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000) | ||
115 | |||
116 | #define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0 | ||
117 | #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c | ||
118 | |||
119 | #define WM8900_REG_DACCTRL_MUTE 0x004 | ||
120 | #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400 | ||
121 | |||
122 | #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800 | ||
123 | |||
124 | #define WM8900_REG_AUDIO4_DACLRC_DIR 0x0800 | ||
125 | |||
126 | #define WM8900_REG_FLLCTL1_OSC_ENA 0x100 | ||
127 | |||
128 | #define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100 | ||
129 | |||
130 | #define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80 | ||
131 | #define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40 | ||
132 | #define WM8900_REG_HPCTL1_HP_CLAMP_IP 0x20 | ||
133 | #define WM8900_REG_HPCTL1_HP_CLAMP_OP 0x10 | ||
134 | #define WM8900_REG_HPCTL1_HP_SHORT 0x08 | ||
135 | #define WM8900_REG_HPCTL1_HP_SHORT2 0x04 | ||
136 | |||
137 | #define WM8900_LRC_MASK 0xfc00 | ||
138 | |||
139 | struct snd_soc_codec_device soc_codec_dev_wm8900; | ||
140 | |||
141 | struct wm8900_priv { | ||
142 | u32 fll_in; /* FLL input frequency */ | ||
143 | u32 fll_out; /* FLL output frequency */ | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * wm8900 register cache. We can't read the entire register space and we | ||
148 | * have slow control buses so we cache the registers. | ||
149 | */ | ||
150 | static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { | ||
151 | 0x8900, 0x0000, | ||
152 | 0xc000, 0x0000, | ||
153 | 0x4050, 0x4000, | ||
154 | 0x0008, 0x0000, | ||
155 | 0x0040, 0x0040, | ||
156 | 0x1004, 0x00c0, | ||
157 | 0x00c0, 0x0000, | ||
158 | 0x0100, 0x00c0, | ||
159 | 0x00c0, 0x0000, | ||
160 | 0xb001, 0x0000, | ||
161 | 0x0000, 0x0044, | ||
162 | 0x004c, 0x004c, | ||
163 | 0x0044, 0x0044, | ||
164 | 0x0000, 0x0044, | ||
165 | 0x0000, 0x0000, | ||
166 | 0x0002, 0x0000, | ||
167 | 0x0000, 0x0000, | ||
168 | 0x0000, 0x0000, | ||
169 | 0x0008, 0x0000, | ||
170 | 0x0000, 0x0008, | ||
171 | 0x0097, 0x0100, | ||
172 | 0x0000, 0x0000, | ||
173 | 0x0050, 0x0050, | ||
174 | 0x0055, 0x0055, | ||
175 | 0x0055, 0x0000, | ||
176 | 0x0000, 0x0079, | ||
177 | 0x0079, 0x0079, | ||
178 | 0x0079, 0x0000, | ||
179 | /* Remaining registers all zero */ | ||
180 | }; | ||
181 | |||
182 | /* | ||
183 | * read wm8900 register cache | ||
184 | */ | ||
185 | static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec, | ||
186 | unsigned int reg) | ||
187 | { | ||
188 | u16 *cache = codec->reg_cache; | ||
189 | |||
190 | BUG_ON(reg >= WM8900_MAXREG); | ||
191 | |||
192 | if (reg == WM8900_REG_ID) | ||
193 | return 0; | ||
194 | |||
195 | return cache[reg]; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * write wm8900 register cache | ||
200 | */ | ||
201 | static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec, | ||
202 | u16 reg, unsigned int value) | ||
203 | { | ||
204 | u16 *cache = codec->reg_cache; | ||
205 | |||
206 | BUG_ON(reg >= WM8900_MAXREG); | ||
207 | |||
208 | cache[reg] = value; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * write to the WM8900 register space | ||
213 | */ | ||
214 | static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg, | ||
215 | unsigned int value) | ||
216 | { | ||
217 | u8 data[3]; | ||
218 | |||
219 | if (value == wm8900_read_reg_cache(codec, reg)) | ||
220 | return 0; | ||
221 | |||
222 | /* data is | ||
223 | * D15..D9 WM8900 register offset | ||
224 | * D8...D0 register data | ||
225 | */ | ||
226 | data[0] = reg; | ||
227 | data[1] = value >> 8; | ||
228 | data[2] = value & 0x00ff; | ||
229 | |||
230 | wm8900_write_reg_cache(codec, reg, value); | ||
231 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
232 | return 0; | ||
233 | else | ||
234 | return -EIO; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Read from the wm8900. | ||
239 | */ | ||
240 | static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg) | ||
241 | { | ||
242 | struct i2c_msg xfer[2]; | ||
243 | u16 data; | ||
244 | int ret; | ||
245 | struct i2c_client *client = codec->control_data; | ||
246 | |||
247 | BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1); | ||
248 | |||
249 | /* Write register */ | ||
250 | xfer[0].addr = client->addr; | ||
251 | xfer[0].flags = 0; | ||
252 | xfer[0].len = 1; | ||
253 | xfer[0].buf = ® | ||
254 | |||
255 | /* Read data */ | ||
256 | xfer[1].addr = client->addr; | ||
257 | xfer[1].flags = I2C_M_RD; | ||
258 | xfer[1].len = 2; | ||
259 | xfer[1].buf = (u8 *)&data; | ||
260 | |||
261 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
262 | if (ret != 2) { | ||
263 | printk(KERN_CRIT "i2c_transfer returned %d\n", ret); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | return (data >> 8) | ((data & 0xff) << 8); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Read from the WM8900 register space. Most registers can't be read | ||
272 | * and are therefore supplied from cache. | ||
273 | */ | ||
274 | static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg) | ||
275 | { | ||
276 | switch (reg) { | ||
277 | case WM8900_REG_ID: | ||
278 | return wm8900_chip_read(codec, reg); | ||
279 | default: | ||
280 | return wm8900_read_reg_cache(codec, reg); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static void wm8900_reset(struct snd_soc_codec *codec) | ||
285 | { | ||
286 | wm8900_write(codec, WM8900_REG_RESET, 0); | ||
287 | |||
288 | memcpy(codec->reg_cache, wm8900_reg_defaults, | ||
289 | sizeof(codec->reg_cache)); | ||
290 | } | ||
291 | |||
292 | static int wm8900_hp_event(struct snd_soc_dapm_widget *w, | ||
293 | struct snd_kcontrol *kcontrol, int event) | ||
294 | { | ||
295 | struct snd_soc_codec *codec = w->codec; | ||
296 | u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1); | ||
297 | |||
298 | switch (event) { | ||
299 | case SND_SOC_DAPM_PRE_PMU: | ||
300 | /* Clamp headphone outputs */ | ||
301 | hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | | ||
302 | WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
303 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
304 | break; | ||
305 | |||
306 | case SND_SOC_DAPM_POST_PMU: | ||
307 | /* Enable the input stage */ | ||
308 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP; | ||
309 | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | | ||
310 | WM8900_REG_HPCTL1_HP_SHORT2 | | ||
311 | WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; | ||
312 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
313 | |||
314 | msleep(400); | ||
315 | |||
316 | /* Enable the output stage */ | ||
317 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
318 | hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; | ||
319 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
320 | |||
321 | /* Remove the shorts */ | ||
322 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; | ||
323 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
324 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; | ||
325 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
326 | break; | ||
327 | |||
328 | case SND_SOC_DAPM_PRE_PMD: | ||
329 | /* Short the output */ | ||
330 | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; | ||
331 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
332 | |||
333 | /* Disable the output stage */ | ||
334 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; | ||
335 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
336 | |||
337 | /* Clamp the outputs and power down input */ | ||
338 | hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | | ||
339 | WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
340 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; | ||
341 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
342 | break; | ||
343 | |||
344 | case SND_SOC_DAPM_POST_PMD: | ||
345 | /* Disable everything */ | ||
346 | wm8900_write(codec, WM8900_REG_HPCTL1, 0); | ||
347 | break; | ||
348 | |||
349 | default: | ||
350 | BUG(); | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0); | ||
357 | |||
358 | static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0); | ||
359 | |||
360 | static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0); | ||
361 | |||
362 | static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0); | ||
363 | |||
364 | static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); | ||
365 | |||
366 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); | ||
367 | |||
368 | static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0); | ||
369 | |||
370 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); | ||
371 | |||
372 | static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; | ||
373 | |||
374 | static const struct soc_enum mic_bias_level = | ||
375 | SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); | ||
376 | |||
377 | static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; | ||
378 | |||
379 | static const struct soc_enum dac_mute_rate = | ||
380 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); | ||
381 | |||
382 | static const char *dac_deemphasis_txt[] = { | ||
383 | "Disabled", "32kHz", "44.1kHz", "48kHz" | ||
384 | }; | ||
385 | |||
386 | static const struct soc_enum dac_deemphasis = | ||
387 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); | ||
388 | |||
389 | static const char *adc_hpf_cut_txt[] = { | ||
390 | "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" | ||
391 | }; | ||
392 | |||
393 | static const struct soc_enum adc_hpf_cut = | ||
394 | SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); | ||
395 | |||
396 | static const char *lr_txt[] = { | ||
397 | "Left", "Right" | ||
398 | }; | ||
399 | |||
400 | static const struct soc_enum aifl_src = | ||
401 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); | ||
402 | |||
403 | static const struct soc_enum aifr_src = | ||
404 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); | ||
405 | |||
406 | static const struct soc_enum dacl_src = | ||
407 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); | ||
408 | |||
409 | static const struct soc_enum dacr_src = | ||
410 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); | ||
411 | |||
412 | static const char *sidetone_txt[] = { | ||
413 | "Disabled", "Left ADC", "Right ADC" | ||
414 | }; | ||
415 | |||
416 | static const struct soc_enum dacl_sidetone = | ||
417 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); | ||
418 | |||
419 | static const struct soc_enum dacr_sidetone = | ||
420 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); | ||
421 | |||
422 | static const struct snd_kcontrol_new wm8900_snd_controls[] = { | ||
423 | SOC_ENUM("Mic Bias Level", mic_bias_level), | ||
424 | |||
425 | SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0, | ||
426 | in_pga_tlv), | ||
427 | SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1), | ||
428 | SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0), | ||
429 | |||
430 | SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0, | ||
431 | in_pga_tlv), | ||
432 | SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1), | ||
433 | SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0), | ||
434 | |||
435 | SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), | ||
436 | SOC_ENUM("DAC Mute Rate", dac_mute_rate), | ||
437 | SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), | ||
438 | SOC_ENUM("DAC Deemphasis", dac_deemphasis), | ||
439 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0), | ||
440 | SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, | ||
441 | 12, 1, 0), | ||
442 | |||
443 | SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0), | ||
444 | SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut), | ||
445 | SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0), | ||
446 | SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0, | ||
447 | adc_svol_tlv), | ||
448 | SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0, | ||
449 | adc_svol_tlv), | ||
450 | SOC_ENUM("Left Digital Audio Source", aifl_src), | ||
451 | SOC_ENUM("Right Digital Audio Source", aifr_src), | ||
452 | |||
453 | SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0, | ||
454 | dac_boost_tlv), | ||
455 | SOC_ENUM("Left DAC Source", dacl_src), | ||
456 | SOC_ENUM("Right DAC Source", dacr_src), | ||
457 | SOC_ENUM("Left DAC Sidetone", dacl_sidetone), | ||
458 | SOC_ENUM("Right DAC Sidetone", dacr_sidetone), | ||
459 | SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0), | ||
460 | |||
461 | SOC_DOUBLE_R_TLV("Digital Playback Volume", | ||
462 | WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV, | ||
463 | 1, 96, 0, dac_tlv), | ||
464 | SOC_DOUBLE_R_TLV("Digital Capture Volume", | ||
465 | WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv), | ||
466 | |||
467 | SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0, | ||
468 | out_mix_tlv), | ||
469 | SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0, | ||
470 | out_mix_tlv), | ||
471 | SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0, | ||
472 | out_mix_tlv), | ||
473 | SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0, | ||
474 | out_mix_tlv), | ||
475 | |||
476 | SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0, | ||
477 | out_mix_tlv), | ||
478 | SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0, | ||
479 | out_mix_tlv), | ||
480 | SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0, | ||
481 | out_mix_tlv), | ||
482 | SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0, | ||
483 | out_mix_tlv), | ||
484 | |||
485 | SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0, | ||
486 | in_boost_tlv), | ||
487 | SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0, | ||
488 | in_boost_tlv), | ||
489 | SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0, | ||
490 | in_boost_tlv), | ||
491 | SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0, | ||
492 | in_boost_tlv), | ||
493 | SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0, | ||
494 | in_boost_tlv), | ||
495 | SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0, | ||
496 | in_boost_tlv), | ||
497 | |||
498 | SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
499 | 0, 63, 0, out_pga_tlv), | ||
500 | SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
501 | 6, 1, 1), | ||
502 | SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
503 | 7, 1, 0), | ||
504 | |||
505 | SOC_DOUBLE_R_TLV("LINEOUT2 Volume", | ||
506 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, | ||
507 | 0, 63, 0, out_pga_tlv), | ||
508 | SOC_DOUBLE_R("LINEOUT2 Switch", | ||
509 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1), | ||
510 | SOC_DOUBLE_R("LINEOUT2 ZC Switch", | ||
511 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0), | ||
512 | SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, | ||
513 | 0, 1, 1), | ||
514 | |||
515 | }; | ||
516 | |||
517 | /* add non dapm controls */ | ||
518 | static int wm8900_add_controls(struct snd_soc_codec *codec) | ||
519 | { | ||
520 | int err, i; | ||
521 | |||
522 | for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) { | ||
523 | err = snd_ctl_add(codec->card, | ||
524 | snd_soc_cnew(&wm8900_snd_controls[i], | ||
525 | codec, NULL)); | ||
526 | if (err < 0) | ||
527 | return err; | ||
528 | } | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = | ||
534 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); | ||
535 | |||
536 | static const struct snd_kcontrol_new wm8900_dapm_routput2_control = | ||
537 | SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0); | ||
538 | |||
539 | static const struct snd_kcontrol_new wm8900_loutmix_controls[] = { | ||
540 | SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0), | ||
541 | SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0), | ||
542 | SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0), | ||
543 | SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0), | ||
544 | SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0), | ||
545 | }; | ||
546 | |||
547 | static const struct snd_kcontrol_new wm8900_routmix_controls[] = { | ||
548 | SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0), | ||
549 | SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0), | ||
550 | SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0), | ||
551 | SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0), | ||
552 | SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0), | ||
553 | }; | ||
554 | |||
555 | static const struct snd_kcontrol_new wm8900_linmix_controls[] = { | ||
556 | SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1), | ||
557 | SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1), | ||
558 | SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1), | ||
559 | SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0), | ||
560 | }; | ||
561 | |||
562 | static const struct snd_kcontrol_new wm8900_rinmix_controls[] = { | ||
563 | SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1), | ||
564 | SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1), | ||
565 | SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1), | ||
566 | SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0), | ||
567 | }; | ||
568 | |||
569 | static const struct snd_kcontrol_new wm8900_linpga_controls[] = { | ||
570 | SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0), | ||
571 | SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0), | ||
572 | SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0), | ||
573 | }; | ||
574 | |||
575 | static const struct snd_kcontrol_new wm8900_rinpga_controls[] = { | ||
576 | SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0), | ||
577 | SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0), | ||
578 | SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), | ||
579 | }; | ||
580 | |||
581 | static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" }; | ||
582 | |||
583 | static const struct soc_enum wm8900_lineout2_lp_mux = | ||
584 | SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux); | ||
585 | |||
586 | static const struct snd_kcontrol_new wm8900_lineout2_lp = | ||
587 | SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); | ||
588 | |||
589 | static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = { | ||
590 | |||
591 | /* Externally visible pins */ | ||
592 | SND_SOC_DAPM_OUTPUT("LINEOUT1L"), | ||
593 | SND_SOC_DAPM_OUTPUT("LINEOUT1R"), | ||
594 | SND_SOC_DAPM_OUTPUT("LINEOUT2L"), | ||
595 | SND_SOC_DAPM_OUTPUT("LINEOUT2R"), | ||
596 | SND_SOC_DAPM_OUTPUT("HP_L"), | ||
597 | SND_SOC_DAPM_OUTPUT("HP_R"), | ||
598 | |||
599 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
600 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
601 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
602 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
603 | SND_SOC_DAPM_INPUT("RINPUT3"), | ||
604 | SND_SOC_DAPM_INPUT("LINPUT3"), | ||
605 | SND_SOC_DAPM_INPUT("AUX"), | ||
606 | |||
607 | SND_SOC_DAPM_VMID("VMID"), | ||
608 | |||
609 | /* Input */ | ||
610 | SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0, | ||
611 | wm8900_linpga_controls, | ||
612 | ARRAY_SIZE(wm8900_linpga_controls)), | ||
613 | SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0, | ||
614 | wm8900_rinpga_controls, | ||
615 | ARRAY_SIZE(wm8900_rinpga_controls)), | ||
616 | |||
617 | SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0, | ||
618 | wm8900_linmix_controls, | ||
619 | ARRAY_SIZE(wm8900_linmix_controls)), | ||
620 | SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0, | ||
621 | wm8900_rinmix_controls, | ||
622 | ARRAY_SIZE(wm8900_rinmix_controls)), | ||
623 | |||
624 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0), | ||
625 | |||
626 | SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0), | ||
627 | SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0), | ||
628 | |||
629 | /* Output */ | ||
630 | SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0), | ||
631 | SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0), | ||
632 | |||
633 | SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0, | ||
634 | wm8900_hp_event, | ||
635 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
636 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
637 | |||
638 | SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0), | ||
639 | SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0), | ||
640 | |||
641 | SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp), | ||
642 | SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0), | ||
643 | SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0), | ||
644 | |||
645 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0, | ||
646 | wm8900_loutmix_controls, | ||
647 | ARRAY_SIZE(wm8900_loutmix_controls)), | ||
648 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0, | ||
649 | wm8900_routmix_controls, | ||
650 | ARRAY_SIZE(wm8900_routmix_controls)), | ||
651 | }; | ||
652 | |||
653 | /* Target, Path, Source */ | ||
654 | static const struct snd_soc_dapm_route audio_map[] = { | ||
655 | /* Inputs */ | ||
656 | {"Left Input PGA", "LINPUT1 Switch", "LINPUT1"}, | ||
657 | {"Left Input PGA", "LINPUT2 Switch", "LINPUT2"}, | ||
658 | {"Left Input PGA", "LINPUT3 Switch", "LINPUT3"}, | ||
659 | |||
660 | {"Right Input PGA", "RINPUT1 Switch", "RINPUT1"}, | ||
661 | {"Right Input PGA", "RINPUT2 Switch", "RINPUT2"}, | ||
662 | {"Right Input PGA", "RINPUT3 Switch", "RINPUT3"}, | ||
663 | |||
664 | {"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"}, | ||
665 | {"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"}, | ||
666 | {"Left Input Mixer", "AUX Switch", "AUX"}, | ||
667 | {"Left Input Mixer", "Input PGA Switch", "Left Input PGA"}, | ||
668 | |||
669 | {"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"}, | ||
670 | {"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"}, | ||
671 | {"Right Input Mixer", "AUX Switch", "AUX"}, | ||
672 | {"Right Input Mixer", "Input PGA Switch", "Right Input PGA"}, | ||
673 | |||
674 | {"ADCL", NULL, "Left Input Mixer"}, | ||
675 | {"ADCR", NULL, "Right Input Mixer"}, | ||
676 | |||
677 | /* Outputs */ | ||
678 | {"LINEOUT1L", NULL, "LINEOUT1L PGA"}, | ||
679 | {"LINEOUT1L PGA", NULL, "Left Output Mixer"}, | ||
680 | {"LINEOUT1R", NULL, "LINEOUT1R PGA"}, | ||
681 | {"LINEOUT1R PGA", NULL, "Right Output Mixer"}, | ||
682 | |||
683 | {"LINEOUT2L PGA", NULL, "Left Output Mixer"}, | ||
684 | {"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"}, | ||
685 | {"LINEOUT2 LP", "Enabled", "Left Output Mixer"}, | ||
686 | {"LINEOUT2L", NULL, "LINEOUT2 LP"}, | ||
687 | |||
688 | {"LINEOUT2R PGA", NULL, "Right Output Mixer"}, | ||
689 | {"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"}, | ||
690 | {"LINEOUT2 LP", "Enabled", "Right Output Mixer"}, | ||
691 | {"LINEOUT2R", NULL, "LINEOUT2 LP"}, | ||
692 | |||
693 | {"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"}, | ||
694 | {"Left Output Mixer", "AUX Bypass Switch", "AUX"}, | ||
695 | {"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, | ||
696 | {"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, | ||
697 | {"Left Output Mixer", "DACL Switch", "DACL"}, | ||
698 | |||
699 | {"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"}, | ||
700 | {"Right Output Mixer", "AUX Bypass Switch", "AUX"}, | ||
701 | {"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, | ||
702 | {"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, | ||
703 | {"Right Output Mixer", "DACR Switch", "DACR"}, | ||
704 | |||
705 | /* Note that the headphone output stage needs to be connected | ||
706 | * externally to LINEOUT2 via DC blocking capacitors. Other | ||
707 | * configurations are not supported. | ||
708 | * | ||
709 | * Note also that left and right headphone paths are treated as a | ||
710 | * mono path. | ||
711 | */ | ||
712 | {"Headphone Amplifier", NULL, "LINEOUT2 LP"}, | ||
713 | {"Headphone Amplifier", NULL, "LINEOUT2 LP"}, | ||
714 | {"HP_L", NULL, "Headphone Amplifier"}, | ||
715 | {"HP_R", NULL, "Headphone Amplifier"}, | ||
716 | }; | ||
717 | |||
718 | static int wm8900_add_widgets(struct snd_soc_codec *codec) | ||
719 | { | ||
720 | snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets, | ||
721 | ARRAY_SIZE(wm8900_dapm_widgets)); | ||
722 | |||
723 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
724 | |||
725 | snd_soc_dapm_new_widgets(codec); | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int wm8900_hw_params(struct snd_pcm_substream *substream, | ||
731 | struct snd_pcm_hw_params *params) | ||
732 | { | ||
733 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
734 | struct snd_soc_device *socdev = rtd->socdev; | ||
735 | struct snd_soc_codec *codec = socdev->codec; | ||
736 | u16 reg; | ||
737 | |||
738 | reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; | ||
739 | |||
740 | switch (params_format(params)) { | ||
741 | case SNDRV_PCM_FORMAT_S16_LE: | ||
742 | break; | ||
743 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
744 | reg |= 0x20; | ||
745 | break; | ||
746 | case SNDRV_PCM_FORMAT_S24_LE: | ||
747 | reg |= 0x40; | ||
748 | break; | ||
749 | case SNDRV_PCM_FORMAT_S32_LE: | ||
750 | reg |= 0x60; | ||
751 | break; | ||
752 | default: | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | wm8900_write(codec, WM8900_REG_AUDIO1, reg); | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | /* FLL divisors */ | ||
762 | struct _fll_div { | ||
763 | u16 fll_ratio; | ||
764 | u16 fllclk_div; | ||
765 | u16 fll_slow_lock_ref; | ||
766 | u16 n; | ||
767 | u16 k; | ||
768 | }; | ||
769 | |||
770 | /* The size in bits of the FLL divide multiplied by 10 | ||
771 | * to allow rounding later */ | ||
772 | #define FIXED_FLL_SIZE ((1 << 16) * 10) | ||
773 | |||
774 | static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, | ||
775 | unsigned int Fout) | ||
776 | { | ||
777 | u64 Kpart; | ||
778 | unsigned int K, Ndiv, Nmod, target; | ||
779 | unsigned int div; | ||
780 | |||
781 | BUG_ON(!Fout); | ||
782 | |||
783 | /* The FLL must run at 90-100MHz which is then scaled down to | ||
784 | * the output value by FLLCLK_DIV. */ | ||
785 | target = Fout; | ||
786 | div = 1; | ||
787 | while (target < 90000000) { | ||
788 | div *= 2; | ||
789 | target *= 2; | ||
790 | } | ||
791 | |||
792 | if (target > 100000000) | ||
793 | printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d" | ||
794 | " Fout=%d\n", target, Fref, Fout); | ||
795 | if (div > 32) { | ||
796 | printk(KERN_ERR "wm8900: Invalid FLL division rate %u, " | ||
797 | "Fref=%d, Fout=%d, target=%d\n", | ||
798 | div, Fref, Fout, target); | ||
799 | return -EINVAL; | ||
800 | } | ||
801 | |||
802 | fll_div->fllclk_div = div >> 2; | ||
803 | |||
804 | if (Fref < 48000) | ||
805 | fll_div->fll_slow_lock_ref = 1; | ||
806 | else | ||
807 | fll_div->fll_slow_lock_ref = 0; | ||
808 | |||
809 | Ndiv = target / Fref; | ||
810 | |||
811 | if (Fref < 1000000) | ||
812 | fll_div->fll_ratio = 8; | ||
813 | else | ||
814 | fll_div->fll_ratio = 1; | ||
815 | |||
816 | fll_div->n = Ndiv / fll_div->fll_ratio; | ||
817 | Nmod = (target / fll_div->fll_ratio) % Fref; | ||
818 | |||
819 | /* Calculate fractional part - scale up so we can round. */ | ||
820 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
821 | |||
822 | do_div(Kpart, Fref); | ||
823 | |||
824 | K = Kpart & 0xFFFFFFFF; | ||
825 | |||
826 | if ((K % 10) >= 5) | ||
827 | K += 5; | ||
828 | |||
829 | /* Move down to proper range now rounding is done */ | ||
830 | fll_div->k = K / 10; | ||
831 | |||
832 | BUG_ON(target != Fout * (fll_div->fllclk_div << 2)); | ||
833 | BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | static int wm8900_set_fll(struct snd_soc_codec *codec, | ||
839 | int fll_id, unsigned int freq_in, unsigned int freq_out) | ||
840 | { | ||
841 | struct wm8900_priv *wm8900 = codec->private_data; | ||
842 | struct _fll_div fll_div; | ||
843 | unsigned int reg; | ||
844 | |||
845 | if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out) | ||
846 | return 0; | ||
847 | |||
848 | /* The digital side should be disabled during any change. */ | ||
849 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
850 | wm8900_write(codec, WM8900_REG_POWER1, | ||
851 | reg & (~WM8900_REG_POWER1_FLL_ENA)); | ||
852 | |||
853 | /* Disable the FLL? */ | ||
854 | if (!freq_in || !freq_out) { | ||
855 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
856 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
857 | reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); | ||
858 | |||
859 | reg = wm8900_read(codec, WM8900_REG_FLLCTL1); | ||
860 | wm8900_write(codec, WM8900_REG_FLLCTL1, | ||
861 | reg & (~WM8900_REG_FLLCTL1_OSC_ENA)); | ||
862 | |||
863 | wm8900->fll_in = freq_in; | ||
864 | wm8900->fll_out = freq_out; | ||
865 | |||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | if (fll_factors(&fll_div, freq_in, freq_out) != 0) | ||
870 | goto reenable; | ||
871 | |||
872 | wm8900->fll_in = freq_in; | ||
873 | wm8900->fll_out = freq_out; | ||
874 | |||
875 | /* The osclilator *MUST* be enabled before we enable the | ||
876 | * digital circuit. */ | ||
877 | wm8900_write(codec, WM8900_REG_FLLCTL1, | ||
878 | fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA); | ||
879 | |||
880 | wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); | ||
881 | wm8900_write(codec, WM8900_REG_FLLCTL5, | ||
882 | (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f)); | ||
883 | |||
884 | if (fll_div.k) { | ||
885 | wm8900_write(codec, WM8900_REG_FLLCTL2, | ||
886 | (fll_div.k >> 8) | 0x100); | ||
887 | wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); | ||
888 | } else | ||
889 | wm8900_write(codec, WM8900_REG_FLLCTL2, 0); | ||
890 | |||
891 | if (fll_div.fll_slow_lock_ref) | ||
892 | wm8900_write(codec, WM8900_REG_FLLCTL6, | ||
893 | WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF); | ||
894 | else | ||
895 | wm8900_write(codec, WM8900_REG_FLLCTL6, 0); | ||
896 | |||
897 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
898 | wm8900_write(codec, WM8900_REG_POWER1, | ||
899 | reg | WM8900_REG_POWER1_FLL_ENA); | ||
900 | |||
901 | reenable: | ||
902 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
903 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
904 | reg | WM8900_REG_CLOCKING1_MCLK_SRC); | ||
905 | |||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
910 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
911 | { | ||
912 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); | ||
913 | } | ||
914 | |||
915 | static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
916 | int div_id, int div) | ||
917 | { | ||
918 | struct snd_soc_codec *codec = codec_dai->codec; | ||
919 | unsigned int reg; | ||
920 | |||
921 | switch (div_id) { | ||
922 | case WM8900_BCLK_DIV: | ||
923 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
924 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
925 | div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK)); | ||
926 | break; | ||
927 | case WM8900_OPCLK_DIV: | ||
928 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
929 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
930 | div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK)); | ||
931 | break; | ||
932 | case WM8900_DAC_LRCLK: | ||
933 | reg = wm8900_read(codec, WM8900_REG_AUDIO4); | ||
934 | wm8900_write(codec, WM8900_REG_AUDIO4, | ||
935 | div | (reg & WM8900_LRC_MASK)); | ||
936 | break; | ||
937 | case WM8900_ADC_LRCLK: | ||
938 | reg = wm8900_read(codec, WM8900_REG_AUDIO3); | ||
939 | wm8900_write(codec, WM8900_REG_AUDIO3, | ||
940 | div | (reg & WM8900_LRC_MASK)); | ||
941 | break; | ||
942 | case WM8900_DAC_CLKDIV: | ||
943 | reg = wm8900_read(codec, WM8900_REG_CLOCKING2); | ||
944 | wm8900_write(codec, WM8900_REG_CLOCKING2, | ||
945 | div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV)); | ||
946 | break; | ||
947 | case WM8900_ADC_CLKDIV: | ||
948 | reg = wm8900_read(codec, WM8900_REG_CLOCKING2); | ||
949 | wm8900_write(codec, WM8900_REG_CLOCKING2, | ||
950 | div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV)); | ||
951 | break; | ||
952 | case WM8900_LRCLK_MODE: | ||
953 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
954 | wm8900_write(codec, WM8900_REG_DACCTRL, | ||
955 | div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE)); | ||
956 | break; | ||
957 | default: | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | |||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | |||
965 | static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
966 | unsigned int fmt) | ||
967 | { | ||
968 | struct snd_soc_codec *codec = codec_dai->codec; | ||
969 | unsigned int clocking1, aif1, aif3, aif4; | ||
970 | |||
971 | clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
972 | aif1 = wm8900_read(codec, WM8900_REG_AUDIO1); | ||
973 | aif3 = wm8900_read(codec, WM8900_REG_AUDIO3); | ||
974 | aif4 = wm8900_read(codec, WM8900_REG_AUDIO4); | ||
975 | |||
976 | /* set master/slave audio interface */ | ||
977 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
978 | case SND_SOC_DAIFMT_CBS_CFS: | ||
979 | clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; | ||
980 | aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
981 | aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; | ||
982 | break; | ||
983 | case SND_SOC_DAIFMT_CBS_CFM: | ||
984 | clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; | ||
985 | aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
986 | aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; | ||
987 | break; | ||
988 | case SND_SOC_DAIFMT_CBM_CFM: | ||
989 | clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; | ||
990 | aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
991 | aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; | ||
992 | break; | ||
993 | case SND_SOC_DAIFMT_CBM_CFS: | ||
994 | clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; | ||
995 | aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
996 | aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; | ||
997 | break; | ||
998 | default: | ||
999 | return -EINVAL; | ||
1000 | } | ||
1001 | |||
1002 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1003 | case SND_SOC_DAIFMT_DSP_A: | ||
1004 | aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1005 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1006 | break; | ||
1007 | case SND_SOC_DAIFMT_DSP_B: | ||
1008 | aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1009 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1010 | break; | ||
1011 | case SND_SOC_DAIFMT_I2S: | ||
1012 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1013 | aif1 |= 0x10; | ||
1014 | break; | ||
1015 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1016 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1017 | break; | ||
1018 | case SND_SOC_DAIFMT_LEFT_J: | ||
1019 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1020 | aif1 |= 0x8; | ||
1021 | break; | ||
1022 | default: | ||
1023 | return -EINVAL; | ||
1024 | } | ||
1025 | |||
1026 | /* Clock inversion */ | ||
1027 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1028 | case SND_SOC_DAIFMT_DSP_A: | ||
1029 | case SND_SOC_DAIFMT_DSP_B: | ||
1030 | /* frame inversion not valid for DSP modes */ | ||
1031 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1032 | case SND_SOC_DAIFMT_NB_NF: | ||
1033 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1034 | break; | ||
1035 | case SND_SOC_DAIFMT_IB_NF: | ||
1036 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1037 | break; | ||
1038 | default: | ||
1039 | return -EINVAL; | ||
1040 | } | ||
1041 | break; | ||
1042 | case SND_SOC_DAIFMT_I2S: | ||
1043 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1044 | case SND_SOC_DAIFMT_LEFT_J: | ||
1045 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1046 | case SND_SOC_DAIFMT_NB_NF: | ||
1047 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1048 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1049 | break; | ||
1050 | case SND_SOC_DAIFMT_IB_IF: | ||
1051 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1052 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1053 | break; | ||
1054 | case SND_SOC_DAIFMT_IB_NF: | ||
1055 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1056 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1057 | break; | ||
1058 | case SND_SOC_DAIFMT_NB_IF: | ||
1059 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1060 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1061 | break; | ||
1062 | default: | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | break; | ||
1066 | default: | ||
1067 | return -EINVAL; | ||
1068 | } | ||
1069 | |||
1070 | wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1); | ||
1071 | wm8900_write(codec, WM8900_REG_AUDIO1, aif1); | ||
1072 | wm8900_write(codec, WM8900_REG_AUDIO3, aif3); | ||
1073 | wm8900_write(codec, WM8900_REG_AUDIO4, aif4); | ||
1074 | |||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
1079 | { | ||
1080 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1081 | u16 reg; | ||
1082 | |||
1083 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
1084 | |||
1085 | if (mute) | ||
1086 | reg |= WM8900_REG_DACCTRL_MUTE; | ||
1087 | else | ||
1088 | reg &= ~WM8900_REG_DACCTRL_MUTE; | ||
1089 | |||
1090 | wm8900_write(codec, WM8900_REG_DACCTRL, reg); | ||
1091 | |||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | #define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
1096 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
1097 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
1098 | |||
1099 | #define WM8900_PCM_FORMATS \ | ||
1100 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | ||
1101 | SNDRV_PCM_FORMAT_S24_LE) | ||
1102 | |||
1103 | struct snd_soc_dai wm8900_dai = { | ||
1104 | .name = "WM8900 HiFi", | ||
1105 | .playback = { | ||
1106 | .stream_name = "HiFi Playback", | ||
1107 | .channels_min = 1, | ||
1108 | .channels_max = 2, | ||
1109 | .rates = WM8900_RATES, | ||
1110 | .formats = WM8900_PCM_FORMATS, | ||
1111 | }, | ||
1112 | .capture = { | ||
1113 | .stream_name = "HiFi Capture", | ||
1114 | .channels_min = 1, | ||
1115 | .channels_max = 2, | ||
1116 | .rates = WM8900_RATES, | ||
1117 | .formats = WM8900_PCM_FORMATS, | ||
1118 | }, | ||
1119 | .ops = { | ||
1120 | .hw_params = wm8900_hw_params, | ||
1121 | }, | ||
1122 | .dai_ops = { | ||
1123 | .set_clkdiv = wm8900_set_dai_clkdiv, | ||
1124 | .set_pll = wm8900_set_dai_pll, | ||
1125 | .set_fmt = wm8900_set_dai_fmt, | ||
1126 | .digital_mute = wm8900_digital_mute, | ||
1127 | }, | ||
1128 | }; | ||
1129 | EXPORT_SYMBOL_GPL(wm8900_dai); | ||
1130 | |||
1131 | static int wm8900_set_bias_level(struct snd_soc_codec *codec, | ||
1132 | enum snd_soc_bias_level level) | ||
1133 | { | ||
1134 | u16 reg; | ||
1135 | |||
1136 | switch (level) { | ||
1137 | case SND_SOC_BIAS_ON: | ||
1138 | /* Enable thermal shutdown */ | ||
1139 | reg = wm8900_read(codec, WM8900_REG_GPIO); | ||
1140 | wm8900_write(codec, WM8900_REG_GPIO, | ||
1141 | reg | WM8900_REG_GPIO_TEMP_ENA); | ||
1142 | reg = wm8900_read(codec, WM8900_REG_ADDCTL); | ||
1143 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1144 | reg | WM8900_REG_ADDCTL_TEMP_SD); | ||
1145 | break; | ||
1146 | |||
1147 | case SND_SOC_BIAS_PREPARE: | ||
1148 | break; | ||
1149 | |||
1150 | case SND_SOC_BIAS_STANDBY: | ||
1151 | /* Charge capacitors if initial power up */ | ||
1152 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1153 | /* STARTUP_BIAS_ENA on */ | ||
1154 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1155 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1156 | |||
1157 | /* Startup bias mode */ | ||
1158 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1159 | WM8900_REG_ADDCTL_BIAS_SRC | | ||
1160 | WM8900_REG_ADDCTL_VMID_SOFTST); | ||
1161 | |||
1162 | /* VMID 2x50k */ | ||
1163 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1164 | WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1); | ||
1165 | |||
1166 | /* Allow capacitors to charge */ | ||
1167 | schedule_timeout_interruptible(msecs_to_jiffies(400)); | ||
1168 | |||
1169 | /* Enable bias */ | ||
1170 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1171 | WM8900_REG_POWER1_STARTUP_BIAS_ENA | | ||
1172 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1173 | |||
1174 | wm8900_write(codec, WM8900_REG_ADDCTL, 0); | ||
1175 | |||
1176 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1177 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1178 | } | ||
1179 | |||
1180 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
1181 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1182 | (reg & WM8900_REG_POWER1_FLL_ENA) | | ||
1183 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1184 | wm8900_write(codec, WM8900_REG_POWER2, | ||
1185 | WM8900_REG_POWER2_SYSCLK_ENA); | ||
1186 | wm8900_write(codec, WM8900_REG_POWER3, 0); | ||
1187 | break; | ||
1188 | |||
1189 | case SND_SOC_BIAS_OFF: | ||
1190 | /* Startup bias enable */ | ||
1191 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
1192 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1193 | reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1194 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1195 | WM8900_REG_ADDCTL_BIAS_SRC | | ||
1196 | WM8900_REG_ADDCTL_VMID_SOFTST); | ||
1197 | |||
1198 | /* Discharge caps */ | ||
1199 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1200 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1201 | schedule_timeout_interruptible(msecs_to_jiffies(500)); | ||
1202 | |||
1203 | /* Remove clamp */ | ||
1204 | wm8900_write(codec, WM8900_REG_HPCTL1, 0); | ||
1205 | |||
1206 | /* Power down */ | ||
1207 | wm8900_write(codec, WM8900_REG_ADDCTL, 0); | ||
1208 | wm8900_write(codec, WM8900_REG_POWER1, 0); | ||
1209 | wm8900_write(codec, WM8900_REG_POWER2, 0); | ||
1210 | wm8900_write(codec, WM8900_REG_POWER3, 0); | ||
1211 | |||
1212 | /* Need to let things settle before stopping the clock | ||
1213 | * to ensure that restart works, see "Stopping the | ||
1214 | * master clock" in the datasheet. */ | ||
1215 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | ||
1216 | wm8900_write(codec, WM8900_REG_POWER2, | ||
1217 | WM8900_REG_POWER2_SYSCLK_ENA); | ||
1218 | break; | ||
1219 | } | ||
1220 | codec->bias_level = level; | ||
1221 | return 0; | ||
1222 | } | ||
1223 | |||
1224 | static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) | ||
1225 | { | ||
1226 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1227 | struct snd_soc_codec *codec = socdev->codec; | ||
1228 | struct wm8900_priv *wm8900 = codec->private_data; | ||
1229 | int fll_out = wm8900->fll_out; | ||
1230 | int fll_in = wm8900->fll_in; | ||
1231 | int ret; | ||
1232 | |||
1233 | /* Stop the FLL in an orderly fashion */ | ||
1234 | ret = wm8900_set_fll(codec, 0, 0, 0); | ||
1235 | if (ret != 0) { | ||
1236 | dev_err(&pdev->dev, "Failed to stop FLL\n"); | ||
1237 | return ret; | ||
1238 | } | ||
1239 | |||
1240 | wm8900->fll_out = fll_out; | ||
1241 | wm8900->fll_in = fll_in; | ||
1242 | |||
1243 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | static int wm8900_resume(struct platform_device *pdev) | ||
1249 | { | ||
1250 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1251 | struct snd_soc_codec *codec = socdev->codec; | ||
1252 | struct wm8900_priv *wm8900 = codec->private_data; | ||
1253 | u16 *cache; | ||
1254 | int i, ret; | ||
1255 | |||
1256 | cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults), | ||
1257 | GFP_KERNEL); | ||
1258 | |||
1259 | wm8900_reset(codec); | ||
1260 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1261 | |||
1262 | /* Restart the FLL? */ | ||
1263 | if (wm8900->fll_out) { | ||
1264 | int fll_out = wm8900->fll_out; | ||
1265 | int fll_in = wm8900->fll_in; | ||
1266 | |||
1267 | wm8900->fll_in = 0; | ||
1268 | wm8900->fll_out = 0; | ||
1269 | |||
1270 | ret = wm8900_set_fll(codec, 0, fll_in, fll_out); | ||
1271 | if (ret != 0) { | ||
1272 | dev_err(&pdev->dev, "Failed to restart FLL\n"); | ||
1273 | return ret; | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | if (cache) { | ||
1278 | for (i = 0; i < WM8900_MAXREG; i++) | ||
1279 | wm8900_write(codec, i, cache[i]); | ||
1280 | kfree(cache); | ||
1281 | } else | ||
1282 | dev_err(&pdev->dev, "Unable to allocate register cache\n"); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | /* | ||
1288 | * initialise the WM8900 driver | ||
1289 | * register the mixer and dsp interfaces with the kernel | ||
1290 | */ | ||
1291 | static int wm8900_init(struct snd_soc_device *socdev) | ||
1292 | { | ||
1293 | struct snd_soc_codec *codec = socdev->codec; | ||
1294 | int ret = 0; | ||
1295 | unsigned int reg; | ||
1296 | struct i2c_client *i2c_client = socdev->codec->control_data; | ||
1297 | |||
1298 | codec->name = "WM8900"; | ||
1299 | codec->owner = THIS_MODULE; | ||
1300 | codec->read = wm8900_read; | ||
1301 | codec->write = wm8900_write; | ||
1302 | codec->dai = &wm8900_dai; | ||
1303 | codec->num_dai = 1; | ||
1304 | codec->reg_cache_size = WM8900_MAXREG; | ||
1305 | codec->reg_cache = kmemdup(wm8900_reg_defaults, | ||
1306 | sizeof(wm8900_reg_defaults), GFP_KERNEL); | ||
1307 | |||
1308 | if (codec->reg_cache == NULL) | ||
1309 | return -ENOMEM; | ||
1310 | |||
1311 | reg = wm8900_read(codec, WM8900_REG_ID); | ||
1312 | if (reg != 0x8900) { | ||
1313 | dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", | ||
1314 | reg); | ||
1315 | return -ENODEV; | ||
1316 | } | ||
1317 | |||
1318 | codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); | ||
1319 | if (codec->private_data == NULL) { | ||
1320 | ret = -ENOMEM; | ||
1321 | goto priv_err; | ||
1322 | } | ||
1323 | |||
1324 | /* Read back from the chip */ | ||
1325 | reg = wm8900_chip_read(codec, WM8900_REG_POWER1); | ||
1326 | reg = (reg >> 12) & 0xf; | ||
1327 | dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); | ||
1328 | |||
1329 | wm8900_reset(codec); | ||
1330 | |||
1331 | /* Latch the volume update bits */ | ||
1332 | wm8900_write(codec, WM8900_REG_LINVOL, | ||
1333 | wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); | ||
1334 | wm8900_write(codec, WM8900_REG_RINVOL, | ||
1335 | wm8900_read(codec, WM8900_REG_RINVOL) | 0x100); | ||
1336 | wm8900_write(codec, WM8900_REG_LOUT1CTL, | ||
1337 | wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100); | ||
1338 | wm8900_write(codec, WM8900_REG_ROUT1CTL, | ||
1339 | wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100); | ||
1340 | wm8900_write(codec, WM8900_REG_LOUT2CTL, | ||
1341 | wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100); | ||
1342 | wm8900_write(codec, WM8900_REG_ROUT2CTL, | ||
1343 | wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100); | ||
1344 | wm8900_write(codec, WM8900_REG_LDAC_DV, | ||
1345 | wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100); | ||
1346 | wm8900_write(codec, WM8900_REG_RDAC_DV, | ||
1347 | wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100); | ||
1348 | wm8900_write(codec, WM8900_REG_LADC_DV, | ||
1349 | wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100); | ||
1350 | wm8900_write(codec, WM8900_REG_RADC_DV, | ||
1351 | wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100); | ||
1352 | |||
1353 | /* Set the DAC and mixer output bias */ | ||
1354 | wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); | ||
1355 | |||
1356 | /* Register pcms */ | ||
1357 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1358 | if (ret < 0) { | ||
1359 | dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); | ||
1360 | goto pcm_err; | ||
1361 | } | ||
1362 | |||
1363 | /* Turn the chip on */ | ||
1364 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1365 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1366 | |||
1367 | wm8900_add_controls(codec); | ||
1368 | wm8900_add_widgets(codec); | ||
1369 | |||
1370 | ret = snd_soc_register_card(socdev); | ||
1371 | if (ret < 0) { | ||
1372 | dev_err(&i2c_client->dev, "Failed to register card\n"); | ||
1373 | goto card_err; | ||
1374 | } | ||
1375 | return ret; | ||
1376 | |||
1377 | card_err: | ||
1378 | snd_soc_free_pcms(socdev); | ||
1379 | snd_soc_dapm_free(socdev); | ||
1380 | pcm_err: | ||
1381 | kfree(codec->reg_cache); | ||
1382 | priv_err: | ||
1383 | kfree(codec->private_data); | ||
1384 | return ret; | ||
1385 | } | ||
1386 | |||
1387 | static struct snd_soc_device *wm8900_socdev; | ||
1388 | |||
1389 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1390 | |||
1391 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1392 | |||
1393 | /* Magic definition of all other variables and things */ | ||
1394 | I2C_CLIENT_INSMOD; | ||
1395 | |||
1396 | static struct i2c_driver wm8900_i2c_driver; | ||
1397 | static struct i2c_client client_template; | ||
1398 | |||
1399 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
1400 | around */ | ||
1401 | static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1402 | { | ||
1403 | struct snd_soc_device *socdev = wm8900_socdev; | ||
1404 | struct wm8900_setup_data *setup = socdev->codec_data; | ||
1405 | struct snd_soc_codec *codec = socdev->codec; | ||
1406 | struct i2c_client *i2c; | ||
1407 | int ret; | ||
1408 | |||
1409 | if (addr != setup->i2c_address) | ||
1410 | return -ENODEV; | ||
1411 | |||
1412 | dev_err(&adap->dev, "Probe on %x\n", addr); | ||
1413 | |||
1414 | client_template.adapter = adap; | ||
1415 | client_template.addr = addr; | ||
1416 | |||
1417 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1418 | if (i2c == NULL) { | ||
1419 | kfree(codec); | ||
1420 | return -ENOMEM; | ||
1421 | } | ||
1422 | i2c_set_clientdata(i2c, codec); | ||
1423 | codec->control_data = i2c; | ||
1424 | |||
1425 | ret = i2c_attach_client(i2c); | ||
1426 | if (ret < 0) { | ||
1427 | dev_err(&adap->dev, | ||
1428 | "failed to attach codec at addr %x\n", addr); | ||
1429 | goto err; | ||
1430 | } | ||
1431 | |||
1432 | ret = wm8900_init(socdev); | ||
1433 | if (ret < 0) { | ||
1434 | dev_err(&adap->dev, "failed to initialise WM8900\n"); | ||
1435 | goto err; | ||
1436 | } | ||
1437 | return ret; | ||
1438 | |||
1439 | err: | ||
1440 | kfree(codec); | ||
1441 | kfree(i2c); | ||
1442 | return ret; | ||
1443 | } | ||
1444 | |||
1445 | static int wm8900_i2c_detach(struct i2c_client *client) | ||
1446 | { | ||
1447 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1448 | i2c_detach_client(client); | ||
1449 | kfree(codec->reg_cache); | ||
1450 | kfree(client); | ||
1451 | return 0; | ||
1452 | } | ||
1453 | |||
1454 | static int wm8900_i2c_attach(struct i2c_adapter *adap) | ||
1455 | { | ||
1456 | return i2c_probe(adap, &addr_data, wm8900_codec_probe); | ||
1457 | } | ||
1458 | |||
1459 | /* corgi i2c codec control layer */ | ||
1460 | static struct i2c_driver wm8900_i2c_driver = { | ||
1461 | .driver = { | ||
1462 | .name = "WM8900 I2C codec", | ||
1463 | .owner = THIS_MODULE, | ||
1464 | }, | ||
1465 | .attach_adapter = wm8900_i2c_attach, | ||
1466 | .detach_client = wm8900_i2c_detach, | ||
1467 | .command = NULL, | ||
1468 | }; | ||
1469 | |||
1470 | static struct i2c_client client_template = { | ||
1471 | .name = "WM8900", | ||
1472 | .driver = &wm8900_i2c_driver, | ||
1473 | }; | ||
1474 | #endif | ||
1475 | |||
1476 | static int wm8900_probe(struct platform_device *pdev) | ||
1477 | { | ||
1478 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1479 | struct wm8900_setup_data *setup; | ||
1480 | struct snd_soc_codec *codec; | ||
1481 | int ret = 0; | ||
1482 | |||
1483 | dev_info(&pdev->dev, "WM8900 Audio Codec\n"); | ||
1484 | |||
1485 | setup = socdev->codec_data; | ||
1486 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1487 | if (codec == NULL) | ||
1488 | return -ENOMEM; | ||
1489 | |||
1490 | mutex_init(&codec->mutex); | ||
1491 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1492 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1493 | |||
1494 | socdev->codec = codec; | ||
1495 | |||
1496 | codec->set_bias_level = wm8900_set_bias_level; | ||
1497 | |||
1498 | wm8900_socdev = socdev; | ||
1499 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1500 | if (setup->i2c_address) { | ||
1501 | normal_i2c[0] = setup->i2c_address; | ||
1502 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1503 | ret = i2c_add_driver(&wm8900_i2c_driver); | ||
1504 | if (ret != 0) | ||
1505 | printk(KERN_ERR "can't add i2c driver"); | ||
1506 | } | ||
1507 | #else | ||
1508 | #error Non-I2C interfaces not yet supported | ||
1509 | #endif | ||
1510 | return ret; | ||
1511 | } | ||
1512 | |||
1513 | /* power down chip */ | ||
1514 | static int wm8900_remove(struct platform_device *pdev) | ||
1515 | { | ||
1516 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1517 | struct snd_soc_codec *codec = socdev->codec; | ||
1518 | |||
1519 | if (codec->control_data) | ||
1520 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1521 | |||
1522 | snd_soc_free_pcms(socdev); | ||
1523 | snd_soc_dapm_free(socdev); | ||
1524 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1525 | i2c_del_driver(&wm8900_i2c_driver); | ||
1526 | #endif | ||
1527 | kfree(codec); | ||
1528 | |||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1532 | struct snd_soc_codec_device soc_codec_dev_wm8900 = { | ||
1533 | .probe = wm8900_probe, | ||
1534 | .remove = wm8900_remove, | ||
1535 | .suspend = wm8900_suspend, | ||
1536 | .resume = wm8900_resume, | ||
1537 | }; | ||
1538 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); | ||
1539 | |||
1540 | MODULE_DESCRIPTION("ASoC WM8900 driver"); | ||
1541 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); | ||
1542 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h new file mode 100644 index 00000000000..ba450d99e90 --- /dev/null +++ b/sound/soc/codecs/wm8900.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * wm8900.h -- WM890 Soc Audio driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _WM8900_H | ||
10 | #define _WM8900_H | ||
11 | |||
12 | #define WM8900_FLL 1 | ||
13 | |||
14 | #define WM8900_BCLK_DIV 1 | ||
15 | #define WM8900_ADC_CLKDIV 2 | ||
16 | #define WM8900_DAC_CLKDIV 3 | ||
17 | #define WM8900_ADC_LRCLK 4 | ||
18 | #define WM8900_DAC_LRCLK 5 | ||
19 | #define WM8900_OPCLK_DIV 6 | ||
20 | #define WM8900_LRCLK_MODE 7 | ||
21 | |||
22 | #define WM8900_BCLK_DIV_1 0x00 | ||
23 | #define WM8900_BCLK_DIV_1_5 0x02 | ||
24 | #define WM8900_BCLK_DIV_2 0x04 | ||
25 | #define WM8900_BCLK_DIV_3 0x06 | ||
26 | #define WM8900_BCLK_DIV_4 0x08 | ||
27 | #define WM8900_BCLK_DIV_5_5 0x0a | ||
28 | #define WM8900_BCLK_DIV_6 0x0c | ||
29 | #define WM8900_BCLK_DIV_8 0x0e | ||
30 | #define WM8900_BCLK_DIV_11 0x10 | ||
31 | #define WM8900_BCLK_DIV_12 0x12 | ||
32 | #define WM8900_BCLK_DIV_16 0x14 | ||
33 | #define WM8900_BCLK_DIV_22 0x16 | ||
34 | #define WM8900_BCLK_DIV_24 0x18 | ||
35 | #define WM8900_BCLK_DIV_32 0x1a | ||
36 | #define WM8900_BCLK_DIV_44 0x1c | ||
37 | #define WM8900_BCLK_DIV_48 0x1e | ||
38 | |||
39 | #define WM8900_ADC_CLKDIV_1 0x00 | ||
40 | #define WM8900_ADC_CLKDIV_1_5 0x20 | ||
41 | #define WM8900_ADC_CLKDIV_2 0x40 | ||
42 | #define WM8900_ADC_CLKDIV_3 0x60 | ||
43 | #define WM8900_ADC_CLKDIV_4 0x80 | ||
44 | #define WM8900_ADC_CLKDIV_5_5 0xa0 | ||
45 | #define WM8900_ADC_CLKDIV_6 0xc0 | ||
46 | |||
47 | #define WM8900_DAC_CLKDIV_1 0x00 | ||
48 | #define WM8900_DAC_CLKDIV_1_5 0x04 | ||
49 | #define WM8900_DAC_CLKDIV_2 0x08 | ||
50 | #define WM8900_DAC_CLKDIV_3 0x0c | ||
51 | #define WM8900_DAC_CLKDIV_4 0x10 | ||
52 | #define WM8900_DAC_CLKDIV_5_5 0x14 | ||
53 | #define WM8900_DAC_CLKDIV_6 0x18 | ||
54 | |||
55 | #define WM8900_ | ||
56 | |||
57 | struct wm8900_setup_data { | ||
58 | unsigned short i2c_address; | ||
59 | }; | ||
60 | |||
61 | extern struct snd_soc_dai wm8900_dai; | ||
62 | extern struct snd_soc_codec_device soc_codec_dev_wm8900; | ||
63 | |||
64 | #endif | ||
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c new file mode 100644 index 00000000000..a3f54ec4226 --- /dev/null +++ b/sound/soc/codecs/wm8903.c | |||
@@ -0,0 +1,1813 @@ | |||
1 | /* | ||
2 | * wm8903.c -- WM8903 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * TODO: | ||
13 | * - TDM mode configuration. | ||
14 | * - Mic detect. | ||
15 | * - Digital microphone support. | ||
16 | * - Interrupt support (mic detect and sequencer). | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include <sound/tlv.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/initval.h> | ||
33 | |||
34 | #include "wm8903.h" | ||
35 | |||
36 | struct wm8903_priv { | ||
37 | int sysclk; | ||
38 | |||
39 | /* Reference counts */ | ||
40 | int charge_pump_users; | ||
41 | int class_w_users; | ||
42 | int playback_active; | ||
43 | int capture_active; | ||
44 | |||
45 | struct snd_pcm_substream *master_substream; | ||
46 | struct snd_pcm_substream *slave_substream; | ||
47 | }; | ||
48 | |||
49 | /* Register defaults at reset */ | ||
50 | static u16 wm8903_reg_defaults[] = { | ||
51 | 0x8903, /* R0 - SW Reset and ID */ | ||
52 | 0x0000, /* R1 - Revision Number */ | ||
53 | 0x0000, /* R2 */ | ||
54 | 0x0000, /* R3 */ | ||
55 | 0x0018, /* R4 - Bias Control 0 */ | ||
56 | 0x0000, /* R5 - VMID Control 0 */ | ||
57 | 0x0000, /* R6 - Mic Bias Control 0 */ | ||
58 | 0x0000, /* R7 */ | ||
59 | 0x0001, /* R8 - Analogue DAC 0 */ | ||
60 | 0x0000, /* R9 */ | ||
61 | 0x0001, /* R10 - Analogue ADC 0 */ | ||
62 | 0x0000, /* R11 */ | ||
63 | 0x0000, /* R12 - Power Management 0 */ | ||
64 | 0x0000, /* R13 - Power Management 1 */ | ||
65 | 0x0000, /* R14 - Power Management 2 */ | ||
66 | 0x0000, /* R15 - Power Management 3 */ | ||
67 | 0x0000, /* R16 - Power Management 4 */ | ||
68 | 0x0000, /* R17 - Power Management 5 */ | ||
69 | 0x0000, /* R18 - Power Management 6 */ | ||
70 | 0x0000, /* R19 */ | ||
71 | 0x0400, /* R20 - Clock Rates 0 */ | ||
72 | 0x0D07, /* R21 - Clock Rates 1 */ | ||
73 | 0x0000, /* R22 - Clock Rates 2 */ | ||
74 | 0x0000, /* R23 */ | ||
75 | 0x0050, /* R24 - Audio Interface 0 */ | ||
76 | 0x0242, /* R25 - Audio Interface 1 */ | ||
77 | 0x0008, /* R26 - Audio Interface 2 */ | ||
78 | 0x0022, /* R27 - Audio Interface 3 */ | ||
79 | 0x0000, /* R28 */ | ||
80 | 0x0000, /* R29 */ | ||
81 | 0x00C0, /* R30 - DAC Digital Volume Left */ | ||
82 | 0x00C0, /* R31 - DAC Digital Volume Right */ | ||
83 | 0x0000, /* R32 - DAC Digital 0 */ | ||
84 | 0x0000, /* R33 - DAC Digital 1 */ | ||
85 | 0x0000, /* R34 */ | ||
86 | 0x0000, /* R35 */ | ||
87 | 0x00C0, /* R36 - ADC Digital Volume Left */ | ||
88 | 0x00C0, /* R37 - ADC Digital Volume Right */ | ||
89 | 0x0000, /* R38 - ADC Digital 0 */ | ||
90 | 0x0073, /* R39 - Digital Microphone 0 */ | ||
91 | 0x09BF, /* R40 - DRC 0 */ | ||
92 | 0x3241, /* R41 - DRC 1 */ | ||
93 | 0x0020, /* R42 - DRC 2 */ | ||
94 | 0x0000, /* R43 - DRC 3 */ | ||
95 | 0x0085, /* R44 - Analogue Left Input 0 */ | ||
96 | 0x0085, /* R45 - Analogue Right Input 0 */ | ||
97 | 0x0044, /* R46 - Analogue Left Input 1 */ | ||
98 | 0x0044, /* R47 - Analogue Right Input 1 */ | ||
99 | 0x0000, /* R48 */ | ||
100 | 0x0000, /* R49 */ | ||
101 | 0x0008, /* R50 - Analogue Left Mix 0 */ | ||
102 | 0x0004, /* R51 - Analogue Right Mix 0 */ | ||
103 | 0x0000, /* R52 - Analogue Spk Mix Left 0 */ | ||
104 | 0x0000, /* R53 - Analogue Spk Mix Left 1 */ | ||
105 | 0x0000, /* R54 - Analogue Spk Mix Right 0 */ | ||
106 | 0x0000, /* R55 - Analogue Spk Mix Right 1 */ | ||
107 | 0x0000, /* R56 */ | ||
108 | 0x002D, /* R57 - Analogue OUT1 Left */ | ||
109 | 0x002D, /* R58 - Analogue OUT1 Right */ | ||
110 | 0x0039, /* R59 - Analogue OUT2 Left */ | ||
111 | 0x0039, /* R60 - Analogue OUT2 Right */ | ||
112 | 0x0100, /* R61 */ | ||
113 | 0x0139, /* R62 - Analogue OUT3 Left */ | ||
114 | 0x0139, /* R63 - Analogue OUT3 Right */ | ||
115 | 0x0000, /* R64 */ | ||
116 | 0x0000, /* R65 - Analogue SPK Output Control 0 */ | ||
117 | 0x0000, /* R66 */ | ||
118 | 0x0010, /* R67 - DC Servo 0 */ | ||
119 | 0x0100, /* R68 */ | ||
120 | 0x00A4, /* R69 - DC Servo 2 */ | ||
121 | 0x0807, /* R70 */ | ||
122 | 0x0000, /* R71 */ | ||
123 | 0x0000, /* R72 */ | ||
124 | 0x0000, /* R73 */ | ||
125 | 0x0000, /* R74 */ | ||
126 | 0x0000, /* R75 */ | ||
127 | 0x0000, /* R76 */ | ||
128 | 0x0000, /* R77 */ | ||
129 | 0x0000, /* R78 */ | ||
130 | 0x000E, /* R79 */ | ||
131 | 0x0000, /* R80 */ | ||
132 | 0x0000, /* R81 */ | ||
133 | 0x0000, /* R82 */ | ||
134 | 0x0000, /* R83 */ | ||
135 | 0x0000, /* R84 */ | ||
136 | 0x0000, /* R85 */ | ||
137 | 0x0000, /* R86 */ | ||
138 | 0x0006, /* R87 */ | ||
139 | 0x0000, /* R88 */ | ||
140 | 0x0000, /* R89 */ | ||
141 | 0x0000, /* R90 - Analogue HP 0 */ | ||
142 | 0x0060, /* R91 */ | ||
143 | 0x0000, /* R92 */ | ||
144 | 0x0000, /* R93 */ | ||
145 | 0x0000, /* R94 - Analogue Lineout 0 */ | ||
146 | 0x0060, /* R95 */ | ||
147 | 0x0000, /* R96 */ | ||
148 | 0x0000, /* R97 */ | ||
149 | 0x0000, /* R98 - Charge Pump 0 */ | ||
150 | 0x1F25, /* R99 */ | ||
151 | 0x2B19, /* R100 */ | ||
152 | 0x01C0, /* R101 */ | ||
153 | 0x01EF, /* R102 */ | ||
154 | 0x2B00, /* R103 */ | ||
155 | 0x0000, /* R104 - Class W 0 */ | ||
156 | 0x01C0, /* R105 */ | ||
157 | 0x1C10, /* R106 */ | ||
158 | 0x0000, /* R107 */ | ||
159 | 0x0000, /* R108 - Write Sequencer 0 */ | ||
160 | 0x0000, /* R109 - Write Sequencer 1 */ | ||
161 | 0x0000, /* R110 - Write Sequencer 2 */ | ||
162 | 0x0000, /* R111 - Write Sequencer 3 */ | ||
163 | 0x0000, /* R112 - Write Sequencer 4 */ | ||
164 | 0x0000, /* R113 */ | ||
165 | 0x0000, /* R114 - Control Interface */ | ||
166 | 0x0000, /* R115 */ | ||
167 | 0x00A8, /* R116 - GPIO Control 1 */ | ||
168 | 0x00A8, /* R117 - GPIO Control 2 */ | ||
169 | 0x00A8, /* R118 - GPIO Control 3 */ | ||
170 | 0x0220, /* R119 - GPIO Control 4 */ | ||
171 | 0x01A0, /* R120 - GPIO Control 5 */ | ||
172 | 0x0000, /* R121 - Interrupt Status 1 */ | ||
173 | 0xFFFF, /* R122 - Interrupt Status 1 Mask */ | ||
174 | 0x0000, /* R123 - Interrupt Polarity 1 */ | ||
175 | 0x0000, /* R124 */ | ||
176 | 0x0003, /* R125 */ | ||
177 | 0x0000, /* R126 - Interrupt Control */ | ||
178 | 0x0000, /* R127 */ | ||
179 | 0x0005, /* R128 */ | ||
180 | 0x0000, /* R129 - Control Interface Test 1 */ | ||
181 | 0x0000, /* R130 */ | ||
182 | 0x0000, /* R131 */ | ||
183 | 0x0000, /* R132 */ | ||
184 | 0x0000, /* R133 */ | ||
185 | 0x0000, /* R134 */ | ||
186 | 0x03FF, /* R135 */ | ||
187 | 0x0007, /* R136 */ | ||
188 | 0x0040, /* R137 */ | ||
189 | 0x0000, /* R138 */ | ||
190 | 0x0000, /* R139 */ | ||
191 | 0x0000, /* R140 */ | ||
192 | 0x0000, /* R141 */ | ||
193 | 0x0000, /* R142 */ | ||
194 | 0x0000, /* R143 */ | ||
195 | 0x0000, /* R144 */ | ||
196 | 0x0000, /* R145 */ | ||
197 | 0x0000, /* R146 */ | ||
198 | 0x0000, /* R147 */ | ||
199 | 0x4000, /* R148 */ | ||
200 | 0x6810, /* R149 - Charge Pump Test 1 */ | ||
201 | 0x0004, /* R150 */ | ||
202 | 0x0000, /* R151 */ | ||
203 | 0x0000, /* R152 */ | ||
204 | 0x0000, /* R153 */ | ||
205 | 0x0000, /* R154 */ | ||
206 | 0x0000, /* R155 */ | ||
207 | 0x0000, /* R156 */ | ||
208 | 0x0000, /* R157 */ | ||
209 | 0x0000, /* R158 */ | ||
210 | 0x0000, /* R159 */ | ||
211 | 0x0000, /* R160 */ | ||
212 | 0x0000, /* R161 */ | ||
213 | 0x0000, /* R162 */ | ||
214 | 0x0000, /* R163 */ | ||
215 | 0x0028, /* R164 - Clock Rate Test 4 */ | ||
216 | 0x0004, /* R165 */ | ||
217 | 0x0000, /* R166 */ | ||
218 | 0x0060, /* R167 */ | ||
219 | 0x0000, /* R168 */ | ||
220 | 0x0000, /* R169 */ | ||
221 | 0x0000, /* R170 */ | ||
222 | 0x0000, /* R171 */ | ||
223 | 0x0000, /* R172 - Analogue Output Bias 0 */ | ||
224 | }; | ||
225 | |||
226 | static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, | ||
227 | unsigned int reg) | ||
228 | { | ||
229 | u16 *cache = codec->reg_cache; | ||
230 | |||
231 | BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); | ||
232 | |||
233 | return cache[reg]; | ||
234 | } | ||
235 | |||
236 | static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg) | ||
237 | { | ||
238 | struct i2c_msg xfer[2]; | ||
239 | u16 data; | ||
240 | int ret; | ||
241 | struct i2c_client *client = codec->control_data; | ||
242 | |||
243 | /* Write register */ | ||
244 | xfer[0].addr = client->addr; | ||
245 | xfer[0].flags = 0; | ||
246 | xfer[0].len = 1; | ||
247 | xfer[0].buf = ® | ||
248 | |||
249 | /* Read data */ | ||
250 | xfer[1].addr = client->addr; | ||
251 | xfer[1].flags = I2C_M_RD; | ||
252 | xfer[1].len = 2; | ||
253 | xfer[1].buf = (u8 *)&data; | ||
254 | |||
255 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
256 | if (ret != 2) { | ||
257 | pr_err("i2c_transfer returned %d\n", ret); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | return (data >> 8) | ((data & 0xff) << 8); | ||
262 | } | ||
263 | |||
264 | static unsigned int wm8903_read(struct snd_soc_codec *codec, | ||
265 | unsigned int reg) | ||
266 | { | ||
267 | switch (reg) { | ||
268 | case WM8903_SW_RESET_AND_ID: | ||
269 | case WM8903_REVISION_NUMBER: | ||
270 | case WM8903_INTERRUPT_STATUS_1: | ||
271 | case WM8903_WRITE_SEQUENCER_4: | ||
272 | return wm8903_hw_read(codec, reg); | ||
273 | |||
274 | default: | ||
275 | return wm8903_read_reg_cache(codec, reg); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | static void wm8903_write_reg_cache(struct snd_soc_codec *codec, | ||
280 | u16 reg, unsigned int value) | ||
281 | { | ||
282 | u16 *cache = codec->reg_cache; | ||
283 | |||
284 | BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); | ||
285 | |||
286 | switch (reg) { | ||
287 | case WM8903_SW_RESET_AND_ID: | ||
288 | case WM8903_REVISION_NUMBER: | ||
289 | break; | ||
290 | |||
291 | default: | ||
292 | cache[reg] = value; | ||
293 | break; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg, | ||
298 | unsigned int value) | ||
299 | { | ||
300 | u8 data[3]; | ||
301 | |||
302 | wm8903_write_reg_cache(codec, reg, value); | ||
303 | |||
304 | /* Data format is 1 byte of address followed by 2 bytes of data */ | ||
305 | data[0] = reg; | ||
306 | data[1] = (value >> 8) & 0xff; | ||
307 | data[2] = value & 0xff; | ||
308 | |||
309 | if (codec->hw_write(codec->control_data, data, 3) == 2) | ||
310 | return 0; | ||
311 | else | ||
312 | return -EIO; | ||
313 | } | ||
314 | |||
315 | static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) | ||
316 | { | ||
317 | u16 reg[5]; | ||
318 | struct i2c_client *i2c = codec->control_data; | ||
319 | |||
320 | BUG_ON(start > 48); | ||
321 | |||
322 | /* Enable the sequencer */ | ||
323 | reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0); | ||
324 | reg[0] |= WM8903_WSEQ_ENA; | ||
325 | wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); | ||
326 | |||
327 | dev_dbg(&i2c->dev, "Starting sequence at %d\n", start); | ||
328 | |||
329 | wm8903_write(codec, WM8903_WRITE_SEQUENCER_3, | ||
330 | start | WM8903_WSEQ_START); | ||
331 | |||
332 | /* Wait for it to complete. If we have the interrupt wired up then | ||
333 | * we could block waiting for an interrupt, though polling may still | ||
334 | * be desirable for diagnostic purposes. | ||
335 | */ | ||
336 | do { | ||
337 | msleep(10); | ||
338 | |||
339 | reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4); | ||
340 | } while (reg[4] & WM8903_WSEQ_BUSY); | ||
341 | |||
342 | dev_dbg(&i2c->dev, "Sequence complete\n"); | ||
343 | |||
344 | /* Disable the sequencer again */ | ||
345 | wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, | ||
346 | reg[0] & ~WM8903_WSEQ_ENA); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) | ||
352 | { | ||
353 | int i; | ||
354 | |||
355 | /* There really ought to be something better we can do here :/ */ | ||
356 | for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++) | ||
357 | cache[i] = wm8903_hw_read(codec, i); | ||
358 | } | ||
359 | |||
360 | static void wm8903_reset(struct snd_soc_codec *codec) | ||
361 | { | ||
362 | wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); | ||
363 | } | ||
364 | |||
365 | #define WM8903_OUTPUT_SHORT 0x8 | ||
366 | #define WM8903_OUTPUT_OUT 0x4 | ||
367 | #define WM8903_OUTPUT_INT 0x2 | ||
368 | #define WM8903_OUTPUT_IN 0x1 | ||
369 | |||
370 | /* | ||
371 | * Event for headphone and line out amplifier power changes. Special | ||
372 | * power up/down sequences are required in order to maximise pop/click | ||
373 | * performance. | ||
374 | */ | ||
375 | static int wm8903_output_event(struct snd_soc_dapm_widget *w, | ||
376 | struct snd_kcontrol *kcontrol, int event) | ||
377 | { | ||
378 | struct snd_soc_codec *codec = w->codec; | ||
379 | struct wm8903_priv *wm8903 = codec->private_data; | ||
380 | struct i2c_client *i2c = codec->control_data; | ||
381 | u16 val; | ||
382 | u16 reg; | ||
383 | int shift; | ||
384 | u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); | ||
385 | |||
386 | switch (w->reg) { | ||
387 | case WM8903_POWER_MANAGEMENT_2: | ||
388 | reg = WM8903_ANALOGUE_HP_0; | ||
389 | break; | ||
390 | case WM8903_POWER_MANAGEMENT_3: | ||
391 | reg = WM8903_ANALOGUE_LINEOUT_0; | ||
392 | break; | ||
393 | default: | ||
394 | BUG(); | ||
395 | } | ||
396 | |||
397 | switch (w->shift) { | ||
398 | case 0: | ||
399 | shift = 0; | ||
400 | break; | ||
401 | case 1: | ||
402 | shift = 4; | ||
403 | break; | ||
404 | default: | ||
405 | BUG(); | ||
406 | } | ||
407 | |||
408 | if (event & SND_SOC_DAPM_PRE_PMU) { | ||
409 | val = wm8903_read(codec, reg); | ||
410 | |||
411 | /* Short the output */ | ||
412 | val &= ~(WM8903_OUTPUT_SHORT << shift); | ||
413 | wm8903_write(codec, reg, val); | ||
414 | |||
415 | wm8903->charge_pump_users++; | ||
416 | |||
417 | dev_dbg(&i2c->dev, "Charge pump use count now %d\n", | ||
418 | wm8903->charge_pump_users); | ||
419 | |||
420 | if (wm8903->charge_pump_users == 1) { | ||
421 | dev_dbg(&i2c->dev, "Enabling charge pump\n"); | ||
422 | wm8903_write(codec, WM8903_CHARGE_PUMP_0, | ||
423 | cp_reg | WM8903_CP_ENA); | ||
424 | mdelay(4); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | if (event & SND_SOC_DAPM_POST_PMU) { | ||
429 | val = wm8903_read(codec, reg); | ||
430 | |||
431 | val |= (WM8903_OUTPUT_IN << shift); | ||
432 | wm8903_write(codec, reg, val); | ||
433 | |||
434 | val |= (WM8903_OUTPUT_INT << shift); | ||
435 | wm8903_write(codec, reg, val); | ||
436 | |||
437 | /* Turn on the output ENA_OUTP */ | ||
438 | val |= (WM8903_OUTPUT_OUT << shift); | ||
439 | wm8903_write(codec, reg, val); | ||
440 | |||
441 | /* Remove the short */ | ||
442 | val |= (WM8903_OUTPUT_SHORT << shift); | ||
443 | wm8903_write(codec, reg, val); | ||
444 | } | ||
445 | |||
446 | if (event & SND_SOC_DAPM_PRE_PMD) { | ||
447 | val = wm8903_read(codec, reg); | ||
448 | |||
449 | /* Short the output */ | ||
450 | val &= ~(WM8903_OUTPUT_SHORT << shift); | ||
451 | wm8903_write(codec, reg, val); | ||
452 | |||
453 | /* Then disable the intermediate and output stages */ | ||
454 | val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | | ||
455 | WM8903_OUTPUT_IN) << shift); | ||
456 | wm8903_write(codec, reg, val); | ||
457 | } | ||
458 | |||
459 | if (event & SND_SOC_DAPM_POST_PMD) { | ||
460 | wm8903->charge_pump_users--; | ||
461 | |||
462 | dev_dbg(&i2c->dev, "Charge pump use count now %d\n", | ||
463 | wm8903->charge_pump_users); | ||
464 | |||
465 | if (wm8903->charge_pump_users == 0) { | ||
466 | dev_dbg(&i2c->dev, "Disabling charge pump\n"); | ||
467 | wm8903_write(codec, WM8903_CHARGE_PUMP_0, | ||
468 | cp_reg & ~WM8903_CP_ENA); | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * When used with DAC outputs only the WM8903 charge pump supports | ||
477 | * operation in class W mode, providing very low power consumption | ||
478 | * when used with digital sources. Enable and disable this mode | ||
479 | * automatically depending on the mixer configuration. | ||
480 | * | ||
481 | * All the relevant controls are simple switches. | ||
482 | */ | ||
483 | static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, | ||
484 | struct snd_ctl_elem_value *ucontrol) | ||
485 | { | ||
486 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
487 | struct snd_soc_codec *codec = widget->codec; | ||
488 | struct wm8903_priv *wm8903 = codec->private_data; | ||
489 | struct i2c_client *i2c = codec->control_data; | ||
490 | u16 reg; | ||
491 | int ret; | ||
492 | |||
493 | reg = wm8903_read(codec, WM8903_CLASS_W_0); | ||
494 | |||
495 | /* Turn it off if we're about to enable bypass */ | ||
496 | if (ucontrol->value.integer.value[0]) { | ||
497 | if (wm8903->class_w_users == 0) { | ||
498 | dev_dbg(&i2c->dev, "Disabling Class W\n"); | ||
499 | wm8903_write(codec, WM8903_CLASS_W_0, reg & | ||
500 | ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V)); | ||
501 | } | ||
502 | wm8903->class_w_users++; | ||
503 | } | ||
504 | |||
505 | /* Implement the change */ | ||
506 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | ||
507 | |||
508 | /* If we've just disabled the last bypass path turn Class W on */ | ||
509 | if (!ucontrol->value.integer.value[0]) { | ||
510 | if (wm8903->class_w_users == 1) { | ||
511 | dev_dbg(&i2c->dev, "Enabling Class W\n"); | ||
512 | wm8903_write(codec, WM8903_CLASS_W_0, reg | | ||
513 | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); | ||
514 | } | ||
515 | wm8903->class_w_users--; | ||
516 | } | ||
517 | |||
518 | dev_dbg(&i2c->dev, "Bypass use count now %d\n", | ||
519 | wm8903->class_w_users); | ||
520 | |||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | #define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \ | ||
525 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
526 | .info = snd_soc_info_volsw, \ | ||
527 | .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \ | ||
528 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
529 | |||
530 | |||
531 | /* ALSA can only do steps of .01dB */ | ||
532 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | ||
533 | |||
534 | static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); | ||
535 | |||
536 | static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0); | ||
537 | static const DECLARE_TLV_DB_SCALE(drc_tlv_amp, -2250, 75, 0); | ||
538 | static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0); | ||
539 | static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0); | ||
540 | static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0); | ||
541 | |||
542 | static const char *drc_slope_text[] = { | ||
543 | "1", "1/2", "1/4", "1/8", "1/16", "0" | ||
544 | }; | ||
545 | |||
546 | static const struct soc_enum drc_slope_r0 = | ||
547 | SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text); | ||
548 | |||
549 | static const struct soc_enum drc_slope_r1 = | ||
550 | SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text); | ||
551 | |||
552 | static const char *drc_attack_text[] = { | ||
553 | "instantaneous", | ||
554 | "363us", "762us", "1.45ms", "2.9ms", "5.8ms", "11.6ms", "23.2ms", | ||
555 | "46.4ms", "92.8ms", "185.6ms" | ||
556 | }; | ||
557 | |||
558 | static const struct soc_enum drc_attack = | ||
559 | SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text); | ||
560 | |||
561 | static const char *drc_decay_text[] = { | ||
562 | "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s", | ||
563 | "23.87s", "47.56s" | ||
564 | }; | ||
565 | |||
566 | static const struct soc_enum drc_decay = | ||
567 | SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text); | ||
568 | |||
569 | static const char *drc_ff_delay_text[] = { | ||
570 | "5 samples", "9 samples" | ||
571 | }; | ||
572 | |||
573 | static const struct soc_enum drc_ff_delay = | ||
574 | SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text); | ||
575 | |||
576 | static const char *drc_qr_decay_text[] = { | ||
577 | "0.725ms", "1.45ms", "5.8ms" | ||
578 | }; | ||
579 | |||
580 | static const struct soc_enum drc_qr_decay = | ||
581 | SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text); | ||
582 | |||
583 | static const char *drc_smoothing_text[] = { | ||
584 | "Low", "Medium", "High" | ||
585 | }; | ||
586 | |||
587 | static const struct soc_enum drc_smoothing = | ||
588 | SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text); | ||
589 | |||
590 | static const char *soft_mute_text[] = { | ||
591 | "Fast (fs/2)", "Slow (fs/32)" | ||
592 | }; | ||
593 | |||
594 | static const struct soc_enum soft_mute = | ||
595 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text); | ||
596 | |||
597 | static const char *mute_mode_text[] = { | ||
598 | "Hard", "Soft" | ||
599 | }; | ||
600 | |||
601 | static const struct soc_enum mute_mode = | ||
602 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text); | ||
603 | |||
604 | static const char *dac_deemphasis_text[] = { | ||
605 | "Disabled", "32kHz", "44.1kHz", "48kHz" | ||
606 | }; | ||
607 | |||
608 | static const struct soc_enum dac_deemphasis = | ||
609 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text); | ||
610 | |||
611 | static const char *companding_text[] = { | ||
612 | "ulaw", "alaw" | ||
613 | }; | ||
614 | |||
615 | static const struct soc_enum dac_companding = | ||
616 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text); | ||
617 | |||
618 | static const struct soc_enum adc_companding = | ||
619 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text); | ||
620 | |||
621 | static const char *input_mode_text[] = { | ||
622 | "Single-Ended", "Differential Line", "Differential Mic" | ||
623 | }; | ||
624 | |||
625 | static const struct soc_enum linput_mode_enum = | ||
626 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); | ||
627 | |||
628 | static const struct soc_enum rinput_mode_enum = | ||
629 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); | ||
630 | |||
631 | static const char *linput_mux_text[] = { | ||
632 | "IN1L", "IN2L", "IN3L" | ||
633 | }; | ||
634 | |||
635 | static const struct soc_enum linput_enum = | ||
636 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text); | ||
637 | |||
638 | static const struct soc_enum linput_inv_enum = | ||
639 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text); | ||
640 | |||
641 | static const char *rinput_mux_text[] = { | ||
642 | "IN1R", "IN2R", "IN3R" | ||
643 | }; | ||
644 | |||
645 | static const struct soc_enum rinput_enum = | ||
646 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text); | ||
647 | |||
648 | static const struct soc_enum rinput_inv_enum = | ||
649 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); | ||
650 | |||
651 | |||
652 | static const struct snd_kcontrol_new wm8903_snd_controls[] = { | ||
653 | |||
654 | /* Input PGAs - No TLV since the scale depends on PGA mode */ | ||
655 | SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0, | ||
656 | 7, 1, 0), | ||
657 | SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0, | ||
658 | 0, 31, 0), | ||
659 | SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1, | ||
660 | 6, 1, 0), | ||
661 | |||
662 | SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0, | ||
663 | 7, 1, 0), | ||
664 | SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0, | ||
665 | 0, 31, 0), | ||
666 | SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1, | ||
667 | 6, 1, 0), | ||
668 | |||
669 | /* ADCs */ | ||
670 | SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0), | ||
671 | SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0), | ||
672 | SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1), | ||
673 | SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1, | ||
674 | drc_tlv_thresh), | ||
675 | SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp), | ||
676 | SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min), | ||
677 | SOC_SINGLE_TLV("DRC Maximum Gain Volume", WM8903_DRC_1, 0, 3, 0, drc_tlv_max), | ||
678 | SOC_ENUM("DRC Attack Rate", drc_attack), | ||
679 | SOC_ENUM("DRC Decay Rate", drc_decay), | ||
680 | SOC_ENUM("DRC FF Delay", drc_ff_delay), | ||
681 | SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0), | ||
682 | SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0), | ||
683 | SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), | ||
684 | SOC_ENUM("DRC QR Decay Rate", drc_qr_decay), | ||
685 | SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0), | ||
686 | SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0), | ||
687 | SOC_ENUM("DRC Smoothing Threashold", drc_smoothing), | ||
688 | SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup), | ||
689 | |||
690 | SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, | ||
691 | WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), | ||
692 | SOC_ENUM("ADC Companding Mode", adc_companding), | ||
693 | SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), | ||
694 | |||
695 | /* DAC */ | ||
696 | SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT, | ||
697 | WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), | ||
698 | SOC_ENUM("DAC Soft Mute Rate", soft_mute), | ||
699 | SOC_ENUM("DAC Mute Mode", mute_mode), | ||
700 | SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), | ||
701 | SOC_ENUM("DAC De-emphasis", dac_deemphasis), | ||
702 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", | ||
703 | WM8903_DAC_DIGITAL_1, 11, 1, 0), | ||
704 | SOC_ENUM("DAC Companding Mode", dac_companding), | ||
705 | SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), | ||
706 | |||
707 | /* Headphones */ | ||
708 | SOC_DOUBLE_R("Headphone Switch", | ||
709 | WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT, | ||
710 | 8, 1, 1), | ||
711 | SOC_DOUBLE_R("Headphone ZC Switch", | ||
712 | WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT, | ||
713 | 6, 1, 0), | ||
714 | SOC_DOUBLE_R_TLV("Headphone Volume", | ||
715 | WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT, | ||
716 | 0, 63, 0, out_tlv), | ||
717 | |||
718 | /* Line out */ | ||
719 | SOC_DOUBLE_R("Line Out Switch", | ||
720 | WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT, | ||
721 | 8, 1, 1), | ||
722 | SOC_DOUBLE_R("Line Out ZC Switch", | ||
723 | WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT, | ||
724 | 6, 1, 0), | ||
725 | SOC_DOUBLE_R_TLV("Line Out Volume", | ||
726 | WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT, | ||
727 | 0, 63, 0, out_tlv), | ||
728 | |||
729 | /* Speaker */ | ||
730 | SOC_DOUBLE_R("Speaker Switch", | ||
731 | WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 8, 1, 1), | ||
732 | SOC_DOUBLE_R("Speaker ZC Switch", | ||
733 | WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 6, 1, 0), | ||
734 | SOC_DOUBLE_R_TLV("Speaker Volume", | ||
735 | WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, | ||
736 | 0, 63, 0, out_tlv), | ||
737 | }; | ||
738 | |||
739 | static int wm8903_add_controls(struct snd_soc_codec *codec) | ||
740 | { | ||
741 | int err, i; | ||
742 | |||
743 | for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) { | ||
744 | err = snd_ctl_add(codec->card, | ||
745 | snd_soc_cnew(&wm8903_snd_controls[i], | ||
746 | codec, NULL)); | ||
747 | if (err < 0) | ||
748 | return err; | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | static const struct snd_kcontrol_new linput_mode_mux = | ||
755 | SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum); | ||
756 | |||
757 | static const struct snd_kcontrol_new rinput_mode_mux = | ||
758 | SOC_DAPM_ENUM("Right Input Mode Mux", rinput_mode_enum); | ||
759 | |||
760 | static const struct snd_kcontrol_new linput_mux = | ||
761 | SOC_DAPM_ENUM("Left Input Mux", linput_enum); | ||
762 | |||
763 | static const struct snd_kcontrol_new linput_inv_mux = | ||
764 | SOC_DAPM_ENUM("Left Inverting Input Mux", linput_inv_enum); | ||
765 | |||
766 | static const struct snd_kcontrol_new rinput_mux = | ||
767 | SOC_DAPM_ENUM("Right Input Mux", rinput_enum); | ||
768 | |||
769 | static const struct snd_kcontrol_new rinput_inv_mux = | ||
770 | SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum); | ||
771 | |||
772 | static const struct snd_kcontrol_new left_output_mixer[] = { | ||
773 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), | ||
774 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), | ||
775 | SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), | ||
776 | SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), | ||
777 | }; | ||
778 | |||
779 | static const struct snd_kcontrol_new right_output_mixer[] = { | ||
780 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0), | ||
781 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0), | ||
782 | SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), | ||
783 | SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), | ||
784 | }; | ||
785 | |||
786 | static const struct snd_kcontrol_new left_speaker_mixer[] = { | ||
787 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0), | ||
788 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0), | ||
789 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0), | ||
790 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, | ||
791 | 1, 1, 0), | ||
792 | }; | ||
793 | |||
794 | static const struct snd_kcontrol_new right_speaker_mixer[] = { | ||
795 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 3, 1, 0), | ||
796 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0), | ||
797 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, | ||
798 | 1, 1, 0), | ||
799 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, | ||
800 | 1, 1, 0), | ||
801 | }; | ||
802 | |||
803 | static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { | ||
804 | SND_SOC_DAPM_INPUT("IN1L"), | ||
805 | SND_SOC_DAPM_INPUT("IN1R"), | ||
806 | SND_SOC_DAPM_INPUT("IN2L"), | ||
807 | SND_SOC_DAPM_INPUT("IN2R"), | ||
808 | SND_SOC_DAPM_INPUT("IN3L"), | ||
809 | SND_SOC_DAPM_INPUT("IN3R"), | ||
810 | |||
811 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
812 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
813 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
814 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
815 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
816 | SND_SOC_DAPM_OUTPUT("LON"), | ||
817 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
818 | SND_SOC_DAPM_OUTPUT("RON"), | ||
819 | |||
820 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8903_MIC_BIAS_CONTROL_0, 0, 0), | ||
821 | |||
822 | SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux), | ||
823 | SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0, | ||
824 | &linput_inv_mux), | ||
825 | SND_SOC_DAPM_MUX("Left Input Mode Mux", SND_SOC_NOPM, 0, 0, &linput_mode_mux), | ||
826 | |||
827 | SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &rinput_mux), | ||
828 | SND_SOC_DAPM_MUX("Right Input Inverting Mux", SND_SOC_NOPM, 0, 0, | ||
829 | &rinput_inv_mux), | ||
830 | SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux), | ||
831 | |||
832 | SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0), | ||
833 | SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), | ||
834 | |||
835 | SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0), | ||
836 | SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0), | ||
837 | |||
838 | SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0), | ||
839 | SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0), | ||
840 | |||
841 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0, | ||
842 | left_output_mixer, ARRAY_SIZE(left_output_mixer)), | ||
843 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8903_POWER_MANAGEMENT_1, 0, 0, | ||
844 | right_output_mixer, ARRAY_SIZE(right_output_mixer)), | ||
845 | |||
846 | SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0, | ||
847 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
848 | SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, | ||
849 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
850 | |||
851 | SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, | ||
852 | 1, 0, NULL, 0, wm8903_output_event, | ||
853 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
854 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
855 | SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, | ||
856 | 0, 0, NULL, 0, wm8903_output_event, | ||
857 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
858 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
859 | |||
860 | SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0, | ||
861 | NULL, 0, wm8903_output_event, | ||
862 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
863 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
864 | SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0, | ||
865 | NULL, 0, wm8903_output_event, | ||
866 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
867 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
868 | |||
869 | SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, | ||
870 | NULL, 0), | ||
871 | SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0, | ||
872 | NULL, 0), | ||
873 | |||
874 | }; | ||
875 | |||
876 | static const struct snd_soc_dapm_route intercon[] = { | ||
877 | |||
878 | { "Left Input Mux", "IN1L", "IN1L" }, | ||
879 | { "Left Input Mux", "IN2L", "IN2L" }, | ||
880 | { "Left Input Mux", "IN3L", "IN3L" }, | ||
881 | |||
882 | { "Left Input Inverting Mux", "IN1L", "IN1L" }, | ||
883 | { "Left Input Inverting Mux", "IN2L", "IN2L" }, | ||
884 | { "Left Input Inverting Mux", "IN3L", "IN3L" }, | ||
885 | |||
886 | { "Right Input Mux", "IN1R", "IN1R" }, | ||
887 | { "Right Input Mux", "IN2R", "IN2R" }, | ||
888 | { "Right Input Mux", "IN3R", "IN3R" }, | ||
889 | |||
890 | { "Right Input Inverting Mux", "IN1R", "IN1R" }, | ||
891 | { "Right Input Inverting Mux", "IN2R", "IN2R" }, | ||
892 | { "Right Input Inverting Mux", "IN3R", "IN3R" }, | ||
893 | |||
894 | { "Left Input Mode Mux", "Single-Ended", "Left Input Inverting Mux" }, | ||
895 | { "Left Input Mode Mux", "Differential Line", | ||
896 | "Left Input Mux" }, | ||
897 | { "Left Input Mode Mux", "Differential Line", | ||
898 | "Left Input Inverting Mux" }, | ||
899 | { "Left Input Mode Mux", "Differential Mic", | ||
900 | "Left Input Mux" }, | ||
901 | { "Left Input Mode Mux", "Differential Mic", | ||
902 | "Left Input Inverting Mux" }, | ||
903 | |||
904 | { "Right Input Mode Mux", "Single-Ended", | ||
905 | "Right Input Inverting Mux" }, | ||
906 | { "Right Input Mode Mux", "Differential Line", | ||
907 | "Right Input Mux" }, | ||
908 | { "Right Input Mode Mux", "Differential Line", | ||
909 | "Right Input Inverting Mux" }, | ||
910 | { "Right Input Mode Mux", "Differential Mic", | ||
911 | "Right Input Mux" }, | ||
912 | { "Right Input Mode Mux", "Differential Mic", | ||
913 | "Right Input Inverting Mux" }, | ||
914 | |||
915 | { "Left Input PGA", NULL, "Left Input Mode Mux" }, | ||
916 | { "Right Input PGA", NULL, "Right Input Mode Mux" }, | ||
917 | |||
918 | { "ADCL", NULL, "Left Input PGA" }, | ||
919 | { "ADCR", NULL, "Right Input PGA" }, | ||
920 | |||
921 | { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
922 | { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
923 | { "Left Output Mixer", "DACL Switch", "DACL" }, | ||
924 | { "Left Output Mixer", "DACR Switch", "DACR" }, | ||
925 | |||
926 | { "Right Output Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
927 | { "Right Output Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
928 | { "Right Output Mixer", "DACL Switch", "DACL" }, | ||
929 | { "Right Output Mixer", "DACR Switch", "DACR" }, | ||
930 | |||
931 | { "Left Speaker Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
932 | { "Left Speaker Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
933 | { "Left Speaker Mixer", "DACL Switch", "DACL" }, | ||
934 | { "Left Speaker Mixer", "DACR Switch", "DACR" }, | ||
935 | |||
936 | { "Right Speaker Mixer", "Left Bypass Switch", "Left Input PGA" }, | ||
937 | { "Right Speaker Mixer", "Right Bypass Switch", "Right Input PGA" }, | ||
938 | { "Right Speaker Mixer", "DACL Switch", "DACL" }, | ||
939 | { "Right Speaker Mixer", "DACR Switch", "DACR" }, | ||
940 | |||
941 | { "Left Line Output PGA", NULL, "Left Output Mixer" }, | ||
942 | { "Right Line Output PGA", NULL, "Right Output Mixer" }, | ||
943 | |||
944 | { "Left Headphone Output PGA", NULL, "Left Output Mixer" }, | ||
945 | { "Right Headphone Output PGA", NULL, "Right Output Mixer" }, | ||
946 | |||
947 | { "Left Speaker PGA", NULL, "Left Speaker Mixer" }, | ||
948 | { "Right Speaker PGA", NULL, "Right Speaker Mixer" }, | ||
949 | |||
950 | { "HPOUTL", NULL, "Left Headphone Output PGA" }, | ||
951 | { "HPOUTR", NULL, "Right Headphone Output PGA" }, | ||
952 | |||
953 | { "LINEOUTL", NULL, "Left Line Output PGA" }, | ||
954 | { "LINEOUTR", NULL, "Right Line Output PGA" }, | ||
955 | |||
956 | { "LOP", NULL, "Left Speaker PGA" }, | ||
957 | { "LON", NULL, "Left Speaker PGA" }, | ||
958 | |||
959 | { "ROP", NULL, "Right Speaker PGA" }, | ||
960 | { "RON", NULL, "Right Speaker PGA" }, | ||
961 | }; | ||
962 | |||
963 | static int wm8903_add_widgets(struct snd_soc_codec *codec) | ||
964 | { | ||
965 | snd_soc_dapm_new_controls(codec, wm8903_dapm_widgets, | ||
966 | ARRAY_SIZE(wm8903_dapm_widgets)); | ||
967 | |||
968 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
969 | |||
970 | snd_soc_dapm_new_widgets(codec); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int wm8903_set_bias_level(struct snd_soc_codec *codec, | ||
976 | enum snd_soc_bias_level level) | ||
977 | { | ||
978 | struct i2c_client *i2c = codec->control_data; | ||
979 | u16 reg, reg2; | ||
980 | |||
981 | switch (level) { | ||
982 | case SND_SOC_BIAS_ON: | ||
983 | case SND_SOC_BIAS_PREPARE: | ||
984 | reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); | ||
985 | reg &= ~(WM8903_VMID_RES_MASK); | ||
986 | reg |= WM8903_VMID_RES_50K; | ||
987 | wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); | ||
988 | break; | ||
989 | |||
990 | case SND_SOC_BIAS_STANDBY: | ||
991 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
992 | wm8903_run_sequence(codec, 0); | ||
993 | wm8903_sync_reg_cache(codec, codec->reg_cache); | ||
994 | |||
995 | /* Enable low impedence charge pump output */ | ||
996 | reg = wm8903_read(codec, | ||
997 | WM8903_CONTROL_INTERFACE_TEST_1); | ||
998 | wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, | ||
999 | reg | WM8903_TEST_KEY); | ||
1000 | reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1); | ||
1001 | wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1, | ||
1002 | reg2 | WM8903_CP_SW_KELVIN_MODE_MASK); | ||
1003 | wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, | ||
1004 | reg); | ||
1005 | |||
1006 | /* By default no bypass paths are enabled so | ||
1007 | * enable Class W support. | ||
1008 | */ | ||
1009 | dev_dbg(&i2c->dev, "Enabling Class W\n"); | ||
1010 | wm8903_write(codec, WM8903_CLASS_W_0, reg | | ||
1011 | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); | ||
1012 | } | ||
1013 | |||
1014 | reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); | ||
1015 | reg &= ~(WM8903_VMID_RES_MASK); | ||
1016 | reg |= WM8903_VMID_RES_250K; | ||
1017 | wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); | ||
1018 | break; | ||
1019 | |||
1020 | case SND_SOC_BIAS_OFF: | ||
1021 | wm8903_run_sequence(codec, 32); | ||
1022 | break; | ||
1023 | } | ||
1024 | |||
1025 | codec->bias_level = level; | ||
1026 | |||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
1031 | int clk_id, unsigned int freq, int dir) | ||
1032 | { | ||
1033 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1034 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1035 | |||
1036 | wm8903->sysclk = freq; | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1042 | unsigned int fmt) | ||
1043 | { | ||
1044 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1045 | u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); | ||
1046 | |||
1047 | aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK | | ||
1048 | WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV); | ||
1049 | |||
1050 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1051 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1052 | break; | ||
1053 | case SND_SOC_DAIFMT_CBS_CFM: | ||
1054 | aif1 |= WM8903_LRCLK_DIR; | ||
1055 | break; | ||
1056 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1057 | aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR; | ||
1058 | break; | ||
1059 | case SND_SOC_DAIFMT_CBM_CFS: | ||
1060 | aif1 |= WM8903_BCLK_DIR; | ||
1061 | break; | ||
1062 | default: | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | |||
1066 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1067 | case SND_SOC_DAIFMT_DSP_A: | ||
1068 | aif1 |= 0x3; | ||
1069 | break; | ||
1070 | case SND_SOC_DAIFMT_DSP_B: | ||
1071 | aif1 |= 0x3 | WM8903_AIF_LRCLK_INV; | ||
1072 | break; | ||
1073 | case SND_SOC_DAIFMT_I2S: | ||
1074 | aif1 |= 0x2; | ||
1075 | break; | ||
1076 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1077 | aif1 |= 0x1; | ||
1078 | break; | ||
1079 | case SND_SOC_DAIFMT_LEFT_J: | ||
1080 | break; | ||
1081 | default: | ||
1082 | return -EINVAL; | ||
1083 | } | ||
1084 | |||
1085 | /* Clock inversion */ | ||
1086 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1087 | case SND_SOC_DAIFMT_DSP_A: | ||
1088 | case SND_SOC_DAIFMT_DSP_B: | ||
1089 | /* frame inversion not valid for DSP modes */ | ||
1090 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1091 | case SND_SOC_DAIFMT_NB_NF: | ||
1092 | break; | ||
1093 | case SND_SOC_DAIFMT_IB_NF: | ||
1094 | aif1 |= WM8903_AIF_BCLK_INV; | ||
1095 | break; | ||
1096 | default: | ||
1097 | return -EINVAL; | ||
1098 | } | ||
1099 | break; | ||
1100 | case SND_SOC_DAIFMT_I2S: | ||
1101 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1102 | case SND_SOC_DAIFMT_LEFT_J: | ||
1103 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1104 | case SND_SOC_DAIFMT_NB_NF: | ||
1105 | break; | ||
1106 | case SND_SOC_DAIFMT_IB_IF: | ||
1107 | aif1 |= WM8903_AIF_BCLK_INV | WM8903_AIF_LRCLK_INV; | ||
1108 | break; | ||
1109 | case SND_SOC_DAIFMT_IB_NF: | ||
1110 | aif1 |= WM8903_AIF_BCLK_INV; | ||
1111 | break; | ||
1112 | case SND_SOC_DAIFMT_NB_IF: | ||
1113 | aif1 |= WM8903_AIF_LRCLK_INV; | ||
1114 | break; | ||
1115 | default: | ||
1116 | return -EINVAL; | ||
1117 | } | ||
1118 | break; | ||
1119 | default: | ||
1120 | return -EINVAL; | ||
1121 | } | ||
1122 | |||
1123 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
1129 | { | ||
1130 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1131 | u16 reg; | ||
1132 | |||
1133 | reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1); | ||
1134 | |||
1135 | if (mute) | ||
1136 | reg |= WM8903_DAC_MUTE; | ||
1137 | else | ||
1138 | reg &= ~WM8903_DAC_MUTE; | ||
1139 | |||
1140 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg); | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | /* Lookup table for CLK_SYS/fs ratio. 256fs or more is recommended | ||
1146 | * for optimal performance so we list the lower rates first and match | ||
1147 | * on the last match we find. */ | ||
1148 | static struct { | ||
1149 | int div; | ||
1150 | int rate; | ||
1151 | int mode; | ||
1152 | int mclk_div; | ||
1153 | } clk_sys_ratios[] = { | ||
1154 | { 64, 0x0, 0x0, 1 }, | ||
1155 | { 68, 0x0, 0x1, 1 }, | ||
1156 | { 125, 0x0, 0x2, 1 }, | ||
1157 | { 128, 0x1, 0x0, 1 }, | ||
1158 | { 136, 0x1, 0x1, 1 }, | ||
1159 | { 192, 0x2, 0x0, 1 }, | ||
1160 | { 204, 0x2, 0x1, 1 }, | ||
1161 | |||
1162 | { 64, 0x0, 0x0, 2 }, | ||
1163 | { 68, 0x0, 0x1, 2 }, | ||
1164 | { 125, 0x0, 0x2, 2 }, | ||
1165 | { 128, 0x1, 0x0, 2 }, | ||
1166 | { 136, 0x1, 0x1, 2 }, | ||
1167 | { 192, 0x2, 0x0, 2 }, | ||
1168 | { 204, 0x2, 0x1, 2 }, | ||
1169 | |||
1170 | { 250, 0x2, 0x2, 1 }, | ||
1171 | { 256, 0x3, 0x0, 1 }, | ||
1172 | { 272, 0x3, 0x1, 1 }, | ||
1173 | { 384, 0x4, 0x0, 1 }, | ||
1174 | { 408, 0x4, 0x1, 1 }, | ||
1175 | { 375, 0x4, 0x2, 1 }, | ||
1176 | { 512, 0x5, 0x0, 1 }, | ||
1177 | { 544, 0x5, 0x1, 1 }, | ||
1178 | { 500, 0x5, 0x2, 1 }, | ||
1179 | { 768, 0x6, 0x0, 1 }, | ||
1180 | { 816, 0x6, 0x1, 1 }, | ||
1181 | { 750, 0x6, 0x2, 1 }, | ||
1182 | { 1024, 0x7, 0x0, 1 }, | ||
1183 | { 1088, 0x7, 0x1, 1 }, | ||
1184 | { 1000, 0x7, 0x2, 1 }, | ||
1185 | { 1408, 0x8, 0x0, 1 }, | ||
1186 | { 1496, 0x8, 0x1, 1 }, | ||
1187 | { 1536, 0x9, 0x0, 1 }, | ||
1188 | { 1632, 0x9, 0x1, 1 }, | ||
1189 | { 1500, 0x9, 0x2, 1 }, | ||
1190 | |||
1191 | { 250, 0x2, 0x2, 2 }, | ||
1192 | { 256, 0x3, 0x0, 2 }, | ||
1193 | { 272, 0x3, 0x1, 2 }, | ||
1194 | { 384, 0x4, 0x0, 2 }, | ||
1195 | { 408, 0x4, 0x1, 2 }, | ||
1196 | { 375, 0x4, 0x2, 2 }, | ||
1197 | { 512, 0x5, 0x0, 2 }, | ||
1198 | { 544, 0x5, 0x1, 2 }, | ||
1199 | { 500, 0x5, 0x2, 2 }, | ||
1200 | { 768, 0x6, 0x0, 2 }, | ||
1201 | { 816, 0x6, 0x1, 2 }, | ||
1202 | { 750, 0x6, 0x2, 2 }, | ||
1203 | { 1024, 0x7, 0x0, 2 }, | ||
1204 | { 1088, 0x7, 0x1, 2 }, | ||
1205 | { 1000, 0x7, 0x2, 2 }, | ||
1206 | { 1408, 0x8, 0x0, 2 }, | ||
1207 | { 1496, 0x8, 0x1, 2 }, | ||
1208 | { 1536, 0x9, 0x0, 2 }, | ||
1209 | { 1632, 0x9, 0x1, 2 }, | ||
1210 | { 1500, 0x9, 0x2, 2 }, | ||
1211 | }; | ||
1212 | |||
1213 | /* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */ | ||
1214 | static struct { | ||
1215 | int ratio; | ||
1216 | int div; | ||
1217 | } bclk_divs[] = { | ||
1218 | { 10, 0 }, | ||
1219 | { 15, 1 }, | ||
1220 | { 20, 2 }, | ||
1221 | { 30, 3 }, | ||
1222 | { 40, 4 }, | ||
1223 | { 50, 5 }, | ||
1224 | { 55, 6 }, | ||
1225 | { 60, 7 }, | ||
1226 | { 80, 8 }, | ||
1227 | { 100, 9 }, | ||
1228 | { 110, 10 }, | ||
1229 | { 120, 11 }, | ||
1230 | { 160, 12 }, | ||
1231 | { 200, 13 }, | ||
1232 | { 220, 14 }, | ||
1233 | { 240, 15 }, | ||
1234 | { 250, 16 }, | ||
1235 | { 300, 17 }, | ||
1236 | { 320, 18 }, | ||
1237 | { 440, 19 }, | ||
1238 | { 480, 20 }, | ||
1239 | }; | ||
1240 | |||
1241 | /* Sample rates for DSP */ | ||
1242 | static struct { | ||
1243 | int rate; | ||
1244 | int value; | ||
1245 | } sample_rates[] = { | ||
1246 | { 8000, 0 }, | ||
1247 | { 11025, 1 }, | ||
1248 | { 12000, 2 }, | ||
1249 | { 16000, 3 }, | ||
1250 | { 22050, 4 }, | ||
1251 | { 24000, 5 }, | ||
1252 | { 32000, 6 }, | ||
1253 | { 44100, 7 }, | ||
1254 | { 48000, 8 }, | ||
1255 | { 88200, 9 }, | ||
1256 | { 96000, 10 }, | ||
1257 | { 0, 0 }, | ||
1258 | }; | ||
1259 | |||
1260 | static int wm8903_startup(struct snd_pcm_substream *substream) | ||
1261 | { | ||
1262 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1263 | struct snd_soc_device *socdev = rtd->socdev; | ||
1264 | struct snd_soc_codec *codec = socdev->codec; | ||
1265 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1266 | struct i2c_client *i2c = codec->control_data; | ||
1267 | struct snd_pcm_runtime *master_runtime; | ||
1268 | |||
1269 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1270 | wm8903->playback_active++; | ||
1271 | else | ||
1272 | wm8903->capture_active++; | ||
1273 | |||
1274 | /* The DAI has shared clocks so if we already have a playback or | ||
1275 | * capture going then constrain this substream to match it. | ||
1276 | */ | ||
1277 | if (wm8903->master_substream) { | ||
1278 | master_runtime = wm8903->master_substream->runtime; | ||
1279 | |||
1280 | dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", | ||
1281 | master_runtime->sample_bits, | ||
1282 | master_runtime->rate); | ||
1283 | |||
1284 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1285 | SNDRV_PCM_HW_PARAM_RATE, | ||
1286 | master_runtime->rate, | ||
1287 | master_runtime->rate); | ||
1288 | |||
1289 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1290 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1291 | master_runtime->sample_bits, | ||
1292 | master_runtime->sample_bits); | ||
1293 | |||
1294 | wm8903->slave_substream = substream; | ||
1295 | } else | ||
1296 | wm8903->master_substream = substream; | ||
1297 | |||
1298 | return 0; | ||
1299 | } | ||
1300 | |||
1301 | static void wm8903_shutdown(struct snd_pcm_substream *substream) | ||
1302 | { | ||
1303 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1304 | struct snd_soc_device *socdev = rtd->socdev; | ||
1305 | struct snd_soc_codec *codec = socdev->codec; | ||
1306 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1307 | |||
1308 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1309 | wm8903->playback_active--; | ||
1310 | else | ||
1311 | wm8903->capture_active--; | ||
1312 | |||
1313 | if (wm8903->master_substream == substream) | ||
1314 | wm8903->master_substream = wm8903->slave_substream; | ||
1315 | |||
1316 | wm8903->slave_substream = NULL; | ||
1317 | } | ||
1318 | |||
1319 | static int wm8903_hw_params(struct snd_pcm_substream *substream, | ||
1320 | struct snd_pcm_hw_params *params) | ||
1321 | { | ||
1322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1323 | struct snd_soc_device *socdev = rtd->socdev; | ||
1324 | struct snd_soc_codec *codec = socdev->codec; | ||
1325 | struct wm8903_priv *wm8903 = codec->private_data; | ||
1326 | struct i2c_client *i2c = codec->control_data; | ||
1327 | int fs = params_rate(params); | ||
1328 | int bclk; | ||
1329 | int bclk_div; | ||
1330 | int i; | ||
1331 | int dsp_config; | ||
1332 | int clk_config; | ||
1333 | int best_val; | ||
1334 | int cur_val; | ||
1335 | int clk_sys; | ||
1336 | |||
1337 | u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); | ||
1338 | u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2); | ||
1339 | u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); | ||
1340 | u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); | ||
1341 | u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); | ||
1342 | |||
1343 | if (substream == wm8903->slave_substream) { | ||
1344 | dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); | ||
1345 | return 0; | ||
1346 | } | ||
1347 | |||
1348 | /* Configure sample rate logic for DSP - choose nearest rate */ | ||
1349 | dsp_config = 0; | ||
1350 | best_val = abs(sample_rates[dsp_config].rate - fs); | ||
1351 | for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { | ||
1352 | cur_val = abs(sample_rates[i].rate - fs); | ||
1353 | if (cur_val <= best_val) { | ||
1354 | dsp_config = i; | ||
1355 | best_val = cur_val; | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | /* Constraints should stop us hitting this but let's make sure */ | ||
1360 | if (wm8903->capture_active) | ||
1361 | switch (sample_rates[dsp_config].rate) { | ||
1362 | case 88200: | ||
1363 | case 96000: | ||
1364 | dev_err(&i2c->dev, "%dHz unsupported by ADC\n", | ||
1365 | fs); | ||
1366 | return -EINVAL; | ||
1367 | |||
1368 | default: | ||
1369 | break; | ||
1370 | } | ||
1371 | |||
1372 | dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate); | ||
1373 | clock1 &= ~WM8903_SAMPLE_RATE_MASK; | ||
1374 | clock1 |= sample_rates[dsp_config].value; | ||
1375 | |||
1376 | aif1 &= ~WM8903_AIF_WL_MASK; | ||
1377 | bclk = 2 * fs; | ||
1378 | switch (params_format(params)) { | ||
1379 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1380 | bclk *= 16; | ||
1381 | break; | ||
1382 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1383 | bclk *= 20; | ||
1384 | aif1 |= 0x4; | ||
1385 | break; | ||
1386 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1387 | bclk *= 24; | ||
1388 | aif1 |= 0x8; | ||
1389 | break; | ||
1390 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1391 | bclk *= 32; | ||
1392 | aif1 |= 0xc; | ||
1393 | break; | ||
1394 | default: | ||
1395 | return -EINVAL; | ||
1396 | } | ||
1397 | |||
1398 | dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n", | ||
1399 | wm8903->sysclk, fs); | ||
1400 | |||
1401 | /* We may not have an MCLK which allows us to generate exactly | ||
1402 | * the clock we want, particularly with USB derived inputs, so | ||
1403 | * approximate. | ||
1404 | */ | ||
1405 | clk_config = 0; | ||
1406 | best_val = abs((wm8903->sysclk / | ||
1407 | (clk_sys_ratios[0].mclk_div * | ||
1408 | clk_sys_ratios[0].div)) - fs); | ||
1409 | for (i = 1; i < ARRAY_SIZE(clk_sys_ratios); i++) { | ||
1410 | cur_val = abs((wm8903->sysclk / | ||
1411 | (clk_sys_ratios[i].mclk_div * | ||
1412 | clk_sys_ratios[i].div)) - fs); | ||
1413 | |||
1414 | if (cur_val <= best_val) { | ||
1415 | clk_config = i; | ||
1416 | best_val = cur_val; | ||
1417 | } | ||
1418 | } | ||
1419 | |||
1420 | if (clk_sys_ratios[clk_config].mclk_div == 2) { | ||
1421 | clock0 |= WM8903_MCLKDIV2; | ||
1422 | clk_sys = wm8903->sysclk / 2; | ||
1423 | } else { | ||
1424 | clock0 &= ~WM8903_MCLKDIV2; | ||
1425 | clk_sys = wm8903->sysclk; | ||
1426 | } | ||
1427 | |||
1428 | clock1 &= ~(WM8903_CLK_SYS_RATE_MASK | | ||
1429 | WM8903_CLK_SYS_MODE_MASK); | ||
1430 | clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT; | ||
1431 | clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT; | ||
1432 | |||
1433 | dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n", | ||
1434 | clk_sys_ratios[clk_config].rate, | ||
1435 | clk_sys_ratios[clk_config].mode, | ||
1436 | clk_sys_ratios[clk_config].div); | ||
1437 | |||
1438 | dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys); | ||
1439 | |||
1440 | /* We may not get quite the right frequency if using | ||
1441 | * approximate clocks so look for the closest match that is | ||
1442 | * higher than the target (we need to ensure that there enough | ||
1443 | * BCLKs to clock out the samples). | ||
1444 | */ | ||
1445 | bclk_div = 0; | ||
1446 | best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk; | ||
1447 | i = 1; | ||
1448 | while (i < ARRAY_SIZE(bclk_divs)) { | ||
1449 | cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk; | ||
1450 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1451 | break; | ||
1452 | bclk_div = i; | ||
1453 | best_val = cur_val; | ||
1454 | i++; | ||
1455 | } | ||
1456 | |||
1457 | aif2 &= ~WM8903_BCLK_DIV_MASK; | ||
1458 | aif3 &= ~WM8903_LRCLK_RATE_MASK; | ||
1459 | |||
1460 | dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n", | ||
1461 | bclk_divs[bclk_div].ratio / 10, bclk, | ||
1462 | (clk_sys * 10) / bclk_divs[bclk_div].ratio); | ||
1463 | |||
1464 | aif2 |= bclk_divs[bclk_div].div; | ||
1465 | aif3 |= bclk / fs; | ||
1466 | |||
1467 | wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0); | ||
1468 | wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1); | ||
1469 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); | ||
1470 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); | ||
1471 | wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); | ||
1472 | |||
1473 | return 0; | ||
1474 | } | ||
1475 | |||
1476 | #define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\ | ||
1477 | SNDRV_PCM_RATE_11025 | \ | ||
1478 | SNDRV_PCM_RATE_16000 | \ | ||
1479 | SNDRV_PCM_RATE_22050 | \ | ||
1480 | SNDRV_PCM_RATE_32000 | \ | ||
1481 | SNDRV_PCM_RATE_44100 | \ | ||
1482 | SNDRV_PCM_RATE_48000 | \ | ||
1483 | SNDRV_PCM_RATE_88200 | \ | ||
1484 | SNDRV_PCM_RATE_96000) | ||
1485 | |||
1486 | #define WM8903_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ | ||
1487 | SNDRV_PCM_RATE_11025 | \ | ||
1488 | SNDRV_PCM_RATE_16000 | \ | ||
1489 | SNDRV_PCM_RATE_22050 | \ | ||
1490 | SNDRV_PCM_RATE_32000 | \ | ||
1491 | SNDRV_PCM_RATE_44100 | \ | ||
1492 | SNDRV_PCM_RATE_48000) | ||
1493 | |||
1494 | #define WM8903_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ | ||
1495 | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1496 | SNDRV_PCM_FMTBIT_S24_LE) | ||
1497 | |||
1498 | struct snd_soc_dai wm8903_dai = { | ||
1499 | .name = "WM8903", | ||
1500 | .playback = { | ||
1501 | .stream_name = "Playback", | ||
1502 | .channels_min = 2, | ||
1503 | .channels_max = 2, | ||
1504 | .rates = WM8903_PLAYBACK_RATES, | ||
1505 | .formats = WM8903_FORMATS, | ||
1506 | }, | ||
1507 | .capture = { | ||
1508 | .stream_name = "Capture", | ||
1509 | .channels_min = 2, | ||
1510 | .channels_max = 2, | ||
1511 | .rates = WM8903_CAPTURE_RATES, | ||
1512 | .formats = WM8903_FORMATS, | ||
1513 | }, | ||
1514 | .ops = { | ||
1515 | .startup = wm8903_startup, | ||
1516 | .shutdown = wm8903_shutdown, | ||
1517 | .hw_params = wm8903_hw_params, | ||
1518 | }, | ||
1519 | .dai_ops = { | ||
1520 | .digital_mute = wm8903_digital_mute, | ||
1521 | .set_fmt = wm8903_set_dai_fmt, | ||
1522 | .set_sysclk = wm8903_set_dai_sysclk | ||
1523 | } | ||
1524 | }; | ||
1525 | EXPORT_SYMBOL_GPL(wm8903_dai); | ||
1526 | |||
1527 | static int wm8903_suspend(struct platform_device *pdev, pm_message_t state) | ||
1528 | { | ||
1529 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1530 | struct snd_soc_codec *codec = socdev->codec; | ||
1531 | |||
1532 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1533 | |||
1534 | return 0; | ||
1535 | } | ||
1536 | |||
1537 | static int wm8903_resume(struct platform_device *pdev) | ||
1538 | { | ||
1539 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1540 | struct snd_soc_codec *codec = socdev->codec; | ||
1541 | struct i2c_client *i2c = codec->control_data; | ||
1542 | int i; | ||
1543 | u16 *reg_cache = codec->reg_cache; | ||
1544 | u16 *tmp_cache = kmemdup(codec->reg_cache, sizeof(wm8903_reg_defaults), | ||
1545 | GFP_KERNEL); | ||
1546 | |||
1547 | /* Bring the codec back up to standby first to minimise pop/clicks */ | ||
1548 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1549 | wm8903_set_bias_level(codec, codec->suspend_bias_level); | ||
1550 | |||
1551 | /* Sync back everything else */ | ||
1552 | if (tmp_cache) { | ||
1553 | for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) | ||
1554 | if (tmp_cache[i] != reg_cache[i]) | ||
1555 | wm8903_write(codec, i, tmp_cache[i]); | ||
1556 | } else { | ||
1557 | dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); | ||
1558 | } | ||
1559 | |||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* | ||
1564 | * initialise the WM8903 driver | ||
1565 | * register the mixer and dsp interfaces with the kernel | ||
1566 | */ | ||
1567 | static int wm8903_init(struct snd_soc_device *socdev) | ||
1568 | { | ||
1569 | struct snd_soc_codec *codec = socdev->codec; | ||
1570 | struct i2c_client *i2c = codec->control_data; | ||
1571 | int ret = 0; | ||
1572 | u16 val; | ||
1573 | |||
1574 | val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); | ||
1575 | if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { | ||
1576 | dev_err(&i2c->dev, | ||
1577 | "Device with ID register %x is not a WM8903\n", val); | ||
1578 | return -ENODEV; | ||
1579 | } | ||
1580 | |||
1581 | codec->name = "WM8903"; | ||
1582 | codec->owner = THIS_MODULE; | ||
1583 | codec->read = wm8903_read; | ||
1584 | codec->write = wm8903_write; | ||
1585 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1586 | codec->set_bias_level = wm8903_set_bias_level; | ||
1587 | codec->dai = &wm8903_dai; | ||
1588 | codec->num_dai = 1; | ||
1589 | codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults); | ||
1590 | codec->reg_cache = kmemdup(wm8903_reg_defaults, | ||
1591 | sizeof(wm8903_reg_defaults), | ||
1592 | GFP_KERNEL); | ||
1593 | if (codec->reg_cache == NULL) { | ||
1594 | dev_err(&i2c->dev, "Failed to allocate register cache\n"); | ||
1595 | return -ENOMEM; | ||
1596 | } | ||
1597 | |||
1598 | val = wm8903_read(codec, WM8903_REVISION_NUMBER); | ||
1599 | dev_info(&i2c->dev, "WM8903 revision %d\n", | ||
1600 | val & WM8903_CHIP_REV_MASK); | ||
1601 | |||
1602 | wm8903_reset(codec); | ||
1603 | |||
1604 | /* register pcms */ | ||
1605 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1606 | if (ret < 0) { | ||
1607 | dev_err(&i2c->dev, "failed to create pcms\n"); | ||
1608 | goto pcm_err; | ||
1609 | } | ||
1610 | |||
1611 | /* SYSCLK is required for pretty much anything */ | ||
1612 | wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); | ||
1613 | |||
1614 | /* power on device */ | ||
1615 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1616 | |||
1617 | /* Latch volume update bits */ | ||
1618 | val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); | ||
1619 | val |= WM8903_ADCVU; | ||
1620 | wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); | ||
1621 | wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); | ||
1622 | |||
1623 | val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); | ||
1624 | val |= WM8903_DACVU; | ||
1625 | wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); | ||
1626 | wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); | ||
1627 | |||
1628 | val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT); | ||
1629 | val |= WM8903_HPOUTVU; | ||
1630 | wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); | ||
1631 | wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); | ||
1632 | |||
1633 | val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT); | ||
1634 | val |= WM8903_LINEOUTVU; | ||
1635 | wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); | ||
1636 | wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); | ||
1637 | |||
1638 | val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT); | ||
1639 | val |= WM8903_SPKVU; | ||
1640 | wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); | ||
1641 | wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); | ||
1642 | |||
1643 | /* Enable DAC soft mute by default */ | ||
1644 | val = wm8903_read(codec, WM8903_DAC_DIGITAL_1); | ||
1645 | val |= WM8903_DAC_MUTEMODE; | ||
1646 | wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); | ||
1647 | |||
1648 | wm8903_add_controls(codec); | ||
1649 | wm8903_add_widgets(codec); | ||
1650 | ret = snd_soc_register_card(socdev); | ||
1651 | if (ret < 0) { | ||
1652 | dev_err(&i2c->dev, "wm8903: failed to register card\n"); | ||
1653 | goto card_err; | ||
1654 | } | ||
1655 | |||
1656 | return ret; | ||
1657 | |||
1658 | card_err: | ||
1659 | snd_soc_free_pcms(socdev); | ||
1660 | snd_soc_dapm_free(socdev); | ||
1661 | pcm_err: | ||
1662 | kfree(codec->reg_cache); | ||
1663 | return ret; | ||
1664 | } | ||
1665 | |||
1666 | static struct snd_soc_device *wm8903_socdev; | ||
1667 | |||
1668 | static int wm8903_i2c_probe(struct i2c_client *i2c, | ||
1669 | const struct i2c_device_id *id) | ||
1670 | { | ||
1671 | struct snd_soc_device *socdev = wm8903_socdev; | ||
1672 | struct snd_soc_codec *codec = socdev->codec; | ||
1673 | int ret; | ||
1674 | |||
1675 | i2c_set_clientdata(i2c, codec); | ||
1676 | codec->control_data = i2c; | ||
1677 | |||
1678 | ret = wm8903_init(socdev); | ||
1679 | if (ret < 0) | ||
1680 | dev_err(&i2c->dev, "Device initialisation failed\n"); | ||
1681 | |||
1682 | return ret; | ||
1683 | } | ||
1684 | |||
1685 | static int wm8903_i2c_remove(struct i2c_client *client) | ||
1686 | { | ||
1687 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1688 | kfree(codec->reg_cache); | ||
1689 | return 0; | ||
1690 | } | ||
1691 | |||
1692 | /* i2c codec control layer */ | ||
1693 | static const struct i2c_device_id wm8903_i2c_id[] = { | ||
1694 | { "wm8903", 0 }, | ||
1695 | { } | ||
1696 | }; | ||
1697 | MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id); | ||
1698 | |||
1699 | static struct i2c_driver wm8903_i2c_driver = { | ||
1700 | .driver = { | ||
1701 | .name = "WM8903", | ||
1702 | .owner = THIS_MODULE, | ||
1703 | }, | ||
1704 | .probe = wm8903_i2c_probe, | ||
1705 | .remove = wm8903_i2c_remove, | ||
1706 | .id_table = wm8903_i2c_id, | ||
1707 | }; | ||
1708 | |||
1709 | static int wm8903_probe(struct platform_device *pdev) | ||
1710 | { | ||
1711 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1712 | struct wm8903_setup_data *setup; | ||
1713 | struct snd_soc_codec *codec; | ||
1714 | struct wm8903_priv *wm8903; | ||
1715 | struct i2c_board_info board_info; | ||
1716 | struct i2c_adapter *adapter; | ||
1717 | struct i2c_client *i2c_client; | ||
1718 | int ret = 0; | ||
1719 | |||
1720 | setup = socdev->codec_data; | ||
1721 | |||
1722 | if (!setup->i2c_address) { | ||
1723 | dev_err(&pdev->dev, "No codec address provided\n"); | ||
1724 | return -ENODEV; | ||
1725 | } | ||
1726 | |||
1727 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1728 | if (codec == NULL) | ||
1729 | return -ENOMEM; | ||
1730 | |||
1731 | wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); | ||
1732 | if (wm8903 == NULL) { | ||
1733 | ret = -ENOMEM; | ||
1734 | goto err_codec; | ||
1735 | } | ||
1736 | |||
1737 | codec->private_data = wm8903; | ||
1738 | socdev->codec = codec; | ||
1739 | mutex_init(&codec->mutex); | ||
1740 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1741 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1742 | |||
1743 | wm8903_socdev = socdev; | ||
1744 | |||
1745 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1746 | ret = i2c_add_driver(&wm8903_i2c_driver); | ||
1747 | if (ret != 0) { | ||
1748 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1749 | goto err_priv; | ||
1750 | } else { | ||
1751 | memset(&board_info, 0, sizeof(board_info)); | ||
1752 | strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE); | ||
1753 | board_info.addr = setup->i2c_address; | ||
1754 | |||
1755 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1756 | if (!adapter) { | ||
1757 | dev_err(&pdev->dev, "Can't get I2C bus %d\n", | ||
1758 | setup->i2c_bus); | ||
1759 | ret = -ENODEV; | ||
1760 | goto err_adapter; | ||
1761 | } | ||
1762 | |||
1763 | i2c_client = i2c_new_device(adapter, &board_info); | ||
1764 | i2c_put_adapter(adapter); | ||
1765 | if (i2c_client == NULL) { | ||
1766 | dev_err(&pdev->dev, | ||
1767 | "I2C driver registration failed\n"); | ||
1768 | ret = -ENODEV; | ||
1769 | goto err_adapter; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | return ret; | ||
1774 | |||
1775 | err_adapter: | ||
1776 | i2c_del_driver(&wm8903_i2c_driver); | ||
1777 | err_priv: | ||
1778 | kfree(codec->private_data); | ||
1779 | err_codec: | ||
1780 | kfree(codec); | ||
1781 | return ret; | ||
1782 | } | ||
1783 | |||
1784 | /* power down chip */ | ||
1785 | static int wm8903_remove(struct platform_device *pdev) | ||
1786 | { | ||
1787 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1788 | struct snd_soc_codec *codec = socdev->codec; | ||
1789 | |||
1790 | if (codec->control_data) | ||
1791 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1792 | |||
1793 | snd_soc_free_pcms(socdev); | ||
1794 | snd_soc_dapm_free(socdev); | ||
1795 | i2c_unregister_device(socdev->codec->control_data); | ||
1796 | i2c_del_driver(&wm8903_i2c_driver); | ||
1797 | kfree(codec->private_data); | ||
1798 | kfree(codec); | ||
1799 | |||
1800 | return 0; | ||
1801 | } | ||
1802 | |||
1803 | struct snd_soc_codec_device soc_codec_dev_wm8903 = { | ||
1804 | .probe = wm8903_probe, | ||
1805 | .remove = wm8903_remove, | ||
1806 | .suspend = wm8903_suspend, | ||
1807 | .resume = wm8903_resume, | ||
1808 | }; | ||
1809 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); | ||
1810 | |||
1811 | MODULE_DESCRIPTION("ASoC WM8903 driver"); | ||
1812 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>"); | ||
1813 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h new file mode 100644 index 00000000000..cec622f2f66 --- /dev/null +++ b/sound/soc/codecs/wm8903.h | |||
@@ -0,0 +1,1463 @@ | |||
1 | /* | ||
2 | * wm8903.h - WM8903 audio codec interface | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _WM8903_H | ||
14 | #define _WM8903_H | ||
15 | |||
16 | #include <linux/i2c.h> | ||
17 | |||
18 | extern struct snd_soc_dai wm8903_dai; | ||
19 | extern struct snd_soc_codec_device soc_codec_dev_wm8903; | ||
20 | |||
21 | struct wm8903_setup_data { | ||
22 | int i2c_bus; | ||
23 | int i2c_address; | ||
24 | }; | ||
25 | |||
26 | #define WM8903_MCLK_DIV_2 1 | ||
27 | #define WM8903_CLK_SYS 2 | ||
28 | #define WM8903_BCLK 3 | ||
29 | #define WM8903_LRCLK 4 | ||
30 | |||
31 | /* | ||
32 | * Register values. | ||
33 | */ | ||
34 | #define WM8903_SW_RESET_AND_ID 0x00 | ||
35 | #define WM8903_REVISION_NUMBER 0x01 | ||
36 | #define WM8903_BIAS_CONTROL_0 0x04 | ||
37 | #define WM8903_VMID_CONTROL_0 0x05 | ||
38 | #define WM8903_MIC_BIAS_CONTROL_0 0x06 | ||
39 | #define WM8903_ANALOGUE_DAC_0 0x08 | ||
40 | #define WM8903_ANALOGUE_ADC_0 0x0A | ||
41 | #define WM8903_POWER_MANAGEMENT_0 0x0C | ||
42 | #define WM8903_POWER_MANAGEMENT_1 0x0D | ||
43 | #define WM8903_POWER_MANAGEMENT_2 0x0E | ||
44 | #define WM8903_POWER_MANAGEMENT_3 0x0F | ||
45 | #define WM8903_POWER_MANAGEMENT_4 0x10 | ||
46 | #define WM8903_POWER_MANAGEMENT_5 0x11 | ||
47 | #define WM8903_POWER_MANAGEMENT_6 0x12 | ||
48 | #define WM8903_CLOCK_RATES_0 0x14 | ||
49 | #define WM8903_CLOCK_RATES_1 0x15 | ||
50 | #define WM8903_CLOCK_RATES_2 0x16 | ||
51 | #define WM8903_AUDIO_INTERFACE_0 0x18 | ||
52 | #define WM8903_AUDIO_INTERFACE_1 0x19 | ||
53 | #define WM8903_AUDIO_INTERFACE_2 0x1A | ||
54 | #define WM8903_AUDIO_INTERFACE_3 0x1B | ||
55 | #define WM8903_DAC_DIGITAL_VOLUME_LEFT 0x1E | ||
56 | #define WM8903_DAC_DIGITAL_VOLUME_RIGHT 0x1F | ||
57 | #define WM8903_DAC_DIGITAL_0 0x20 | ||
58 | #define WM8903_DAC_DIGITAL_1 0x21 | ||
59 | #define WM8903_ADC_DIGITAL_VOLUME_LEFT 0x24 | ||
60 | #define WM8903_ADC_DIGITAL_VOLUME_RIGHT 0x25 | ||
61 | #define WM8903_ADC_DIGITAL_0 0x26 | ||
62 | #define WM8903_DIGITAL_MICROPHONE_0 0x27 | ||
63 | #define WM8903_DRC_0 0x28 | ||
64 | #define WM8903_DRC_1 0x29 | ||
65 | #define WM8903_DRC_2 0x2A | ||
66 | #define WM8903_DRC_3 0x2B | ||
67 | #define WM8903_ANALOGUE_LEFT_INPUT_0 0x2C | ||
68 | #define WM8903_ANALOGUE_RIGHT_INPUT_0 0x2D | ||
69 | #define WM8903_ANALOGUE_LEFT_INPUT_1 0x2E | ||
70 | #define WM8903_ANALOGUE_RIGHT_INPUT_1 0x2F | ||
71 | #define WM8903_ANALOGUE_LEFT_MIX_0 0x32 | ||
72 | #define WM8903_ANALOGUE_RIGHT_MIX_0 0x33 | ||
73 | #define WM8903_ANALOGUE_SPK_MIX_LEFT_0 0x34 | ||
74 | #define WM8903_ANALOGUE_SPK_MIX_LEFT_1 0x35 | ||
75 | #define WM8903_ANALOGUE_SPK_MIX_RIGHT_0 0x36 | ||
76 | #define WM8903_ANALOGUE_SPK_MIX_RIGHT_1 0x37 | ||
77 | #define WM8903_ANALOGUE_OUT1_LEFT 0x39 | ||
78 | #define WM8903_ANALOGUE_OUT1_RIGHT 0x3A | ||
79 | #define WM8903_ANALOGUE_OUT2_LEFT 0x3B | ||
80 | #define WM8903_ANALOGUE_OUT2_RIGHT 0x3C | ||
81 | #define WM8903_ANALOGUE_OUT3_LEFT 0x3E | ||
82 | #define WM8903_ANALOGUE_OUT3_RIGHT 0x3F | ||
83 | #define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0 0x41 | ||
84 | #define WM8903_DC_SERVO_0 0x43 | ||
85 | #define WM8903_DC_SERVO_2 0x45 | ||
86 | #define WM8903_ANALOGUE_HP_0 0x5A | ||
87 | #define WM8903_ANALOGUE_LINEOUT_0 0x5E | ||
88 | #define WM8903_CHARGE_PUMP_0 0x62 | ||
89 | #define WM8903_CLASS_W_0 0x68 | ||
90 | #define WM8903_WRITE_SEQUENCER_0 0x6C | ||
91 | #define WM8903_WRITE_SEQUENCER_1 0x6D | ||
92 | #define WM8903_WRITE_SEQUENCER_2 0x6E | ||
93 | #define WM8903_WRITE_SEQUENCER_3 0x6F | ||
94 | #define WM8903_WRITE_SEQUENCER_4 0x70 | ||
95 | #define WM8903_CONTROL_INTERFACE 0x72 | ||
96 | #define WM8903_GPIO_CONTROL_1 0x74 | ||
97 | #define WM8903_GPIO_CONTROL_2 0x75 | ||
98 | #define WM8903_GPIO_CONTROL_3 0x76 | ||
99 | #define WM8903_GPIO_CONTROL_4 0x77 | ||
100 | #define WM8903_GPIO_CONTROL_5 0x78 | ||
101 | #define WM8903_INTERRUPT_STATUS_1 0x79 | ||
102 | #define WM8903_INTERRUPT_STATUS_1_MASK 0x7A | ||
103 | #define WM8903_INTERRUPT_POLARITY_1 0x7B | ||
104 | #define WM8903_INTERRUPT_CONTROL 0x7E | ||
105 | #define WM8903_CONTROL_INTERFACE_TEST_1 0x81 | ||
106 | #define WM8903_CHARGE_PUMP_TEST_1 0x95 | ||
107 | #define WM8903_CLOCK_RATE_TEST_4 0xA4 | ||
108 | #define WM8903_ANALOGUE_OUTPUT_BIAS_0 0xAC | ||
109 | |||
110 | #define WM8903_REGISTER_COUNT 75 | ||
111 | #define WM8903_MAX_REGISTER 0xAC | ||
112 | |||
113 | /* | ||
114 | * Field Definitions. | ||
115 | */ | ||
116 | |||
117 | /* | ||
118 | * R0 (0x00) - SW Reset and ID | ||
119 | */ | ||
120 | #define WM8903_SW_RESET_DEV_ID1_MASK 0xFFFF /* SW_RESET_DEV_ID1 - [15:0] */ | ||
121 | #define WM8903_SW_RESET_DEV_ID1_SHIFT 0 /* SW_RESET_DEV_ID1 - [15:0] */ | ||
122 | #define WM8903_SW_RESET_DEV_ID1_WIDTH 16 /* SW_RESET_DEV_ID1 - [15:0] */ | ||
123 | |||
124 | /* | ||
125 | * R1 (0x01) - Revision Number | ||
126 | */ | ||
127 | #define WM8903_CHIP_REV_MASK 0x000F /* CHIP_REV - [3:0] */ | ||
128 | #define WM8903_CHIP_REV_SHIFT 0 /* CHIP_REV - [3:0] */ | ||
129 | #define WM8903_CHIP_REV_WIDTH 4 /* CHIP_REV - [3:0] */ | ||
130 | |||
131 | /* | ||
132 | * R4 (0x04) - Bias Control 0 | ||
133 | */ | ||
134 | #define WM8903_POBCTRL 0x0010 /* POBCTRL */ | ||
135 | #define WM8903_POBCTRL_MASK 0x0010 /* POBCTRL */ | ||
136 | #define WM8903_POBCTRL_SHIFT 4 /* POBCTRL */ | ||
137 | #define WM8903_POBCTRL_WIDTH 1 /* POBCTRL */ | ||
138 | #define WM8903_ISEL_MASK 0x000C /* ISEL - [3:2] */ | ||
139 | #define WM8903_ISEL_SHIFT 2 /* ISEL - [3:2] */ | ||
140 | #define WM8903_ISEL_WIDTH 2 /* ISEL - [3:2] */ | ||
141 | #define WM8903_STARTUP_BIAS_ENA 0x0002 /* STARTUP_BIAS_ENA */ | ||
142 | #define WM8903_STARTUP_BIAS_ENA_MASK 0x0002 /* STARTUP_BIAS_ENA */ | ||
143 | #define WM8903_STARTUP_BIAS_ENA_SHIFT 1 /* STARTUP_BIAS_ENA */ | ||
144 | #define WM8903_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ | ||
145 | #define WM8903_BIAS_ENA 0x0001 /* BIAS_ENA */ | ||
146 | #define WM8903_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */ | ||
147 | #define WM8903_BIAS_ENA_SHIFT 0 /* BIAS_ENA */ | ||
148 | #define WM8903_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ | ||
149 | |||
150 | /* | ||
151 | * R5 (0x05) - VMID Control 0 | ||
152 | */ | ||
153 | #define WM8903_VMID_TIE_ENA 0x0080 /* VMID_TIE_ENA */ | ||
154 | #define WM8903_VMID_TIE_ENA_MASK 0x0080 /* VMID_TIE_ENA */ | ||
155 | #define WM8903_VMID_TIE_ENA_SHIFT 7 /* VMID_TIE_ENA */ | ||
156 | #define WM8903_VMID_TIE_ENA_WIDTH 1 /* VMID_TIE_ENA */ | ||
157 | #define WM8903_BUFIO_ENA 0x0040 /* BUFIO_ENA */ | ||
158 | #define WM8903_BUFIO_ENA_MASK 0x0040 /* BUFIO_ENA */ | ||
159 | #define WM8903_BUFIO_ENA_SHIFT 6 /* BUFIO_ENA */ | ||
160 | #define WM8903_BUFIO_ENA_WIDTH 1 /* BUFIO_ENA */ | ||
161 | #define WM8903_VMID_IO_ENA 0x0020 /* VMID_IO_ENA */ | ||
162 | #define WM8903_VMID_IO_ENA_MASK 0x0020 /* VMID_IO_ENA */ | ||
163 | #define WM8903_VMID_IO_ENA_SHIFT 5 /* VMID_IO_ENA */ | ||
164 | #define WM8903_VMID_IO_ENA_WIDTH 1 /* VMID_IO_ENA */ | ||
165 | #define WM8903_VMID_SOFT_MASK 0x0018 /* VMID_SOFT - [4:3] */ | ||
166 | #define WM8903_VMID_SOFT_SHIFT 3 /* VMID_SOFT - [4:3] */ | ||
167 | #define WM8903_VMID_SOFT_WIDTH 2 /* VMID_SOFT - [4:3] */ | ||
168 | #define WM8903_VMID_RES_MASK 0x0006 /* VMID_RES - [2:1] */ | ||
169 | #define WM8903_VMID_RES_SHIFT 1 /* VMID_RES - [2:1] */ | ||
170 | #define WM8903_VMID_RES_WIDTH 2 /* VMID_RES - [2:1] */ | ||
171 | #define WM8903_VMID_BUF_ENA 0x0001 /* VMID_BUF_ENA */ | ||
172 | #define WM8903_VMID_BUF_ENA_MASK 0x0001 /* VMID_BUF_ENA */ | ||
173 | #define WM8903_VMID_BUF_ENA_SHIFT 0 /* VMID_BUF_ENA */ | ||
174 | #define WM8903_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ | ||
175 | |||
176 | #define WM8903_VMID_RES_50K 2 | ||
177 | #define WM8903_VMID_RES_250K 3 | ||
178 | #define WM8903_VMID_RES_5K 4 | ||
179 | |||
180 | /* | ||
181 | * R6 (0x06) - Mic Bias Control 0 | ||
182 | */ | ||
183 | #define WM8903_MICDET_HYST_ENA 0x0080 /* MICDET_HYST_ENA */ | ||
184 | #define WM8903_MICDET_HYST_ENA_MASK 0x0080 /* MICDET_HYST_ENA */ | ||
185 | #define WM8903_MICDET_HYST_ENA_SHIFT 7 /* MICDET_HYST_ENA */ | ||
186 | #define WM8903_MICDET_HYST_ENA_WIDTH 1 /* MICDET_HYST_ENA */ | ||
187 | #define WM8903_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */ | ||
188 | #define WM8903_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */ | ||
189 | #define WM8903_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */ | ||
190 | #define WM8903_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */ | ||
191 | #define WM8903_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */ | ||
192 | #define WM8903_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */ | ||
193 | #define WM8903_MICDET_ENA 0x0002 /* MICDET_ENA */ | ||
194 | #define WM8903_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */ | ||
195 | #define WM8903_MICDET_ENA_SHIFT 1 /* MICDET_ENA */ | ||
196 | #define WM8903_MICDET_ENA_WIDTH 1 /* MICDET_ENA */ | ||
197 | #define WM8903_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */ | ||
198 | #define WM8903_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */ | ||
199 | #define WM8903_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */ | ||
200 | #define WM8903_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */ | ||
201 | |||
202 | /* | ||
203 | * R8 (0x08) - Analogue DAC 0 | ||
204 | */ | ||
205 | #define WM8903_DACBIAS_SEL_MASK 0x0018 /* DACBIAS_SEL - [4:3] */ | ||
206 | #define WM8903_DACBIAS_SEL_SHIFT 3 /* DACBIAS_SEL - [4:3] */ | ||
207 | #define WM8903_DACBIAS_SEL_WIDTH 2 /* DACBIAS_SEL - [4:3] */ | ||
208 | #define WM8903_DACVMID_BIAS_SEL_MASK 0x0006 /* DACVMID_BIAS_SEL - [2:1] */ | ||
209 | #define WM8903_DACVMID_BIAS_SEL_SHIFT 1 /* DACVMID_BIAS_SEL - [2:1] */ | ||
210 | #define WM8903_DACVMID_BIAS_SEL_WIDTH 2 /* DACVMID_BIAS_SEL - [2:1] */ | ||
211 | |||
212 | /* | ||
213 | * R10 (0x0A) - Analogue ADC 0 | ||
214 | */ | ||
215 | #define WM8903_ADC_OSR128 0x0001 /* ADC_OSR128 */ | ||
216 | #define WM8903_ADC_OSR128_MASK 0x0001 /* ADC_OSR128 */ | ||
217 | #define WM8903_ADC_OSR128_SHIFT 0 /* ADC_OSR128 */ | ||
218 | #define WM8903_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ | ||
219 | |||
220 | /* | ||
221 | * R12 (0x0C) - Power Management 0 | ||
222 | */ | ||
223 | #define WM8903_INL_ENA 0x0002 /* INL_ENA */ | ||
224 | #define WM8903_INL_ENA_MASK 0x0002 /* INL_ENA */ | ||
225 | #define WM8903_INL_ENA_SHIFT 1 /* INL_ENA */ | ||
226 | #define WM8903_INL_ENA_WIDTH 1 /* INL_ENA */ | ||
227 | #define WM8903_INR_ENA 0x0001 /* INR_ENA */ | ||
228 | #define WM8903_INR_ENA_MASK 0x0001 /* INR_ENA */ | ||
229 | #define WM8903_INR_ENA_SHIFT 0 /* INR_ENA */ | ||
230 | #define WM8903_INR_ENA_WIDTH 1 /* INR_ENA */ | ||
231 | |||
232 | /* | ||
233 | * R13 (0x0D) - Power Management 1 | ||
234 | */ | ||
235 | #define WM8903_MIXOUTL_ENA 0x0002 /* MIXOUTL_ENA */ | ||
236 | #define WM8903_MIXOUTL_ENA_MASK 0x0002 /* MIXOUTL_ENA */ | ||
237 | #define WM8903_MIXOUTL_ENA_SHIFT 1 /* MIXOUTL_ENA */ | ||
238 | #define WM8903_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */ | ||
239 | #define WM8903_MIXOUTR_ENA 0x0001 /* MIXOUTR_ENA */ | ||
240 | #define WM8903_MIXOUTR_ENA_MASK 0x0001 /* MIXOUTR_ENA */ | ||
241 | #define WM8903_MIXOUTR_ENA_SHIFT 0 /* MIXOUTR_ENA */ | ||
242 | #define WM8903_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */ | ||
243 | |||
244 | /* | ||
245 | * R14 (0x0E) - Power Management 2 | ||
246 | */ | ||
247 | #define WM8903_HPL_PGA_ENA 0x0002 /* HPL_PGA_ENA */ | ||
248 | #define WM8903_HPL_PGA_ENA_MASK 0x0002 /* HPL_PGA_ENA */ | ||
249 | #define WM8903_HPL_PGA_ENA_SHIFT 1 /* HPL_PGA_ENA */ | ||
250 | #define WM8903_HPL_PGA_ENA_WIDTH 1 /* HPL_PGA_ENA */ | ||
251 | #define WM8903_HPR_PGA_ENA 0x0001 /* HPR_PGA_ENA */ | ||
252 | #define WM8903_HPR_PGA_ENA_MASK 0x0001 /* HPR_PGA_ENA */ | ||
253 | #define WM8903_HPR_PGA_ENA_SHIFT 0 /* HPR_PGA_ENA */ | ||
254 | #define WM8903_HPR_PGA_ENA_WIDTH 1 /* HPR_PGA_ENA */ | ||
255 | |||
256 | /* | ||
257 | * R15 (0x0F) - Power Management 3 | ||
258 | */ | ||
259 | #define WM8903_LINEOUTL_PGA_ENA 0x0002 /* LINEOUTL_PGA_ENA */ | ||
260 | #define WM8903_LINEOUTL_PGA_ENA_MASK 0x0002 /* LINEOUTL_PGA_ENA */ | ||
261 | #define WM8903_LINEOUTL_PGA_ENA_SHIFT 1 /* LINEOUTL_PGA_ENA */ | ||
262 | #define WM8903_LINEOUTL_PGA_ENA_WIDTH 1 /* LINEOUTL_PGA_ENA */ | ||
263 | #define WM8903_LINEOUTR_PGA_ENA 0x0001 /* LINEOUTR_PGA_ENA */ | ||
264 | #define WM8903_LINEOUTR_PGA_ENA_MASK 0x0001 /* LINEOUTR_PGA_ENA */ | ||
265 | #define WM8903_LINEOUTR_PGA_ENA_SHIFT 0 /* LINEOUTR_PGA_ENA */ | ||
266 | #define WM8903_LINEOUTR_PGA_ENA_WIDTH 1 /* LINEOUTR_PGA_ENA */ | ||
267 | |||
268 | /* | ||
269 | * R16 (0x10) - Power Management 4 | ||
270 | */ | ||
271 | #define WM8903_MIXSPKL_ENA 0x0002 /* MIXSPKL_ENA */ | ||
272 | #define WM8903_MIXSPKL_ENA_MASK 0x0002 /* MIXSPKL_ENA */ | ||
273 | #define WM8903_MIXSPKL_ENA_SHIFT 1 /* MIXSPKL_ENA */ | ||
274 | #define WM8903_MIXSPKL_ENA_WIDTH 1 /* MIXSPKL_ENA */ | ||
275 | #define WM8903_MIXSPKR_ENA 0x0001 /* MIXSPKR_ENA */ | ||
276 | #define WM8903_MIXSPKR_ENA_MASK 0x0001 /* MIXSPKR_ENA */ | ||
277 | #define WM8903_MIXSPKR_ENA_SHIFT 0 /* MIXSPKR_ENA */ | ||
278 | #define WM8903_MIXSPKR_ENA_WIDTH 1 /* MIXSPKR_ENA */ | ||
279 | |||
280 | /* | ||
281 | * R17 (0x11) - Power Management 5 | ||
282 | */ | ||
283 | #define WM8903_SPKL_ENA 0x0002 /* SPKL_ENA */ | ||
284 | #define WM8903_SPKL_ENA_MASK 0x0002 /* SPKL_ENA */ | ||
285 | #define WM8903_SPKL_ENA_SHIFT 1 /* SPKL_ENA */ | ||
286 | #define WM8903_SPKL_ENA_WIDTH 1 /* SPKL_ENA */ | ||
287 | #define WM8903_SPKR_ENA 0x0001 /* SPKR_ENA */ | ||
288 | #define WM8903_SPKR_ENA_MASK 0x0001 /* SPKR_ENA */ | ||
289 | #define WM8903_SPKR_ENA_SHIFT 0 /* SPKR_ENA */ | ||
290 | #define WM8903_SPKR_ENA_WIDTH 1 /* SPKR_ENA */ | ||
291 | |||
292 | /* | ||
293 | * R18 (0x12) - Power Management 6 | ||
294 | */ | ||
295 | #define WM8903_DACL_ENA 0x0008 /* DACL_ENA */ | ||
296 | #define WM8903_DACL_ENA_MASK 0x0008 /* DACL_ENA */ | ||
297 | #define WM8903_DACL_ENA_SHIFT 3 /* DACL_ENA */ | ||
298 | #define WM8903_DACL_ENA_WIDTH 1 /* DACL_ENA */ | ||
299 | #define WM8903_DACR_ENA 0x0004 /* DACR_ENA */ | ||
300 | #define WM8903_DACR_ENA_MASK 0x0004 /* DACR_ENA */ | ||
301 | #define WM8903_DACR_ENA_SHIFT 2 /* DACR_ENA */ | ||
302 | #define WM8903_DACR_ENA_WIDTH 1 /* DACR_ENA */ | ||
303 | #define WM8903_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
304 | #define WM8903_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ | ||
305 | #define WM8903_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ | ||
306 | #define WM8903_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ | ||
307 | #define WM8903_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
308 | #define WM8903_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ | ||
309 | #define WM8903_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ | ||
310 | #define WM8903_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ | ||
311 | |||
312 | /* | ||
313 | * R20 (0x14) - Clock Rates 0 | ||
314 | */ | ||
315 | #define WM8903_MCLKDIV2 0x0001 /* MCLKDIV2 */ | ||
316 | #define WM8903_MCLKDIV2_MASK 0x0001 /* MCLKDIV2 */ | ||
317 | #define WM8903_MCLKDIV2_SHIFT 0 /* MCLKDIV2 */ | ||
318 | #define WM8903_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */ | ||
319 | |||
320 | /* | ||
321 | * R21 (0x15) - Clock Rates 1 | ||
322 | */ | ||
323 | #define WM8903_CLK_SYS_RATE_MASK 0x3C00 /* CLK_SYS_RATE - [13:10] */ | ||
324 | #define WM8903_CLK_SYS_RATE_SHIFT 10 /* CLK_SYS_RATE - [13:10] */ | ||
325 | #define WM8903_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [13:10] */ | ||
326 | #define WM8903_CLK_SYS_MODE_MASK 0x0300 /* CLK_SYS_MODE - [9:8] */ | ||
327 | #define WM8903_CLK_SYS_MODE_SHIFT 8 /* CLK_SYS_MODE - [9:8] */ | ||
328 | #define WM8903_CLK_SYS_MODE_WIDTH 2 /* CLK_SYS_MODE - [9:8] */ | ||
329 | #define WM8903_SAMPLE_RATE_MASK 0x000F /* SAMPLE_RATE - [3:0] */ | ||
330 | #define WM8903_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [3:0] */ | ||
331 | #define WM8903_SAMPLE_RATE_WIDTH 4 /* SAMPLE_RATE - [3:0] */ | ||
332 | |||
333 | /* | ||
334 | * R22 (0x16) - Clock Rates 2 | ||
335 | */ | ||
336 | #define WM8903_CLK_SYS_ENA 0x0004 /* CLK_SYS_ENA */ | ||
337 | #define WM8903_CLK_SYS_ENA_MASK 0x0004 /* CLK_SYS_ENA */ | ||
338 | #define WM8903_CLK_SYS_ENA_SHIFT 2 /* CLK_SYS_ENA */ | ||
339 | #define WM8903_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ | ||
340 | #define WM8903_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */ | ||
341 | #define WM8903_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */ | ||
342 | #define WM8903_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */ | ||
343 | #define WM8903_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ | ||
344 | #define WM8903_TO_ENA 0x0001 /* TO_ENA */ | ||
345 | #define WM8903_TO_ENA_MASK 0x0001 /* TO_ENA */ | ||
346 | #define WM8903_TO_ENA_SHIFT 0 /* TO_ENA */ | ||
347 | #define WM8903_TO_ENA_WIDTH 1 /* TO_ENA */ | ||
348 | |||
349 | /* | ||
350 | * R24 (0x18) - Audio Interface 0 | ||
351 | */ | ||
352 | #define WM8903_DACL_DATINV 0x1000 /* DACL_DATINV */ | ||
353 | #define WM8903_DACL_DATINV_MASK 0x1000 /* DACL_DATINV */ | ||
354 | #define WM8903_DACL_DATINV_SHIFT 12 /* DACL_DATINV */ | ||
355 | #define WM8903_DACL_DATINV_WIDTH 1 /* DACL_DATINV */ | ||
356 | #define WM8903_DACR_DATINV 0x0800 /* DACR_DATINV */ | ||
357 | #define WM8903_DACR_DATINV_MASK 0x0800 /* DACR_DATINV */ | ||
358 | #define WM8903_DACR_DATINV_SHIFT 11 /* DACR_DATINV */ | ||
359 | #define WM8903_DACR_DATINV_WIDTH 1 /* DACR_DATINV */ | ||
360 | #define WM8903_DAC_BOOST_MASK 0x0600 /* DAC_BOOST - [10:9] */ | ||
361 | #define WM8903_DAC_BOOST_SHIFT 9 /* DAC_BOOST - [10:9] */ | ||
362 | #define WM8903_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [10:9] */ | ||
363 | #define WM8903_LOOPBACK 0x0100 /* LOOPBACK */ | ||
364 | #define WM8903_LOOPBACK_MASK 0x0100 /* LOOPBACK */ | ||
365 | #define WM8903_LOOPBACK_SHIFT 8 /* LOOPBACK */ | ||
366 | #define WM8903_LOOPBACK_WIDTH 1 /* LOOPBACK */ | ||
367 | #define WM8903_AIFADCL_SRC 0x0080 /* AIFADCL_SRC */ | ||
368 | #define WM8903_AIFADCL_SRC_MASK 0x0080 /* AIFADCL_SRC */ | ||
369 | #define WM8903_AIFADCL_SRC_SHIFT 7 /* AIFADCL_SRC */ | ||
370 | #define WM8903_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */ | ||
371 | #define WM8903_AIFADCR_SRC 0x0040 /* AIFADCR_SRC */ | ||
372 | #define WM8903_AIFADCR_SRC_MASK 0x0040 /* AIFADCR_SRC */ | ||
373 | #define WM8903_AIFADCR_SRC_SHIFT 6 /* AIFADCR_SRC */ | ||
374 | #define WM8903_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */ | ||
375 | #define WM8903_AIFDACL_SRC 0x0020 /* AIFDACL_SRC */ | ||
376 | #define WM8903_AIFDACL_SRC_MASK 0x0020 /* AIFDACL_SRC */ | ||
377 | #define WM8903_AIFDACL_SRC_SHIFT 5 /* AIFDACL_SRC */ | ||
378 | #define WM8903_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */ | ||
379 | #define WM8903_AIFDACR_SRC 0x0010 /* AIFDACR_SRC */ | ||
380 | #define WM8903_AIFDACR_SRC_MASK 0x0010 /* AIFDACR_SRC */ | ||
381 | #define WM8903_AIFDACR_SRC_SHIFT 4 /* AIFDACR_SRC */ | ||
382 | #define WM8903_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */ | ||
383 | #define WM8903_ADC_COMP 0x0008 /* ADC_COMP */ | ||
384 | #define WM8903_ADC_COMP_MASK 0x0008 /* ADC_COMP */ | ||
385 | #define WM8903_ADC_COMP_SHIFT 3 /* ADC_COMP */ | ||
386 | #define WM8903_ADC_COMP_WIDTH 1 /* ADC_COMP */ | ||
387 | #define WM8903_ADC_COMPMODE 0x0004 /* ADC_COMPMODE */ | ||
388 | #define WM8903_ADC_COMPMODE_MASK 0x0004 /* ADC_COMPMODE */ | ||
389 | #define WM8903_ADC_COMPMODE_SHIFT 2 /* ADC_COMPMODE */ | ||
390 | #define WM8903_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */ | ||
391 | #define WM8903_DAC_COMP 0x0002 /* DAC_COMP */ | ||
392 | #define WM8903_DAC_COMP_MASK 0x0002 /* DAC_COMP */ | ||
393 | #define WM8903_DAC_COMP_SHIFT 1 /* DAC_COMP */ | ||
394 | #define WM8903_DAC_COMP_WIDTH 1 /* DAC_COMP */ | ||
395 | #define WM8903_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */ | ||
396 | #define WM8903_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */ | ||
397 | #define WM8903_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */ | ||
398 | #define WM8903_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ | ||
399 | |||
400 | /* | ||
401 | * R25 (0x19) - Audio Interface 1 | ||
402 | */ | ||
403 | #define WM8903_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
404 | #define WM8903_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */ | ||
405 | #define WM8903_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */ | ||
406 | #define WM8903_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */ | ||
407 | #define WM8903_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
408 | #define WM8903_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */ | ||
409 | #define WM8903_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */ | ||
410 | #define WM8903_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */ | ||
411 | #define WM8903_AIFADC_TDM 0x0800 /* AIFADC_TDM */ | ||
412 | #define WM8903_AIFADC_TDM_MASK 0x0800 /* AIFADC_TDM */ | ||
413 | #define WM8903_AIFADC_TDM_SHIFT 11 /* AIFADC_TDM */ | ||
414 | #define WM8903_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */ | ||
415 | #define WM8903_AIFADC_TDM_CHAN 0x0400 /* AIFADC_TDM_CHAN */ | ||
416 | #define WM8903_AIFADC_TDM_CHAN_MASK 0x0400 /* AIFADC_TDM_CHAN */ | ||
417 | #define WM8903_AIFADC_TDM_CHAN_SHIFT 10 /* AIFADC_TDM_CHAN */ | ||
418 | #define WM8903_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */ | ||
419 | #define WM8903_LRCLK_DIR 0x0200 /* LRCLK_DIR */ | ||
420 | #define WM8903_LRCLK_DIR_MASK 0x0200 /* LRCLK_DIR */ | ||
421 | #define WM8903_LRCLK_DIR_SHIFT 9 /* LRCLK_DIR */ | ||
422 | #define WM8903_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ | ||
423 | #define WM8903_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */ | ||
424 | #define WM8903_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */ | ||
425 | #define WM8903_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */ | ||
426 | #define WM8903_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ | ||
427 | #define WM8903_BCLK_DIR 0x0040 /* BCLK_DIR */ | ||
428 | #define WM8903_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */ | ||
429 | #define WM8903_BCLK_DIR_SHIFT 6 /* BCLK_DIR */ | ||
430 | #define WM8903_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ | ||
431 | #define WM8903_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */ | ||
432 | #define WM8903_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */ | ||
433 | #define WM8903_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */ | ||
434 | #define WM8903_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ | ||
435 | #define WM8903_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */ | ||
436 | #define WM8903_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */ | ||
437 | #define WM8903_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */ | ||
438 | #define WM8903_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */ | ||
439 | #define WM8903_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */ | ||
440 | #define WM8903_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */ | ||
441 | |||
442 | /* | ||
443 | * R26 (0x1A) - Audio Interface 2 | ||
444 | */ | ||
445 | #define WM8903_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */ | ||
446 | #define WM8903_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */ | ||
447 | #define WM8903_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */ | ||
448 | |||
449 | /* | ||
450 | * R27 (0x1B) - Audio Interface 3 | ||
451 | */ | ||
452 | #define WM8903_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ | ||
453 | #define WM8903_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ | ||
454 | #define WM8903_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ | ||
455 | |||
456 | /* | ||
457 | * R30 (0x1E) - DAC Digital Volume Left | ||
458 | */ | ||
459 | #define WM8903_DACVU 0x0100 /* DACVU */ | ||
460 | #define WM8903_DACVU_MASK 0x0100 /* DACVU */ | ||
461 | #define WM8903_DACVU_SHIFT 8 /* DACVU */ | ||
462 | #define WM8903_DACVU_WIDTH 1 /* DACVU */ | ||
463 | #define WM8903_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
464 | #define WM8903_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */ | ||
465 | #define WM8903_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */ | ||
466 | |||
467 | /* | ||
468 | * R31 (0x1F) - DAC Digital Volume Right | ||
469 | */ | ||
470 | #define WM8903_DACVU 0x0100 /* DACVU */ | ||
471 | #define WM8903_DACVU_MASK 0x0100 /* DACVU */ | ||
472 | #define WM8903_DACVU_SHIFT 8 /* DACVU */ | ||
473 | #define WM8903_DACVU_WIDTH 1 /* DACVU */ | ||
474 | #define WM8903_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
475 | #define WM8903_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */ | ||
476 | #define WM8903_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */ | ||
477 | |||
478 | /* | ||
479 | * R32 (0x20) - DAC Digital 0 | ||
480 | */ | ||
481 | #define WM8903_ADCL_DAC_SVOL_MASK 0x0F00 /* ADCL_DAC_SVOL - [11:8] */ | ||
482 | #define WM8903_ADCL_DAC_SVOL_SHIFT 8 /* ADCL_DAC_SVOL - [11:8] */ | ||
483 | #define WM8903_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [11:8] */ | ||
484 | #define WM8903_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */ | ||
485 | #define WM8903_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
486 | #define WM8903_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */ | ||
487 | #define WM8903_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */ | ||
488 | #define WM8903_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */ | ||
489 | #define WM8903_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */ | ||
490 | #define WM8903_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */ | ||
491 | #define WM8903_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */ | ||
492 | #define WM8903_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */ | ||
493 | |||
494 | /* | ||
495 | * R33 (0x21) - DAC Digital 1 | ||
496 | */ | ||
497 | #define WM8903_DAC_MONO 0x1000 /* DAC_MONO */ | ||
498 | #define WM8903_DAC_MONO_MASK 0x1000 /* DAC_MONO */ | ||
499 | #define WM8903_DAC_MONO_SHIFT 12 /* DAC_MONO */ | ||
500 | #define WM8903_DAC_MONO_WIDTH 1 /* DAC_MONO */ | ||
501 | #define WM8903_DAC_SB_FILT 0x0800 /* DAC_SB_FILT */ | ||
502 | #define WM8903_DAC_SB_FILT_MASK 0x0800 /* DAC_SB_FILT */ | ||
503 | #define WM8903_DAC_SB_FILT_SHIFT 11 /* DAC_SB_FILT */ | ||
504 | #define WM8903_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */ | ||
505 | #define WM8903_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */ | ||
506 | #define WM8903_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */ | ||
507 | #define WM8903_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */ | ||
508 | #define WM8903_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ | ||
509 | #define WM8903_DAC_MUTEMODE 0x0200 /* DAC_MUTEMODE */ | ||
510 | #define WM8903_DAC_MUTEMODE_MASK 0x0200 /* DAC_MUTEMODE */ | ||
511 | #define WM8903_DAC_MUTEMODE_SHIFT 9 /* DAC_MUTEMODE */ | ||
512 | #define WM8903_DAC_MUTEMODE_WIDTH 1 /* DAC_MUTEMODE */ | ||
513 | #define WM8903_DAC_MUTE 0x0008 /* DAC_MUTE */ | ||
514 | #define WM8903_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */ | ||
515 | #define WM8903_DAC_MUTE_SHIFT 3 /* DAC_MUTE */ | ||
516 | #define WM8903_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ | ||
517 | #define WM8903_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ | ||
518 | #define WM8903_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ | ||
519 | #define WM8903_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ | ||
520 | |||
521 | /* | ||
522 | * R36 (0x24) - ADC Digital Volume Left | ||
523 | */ | ||
524 | #define WM8903_ADCVU 0x0100 /* ADCVU */ | ||
525 | #define WM8903_ADCVU_MASK 0x0100 /* ADCVU */ | ||
526 | #define WM8903_ADCVU_SHIFT 8 /* ADCVU */ | ||
527 | #define WM8903_ADCVU_WIDTH 1 /* ADCVU */ | ||
528 | #define WM8903_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
529 | #define WM8903_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */ | ||
530 | #define WM8903_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */ | ||
531 | |||
532 | /* | ||
533 | * R37 (0x25) - ADC Digital Volume Right | ||
534 | */ | ||
535 | #define WM8903_ADCVU 0x0100 /* ADCVU */ | ||
536 | #define WM8903_ADCVU_MASK 0x0100 /* ADCVU */ | ||
537 | #define WM8903_ADCVU_SHIFT 8 /* ADCVU */ | ||
538 | #define WM8903_ADCVU_WIDTH 1 /* ADCVU */ | ||
539 | #define WM8903_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
540 | #define WM8903_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */ | ||
541 | #define WM8903_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */ | ||
542 | |||
543 | /* | ||
544 | * R38 (0x26) - ADC Digital 0 | ||
545 | */ | ||
546 | #define WM8903_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */ | ||
547 | #define WM8903_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */ | ||
548 | #define WM8903_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */ | ||
549 | #define WM8903_ADC_HPF_ENA 0x0010 /* ADC_HPF_ENA */ | ||
550 | #define WM8903_ADC_HPF_ENA_MASK 0x0010 /* ADC_HPF_ENA */ | ||
551 | #define WM8903_ADC_HPF_ENA_SHIFT 4 /* ADC_HPF_ENA */ | ||
552 | #define WM8903_ADC_HPF_ENA_WIDTH 1 /* ADC_HPF_ENA */ | ||
553 | #define WM8903_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
554 | #define WM8903_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */ | ||
555 | #define WM8903_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */ | ||
556 | #define WM8903_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */ | ||
557 | #define WM8903_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
558 | #define WM8903_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */ | ||
559 | #define WM8903_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */ | ||
560 | #define WM8903_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */ | ||
561 | |||
562 | /* | ||
563 | * R39 (0x27) - Digital Microphone 0 | ||
564 | */ | ||
565 | #define WM8903_DIGMIC_MODE_SEL 0x0100 /* DIGMIC_MODE_SEL */ | ||
566 | #define WM8903_DIGMIC_MODE_SEL_MASK 0x0100 /* DIGMIC_MODE_SEL */ | ||
567 | #define WM8903_DIGMIC_MODE_SEL_SHIFT 8 /* DIGMIC_MODE_SEL */ | ||
568 | #define WM8903_DIGMIC_MODE_SEL_WIDTH 1 /* DIGMIC_MODE_SEL */ | ||
569 | #define WM8903_DIGMIC_CLK_SEL_L_MASK 0x00C0 /* DIGMIC_CLK_SEL_L - [7:6] */ | ||
570 | #define WM8903_DIGMIC_CLK_SEL_L_SHIFT 6 /* DIGMIC_CLK_SEL_L - [7:6] */ | ||
571 | #define WM8903_DIGMIC_CLK_SEL_L_WIDTH 2 /* DIGMIC_CLK_SEL_L - [7:6] */ | ||
572 | #define WM8903_DIGMIC_CLK_SEL_R_MASK 0x0030 /* DIGMIC_CLK_SEL_R - [5:4] */ | ||
573 | #define WM8903_DIGMIC_CLK_SEL_R_SHIFT 4 /* DIGMIC_CLK_SEL_R - [5:4] */ | ||
574 | #define WM8903_DIGMIC_CLK_SEL_R_WIDTH 2 /* DIGMIC_CLK_SEL_R - [5:4] */ | ||
575 | #define WM8903_DIGMIC_CLK_SEL_RT_MASK 0x000C /* DIGMIC_CLK_SEL_RT - [3:2] */ | ||
576 | #define WM8903_DIGMIC_CLK_SEL_RT_SHIFT 2 /* DIGMIC_CLK_SEL_RT - [3:2] */ | ||
577 | #define WM8903_DIGMIC_CLK_SEL_RT_WIDTH 2 /* DIGMIC_CLK_SEL_RT - [3:2] */ | ||
578 | #define WM8903_DIGMIC_CLK_SEL_MASK 0x0003 /* DIGMIC_CLK_SEL - [1:0] */ | ||
579 | #define WM8903_DIGMIC_CLK_SEL_SHIFT 0 /* DIGMIC_CLK_SEL - [1:0] */ | ||
580 | #define WM8903_DIGMIC_CLK_SEL_WIDTH 2 /* DIGMIC_CLK_SEL - [1:0] */ | ||
581 | |||
582 | /* | ||
583 | * R40 (0x28) - DRC 0 | ||
584 | */ | ||
585 | #define WM8903_DRC_ENA 0x8000 /* DRC_ENA */ | ||
586 | #define WM8903_DRC_ENA_MASK 0x8000 /* DRC_ENA */ | ||
587 | #define WM8903_DRC_ENA_SHIFT 15 /* DRC_ENA */ | ||
588 | #define WM8903_DRC_ENA_WIDTH 1 /* DRC_ENA */ | ||
589 | #define WM8903_DRC_THRESH_HYST_MASK 0x1800 /* DRC_THRESH_HYST - [12:11] */ | ||
590 | #define WM8903_DRC_THRESH_HYST_SHIFT 11 /* DRC_THRESH_HYST - [12:11] */ | ||
591 | #define WM8903_DRC_THRESH_HYST_WIDTH 2 /* DRC_THRESH_HYST - [12:11] */ | ||
592 | #define WM8903_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */ | ||
593 | #define WM8903_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */ | ||
594 | #define WM8903_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */ | ||
595 | #define WM8903_DRC_FF_DELAY 0x0020 /* DRC_FF_DELAY */ | ||
596 | #define WM8903_DRC_FF_DELAY_MASK 0x0020 /* DRC_FF_DELAY */ | ||
597 | #define WM8903_DRC_FF_DELAY_SHIFT 5 /* DRC_FF_DELAY */ | ||
598 | #define WM8903_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */ | ||
599 | #define WM8903_DRC_SMOOTH_ENA 0x0008 /* DRC_SMOOTH_ENA */ | ||
600 | #define WM8903_DRC_SMOOTH_ENA_MASK 0x0008 /* DRC_SMOOTH_ENA */ | ||
601 | #define WM8903_DRC_SMOOTH_ENA_SHIFT 3 /* DRC_SMOOTH_ENA */ | ||
602 | #define WM8903_DRC_SMOOTH_ENA_WIDTH 1 /* DRC_SMOOTH_ENA */ | ||
603 | #define WM8903_DRC_QR_ENA 0x0004 /* DRC_QR_ENA */ | ||
604 | #define WM8903_DRC_QR_ENA_MASK 0x0004 /* DRC_QR_ENA */ | ||
605 | #define WM8903_DRC_QR_ENA_SHIFT 2 /* DRC_QR_ENA */ | ||
606 | #define WM8903_DRC_QR_ENA_WIDTH 1 /* DRC_QR_ENA */ | ||
607 | #define WM8903_DRC_ANTICLIP_ENA 0x0002 /* DRC_ANTICLIP_ENA */ | ||
608 | #define WM8903_DRC_ANTICLIP_ENA_MASK 0x0002 /* DRC_ANTICLIP_ENA */ | ||
609 | #define WM8903_DRC_ANTICLIP_ENA_SHIFT 1 /* DRC_ANTICLIP_ENA */ | ||
610 | #define WM8903_DRC_ANTICLIP_ENA_WIDTH 1 /* DRC_ANTICLIP_ENA */ | ||
611 | #define WM8903_DRC_HYST_ENA 0x0001 /* DRC_HYST_ENA */ | ||
612 | #define WM8903_DRC_HYST_ENA_MASK 0x0001 /* DRC_HYST_ENA */ | ||
613 | #define WM8903_DRC_HYST_ENA_SHIFT 0 /* DRC_HYST_ENA */ | ||
614 | #define WM8903_DRC_HYST_ENA_WIDTH 1 /* DRC_HYST_ENA */ | ||
615 | |||
616 | /* | ||
617 | * R41 (0x29) - DRC 1 | ||
618 | */ | ||
619 | #define WM8903_DRC_ATTACK_RATE_MASK 0xF000 /* DRC_ATTACK_RATE - [15:12] */ | ||
620 | #define WM8903_DRC_ATTACK_RATE_SHIFT 12 /* DRC_ATTACK_RATE - [15:12] */ | ||
621 | #define WM8903_DRC_ATTACK_RATE_WIDTH 4 /* DRC_ATTACK_RATE - [15:12] */ | ||
622 | #define WM8903_DRC_DECAY_RATE_MASK 0x0F00 /* DRC_DECAY_RATE - [11:8] */ | ||
623 | #define WM8903_DRC_DECAY_RATE_SHIFT 8 /* DRC_DECAY_RATE - [11:8] */ | ||
624 | #define WM8903_DRC_DECAY_RATE_WIDTH 4 /* DRC_DECAY_RATE - [11:8] */ | ||
625 | #define WM8903_DRC_THRESH_QR_MASK 0x00C0 /* DRC_THRESH_QR - [7:6] */ | ||
626 | #define WM8903_DRC_THRESH_QR_SHIFT 6 /* DRC_THRESH_QR - [7:6] */ | ||
627 | #define WM8903_DRC_THRESH_QR_WIDTH 2 /* DRC_THRESH_QR - [7:6] */ | ||
628 | #define WM8903_DRC_RATE_QR_MASK 0x0030 /* DRC_RATE_QR - [5:4] */ | ||
629 | #define WM8903_DRC_RATE_QR_SHIFT 4 /* DRC_RATE_QR - [5:4] */ | ||
630 | #define WM8903_DRC_RATE_QR_WIDTH 2 /* DRC_RATE_QR - [5:4] */ | ||
631 | #define WM8903_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ | ||
632 | #define WM8903_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ | ||
633 | #define WM8903_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ | ||
634 | #define WM8903_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ | ||
635 | #define WM8903_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ | ||
636 | #define WM8903_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ | ||
637 | |||
638 | /* | ||
639 | * R42 (0x2A) - DRC 2 | ||
640 | */ | ||
641 | #define WM8903_DRC_R0_SLOPE_COMP_MASK 0x0038 /* DRC_R0_SLOPE_COMP - [5:3] */ | ||
642 | #define WM8903_DRC_R0_SLOPE_COMP_SHIFT 3 /* DRC_R0_SLOPE_COMP - [5:3] */ | ||
643 | #define WM8903_DRC_R0_SLOPE_COMP_WIDTH 3 /* DRC_R0_SLOPE_COMP - [5:3] */ | ||
644 | #define WM8903_DRC_R1_SLOPE_COMP_MASK 0x0007 /* DRC_R1_SLOPE_COMP - [2:0] */ | ||
645 | #define WM8903_DRC_R1_SLOPE_COMP_SHIFT 0 /* DRC_R1_SLOPE_COMP - [2:0] */ | ||
646 | #define WM8903_DRC_R1_SLOPE_COMP_WIDTH 3 /* DRC_R1_SLOPE_COMP - [2:0] */ | ||
647 | |||
648 | /* | ||
649 | * R43 (0x2B) - DRC 3 | ||
650 | */ | ||
651 | #define WM8903_DRC_THRESH_COMP_MASK 0x07E0 /* DRC_THRESH_COMP - [10:5] */ | ||
652 | #define WM8903_DRC_THRESH_COMP_SHIFT 5 /* DRC_THRESH_COMP - [10:5] */ | ||
653 | #define WM8903_DRC_THRESH_COMP_WIDTH 6 /* DRC_THRESH_COMP - [10:5] */ | ||
654 | #define WM8903_DRC_AMP_COMP_MASK 0x001F /* DRC_AMP_COMP - [4:0] */ | ||
655 | #define WM8903_DRC_AMP_COMP_SHIFT 0 /* DRC_AMP_COMP - [4:0] */ | ||
656 | #define WM8903_DRC_AMP_COMP_WIDTH 5 /* DRC_AMP_COMP - [4:0] */ | ||
657 | |||
658 | /* | ||
659 | * R44 (0x2C) - Analogue Left Input 0 | ||
660 | */ | ||
661 | #define WM8903_LINMUTE 0x0080 /* LINMUTE */ | ||
662 | #define WM8903_LINMUTE_MASK 0x0080 /* LINMUTE */ | ||
663 | #define WM8903_LINMUTE_SHIFT 7 /* LINMUTE */ | ||
664 | #define WM8903_LINMUTE_WIDTH 1 /* LINMUTE */ | ||
665 | #define WM8903_LIN_VOL_MASK 0x001F /* LIN_VOL - [4:0] */ | ||
666 | #define WM8903_LIN_VOL_SHIFT 0 /* LIN_VOL - [4:0] */ | ||
667 | #define WM8903_LIN_VOL_WIDTH 5 /* LIN_VOL - [4:0] */ | ||
668 | |||
669 | /* | ||
670 | * R45 (0x2D) - Analogue Right Input 0 | ||
671 | */ | ||
672 | #define WM8903_RINMUTE 0x0080 /* RINMUTE */ | ||
673 | #define WM8903_RINMUTE_MASK 0x0080 /* RINMUTE */ | ||
674 | #define WM8903_RINMUTE_SHIFT 7 /* RINMUTE */ | ||
675 | #define WM8903_RINMUTE_WIDTH 1 /* RINMUTE */ | ||
676 | #define WM8903_RIN_VOL_MASK 0x001F /* RIN_VOL - [4:0] */ | ||
677 | #define WM8903_RIN_VOL_SHIFT 0 /* RIN_VOL - [4:0] */ | ||
678 | #define WM8903_RIN_VOL_WIDTH 5 /* RIN_VOL - [4:0] */ | ||
679 | |||
680 | /* | ||
681 | * R46 (0x2E) - Analogue Left Input 1 | ||
682 | */ | ||
683 | #define WM8903_INL_CM_ENA 0x0040 /* INL_CM_ENA */ | ||
684 | #define WM8903_INL_CM_ENA_MASK 0x0040 /* INL_CM_ENA */ | ||
685 | #define WM8903_INL_CM_ENA_SHIFT 6 /* INL_CM_ENA */ | ||
686 | #define WM8903_INL_CM_ENA_WIDTH 1 /* INL_CM_ENA */ | ||
687 | #define WM8903_L_IP_SEL_N_MASK 0x0030 /* L_IP_SEL_N - [5:4] */ | ||
688 | #define WM8903_L_IP_SEL_N_SHIFT 4 /* L_IP_SEL_N - [5:4] */ | ||
689 | #define WM8903_L_IP_SEL_N_WIDTH 2 /* L_IP_SEL_N - [5:4] */ | ||
690 | #define WM8903_L_IP_SEL_P_MASK 0x000C /* L_IP_SEL_P - [3:2] */ | ||
691 | #define WM8903_L_IP_SEL_P_SHIFT 2 /* L_IP_SEL_P - [3:2] */ | ||
692 | #define WM8903_L_IP_SEL_P_WIDTH 2 /* L_IP_SEL_P - [3:2] */ | ||
693 | #define WM8903_L_MODE_MASK 0x0003 /* L_MODE - [1:0] */ | ||
694 | #define WM8903_L_MODE_SHIFT 0 /* L_MODE - [1:0] */ | ||
695 | #define WM8903_L_MODE_WIDTH 2 /* L_MODE - [1:0] */ | ||
696 | |||
697 | /* | ||
698 | * R47 (0x2F) - Analogue Right Input 1 | ||
699 | */ | ||
700 | #define WM8903_INR_CM_ENA 0x0040 /* INR_CM_ENA */ | ||
701 | #define WM8903_INR_CM_ENA_MASK 0x0040 /* INR_CM_ENA */ | ||
702 | #define WM8903_INR_CM_ENA_SHIFT 6 /* INR_CM_ENA */ | ||
703 | #define WM8903_INR_CM_ENA_WIDTH 1 /* INR_CM_ENA */ | ||
704 | #define WM8903_R_IP_SEL_N_MASK 0x0030 /* R_IP_SEL_N - [5:4] */ | ||
705 | #define WM8903_R_IP_SEL_N_SHIFT 4 /* R_IP_SEL_N - [5:4] */ | ||
706 | #define WM8903_R_IP_SEL_N_WIDTH 2 /* R_IP_SEL_N - [5:4] */ | ||
707 | #define WM8903_R_IP_SEL_P_MASK 0x000C /* R_IP_SEL_P - [3:2] */ | ||
708 | #define WM8903_R_IP_SEL_P_SHIFT 2 /* R_IP_SEL_P - [3:2] */ | ||
709 | #define WM8903_R_IP_SEL_P_WIDTH 2 /* R_IP_SEL_P - [3:2] */ | ||
710 | #define WM8903_R_MODE_MASK 0x0003 /* R_MODE - [1:0] */ | ||
711 | #define WM8903_R_MODE_SHIFT 0 /* R_MODE - [1:0] */ | ||
712 | #define WM8903_R_MODE_WIDTH 2 /* R_MODE - [1:0] */ | ||
713 | |||
714 | /* | ||
715 | * R50 (0x32) - Analogue Left Mix 0 | ||
716 | */ | ||
717 | #define WM8903_DACL_TO_MIXOUTL 0x0008 /* DACL_TO_MIXOUTL */ | ||
718 | #define WM8903_DACL_TO_MIXOUTL_MASK 0x0008 /* DACL_TO_MIXOUTL */ | ||
719 | #define WM8903_DACL_TO_MIXOUTL_SHIFT 3 /* DACL_TO_MIXOUTL */ | ||
720 | #define WM8903_DACL_TO_MIXOUTL_WIDTH 1 /* DACL_TO_MIXOUTL */ | ||
721 | #define WM8903_DACR_TO_MIXOUTL 0x0004 /* DACR_TO_MIXOUTL */ | ||
722 | #define WM8903_DACR_TO_MIXOUTL_MASK 0x0004 /* DACR_TO_MIXOUTL */ | ||
723 | #define WM8903_DACR_TO_MIXOUTL_SHIFT 2 /* DACR_TO_MIXOUTL */ | ||
724 | #define WM8903_DACR_TO_MIXOUTL_WIDTH 1 /* DACR_TO_MIXOUTL */ | ||
725 | #define WM8903_BYPASSL_TO_MIXOUTL 0x0002 /* BYPASSL_TO_MIXOUTL */ | ||
726 | #define WM8903_BYPASSL_TO_MIXOUTL_MASK 0x0002 /* BYPASSL_TO_MIXOUTL */ | ||
727 | #define WM8903_BYPASSL_TO_MIXOUTL_SHIFT 1 /* BYPASSL_TO_MIXOUTL */ | ||
728 | #define WM8903_BYPASSL_TO_MIXOUTL_WIDTH 1 /* BYPASSL_TO_MIXOUTL */ | ||
729 | #define WM8903_BYPASSR_TO_MIXOUTL 0x0001 /* BYPASSR_TO_MIXOUTL */ | ||
730 | #define WM8903_BYPASSR_TO_MIXOUTL_MASK 0x0001 /* BYPASSR_TO_MIXOUTL */ | ||
731 | #define WM8903_BYPASSR_TO_MIXOUTL_SHIFT 0 /* BYPASSR_TO_MIXOUTL */ | ||
732 | #define WM8903_BYPASSR_TO_MIXOUTL_WIDTH 1 /* BYPASSR_TO_MIXOUTL */ | ||
733 | |||
734 | /* | ||
735 | * R51 (0x33) - Analogue Right Mix 0 | ||
736 | */ | ||
737 | #define WM8903_DACL_TO_MIXOUTR 0x0008 /* DACL_TO_MIXOUTR */ | ||
738 | #define WM8903_DACL_TO_MIXOUTR_MASK 0x0008 /* DACL_TO_MIXOUTR */ | ||
739 | #define WM8903_DACL_TO_MIXOUTR_SHIFT 3 /* DACL_TO_MIXOUTR */ | ||
740 | #define WM8903_DACL_TO_MIXOUTR_WIDTH 1 /* DACL_TO_MIXOUTR */ | ||
741 | #define WM8903_DACR_TO_MIXOUTR 0x0004 /* DACR_TO_MIXOUTR */ | ||
742 | #define WM8903_DACR_TO_MIXOUTR_MASK 0x0004 /* DACR_TO_MIXOUTR */ | ||
743 | #define WM8903_DACR_TO_MIXOUTR_SHIFT 2 /* DACR_TO_MIXOUTR */ | ||
744 | #define WM8903_DACR_TO_MIXOUTR_WIDTH 1 /* DACR_TO_MIXOUTR */ | ||
745 | #define WM8903_BYPASSL_TO_MIXOUTR 0x0002 /* BYPASSL_TO_MIXOUTR */ | ||
746 | #define WM8903_BYPASSL_TO_MIXOUTR_MASK 0x0002 /* BYPASSL_TO_MIXOUTR */ | ||
747 | #define WM8903_BYPASSL_TO_MIXOUTR_SHIFT 1 /* BYPASSL_TO_MIXOUTR */ | ||
748 | #define WM8903_BYPASSL_TO_MIXOUTR_WIDTH 1 /* BYPASSL_TO_MIXOUTR */ | ||
749 | #define WM8903_BYPASSR_TO_MIXOUTR 0x0001 /* BYPASSR_TO_MIXOUTR */ | ||
750 | #define WM8903_BYPASSR_TO_MIXOUTR_MASK 0x0001 /* BYPASSR_TO_MIXOUTR */ | ||
751 | #define WM8903_BYPASSR_TO_MIXOUTR_SHIFT 0 /* BYPASSR_TO_MIXOUTR */ | ||
752 | #define WM8903_BYPASSR_TO_MIXOUTR_WIDTH 1 /* BYPASSR_TO_MIXOUTR */ | ||
753 | |||
754 | /* | ||
755 | * R52 (0x34) - Analogue Spk Mix Left 0 | ||
756 | */ | ||
757 | #define WM8903_DACL_TO_MIXSPKL 0x0008 /* DACL_TO_MIXSPKL */ | ||
758 | #define WM8903_DACL_TO_MIXSPKL_MASK 0x0008 /* DACL_TO_MIXSPKL */ | ||
759 | #define WM8903_DACL_TO_MIXSPKL_SHIFT 3 /* DACL_TO_MIXSPKL */ | ||
760 | #define WM8903_DACL_TO_MIXSPKL_WIDTH 1 /* DACL_TO_MIXSPKL */ | ||
761 | #define WM8903_DACR_TO_MIXSPKL 0x0004 /* DACR_TO_MIXSPKL */ | ||
762 | #define WM8903_DACR_TO_MIXSPKL_MASK 0x0004 /* DACR_TO_MIXSPKL */ | ||
763 | #define WM8903_DACR_TO_MIXSPKL_SHIFT 2 /* DACR_TO_MIXSPKL */ | ||
764 | #define WM8903_DACR_TO_MIXSPKL_WIDTH 1 /* DACR_TO_MIXSPKL */ | ||
765 | #define WM8903_BYPASSL_TO_MIXSPKL 0x0002 /* BYPASSL_TO_MIXSPKL */ | ||
766 | #define WM8903_BYPASSL_TO_MIXSPKL_MASK 0x0002 /* BYPASSL_TO_MIXSPKL */ | ||
767 | #define WM8903_BYPASSL_TO_MIXSPKL_SHIFT 1 /* BYPASSL_TO_MIXSPKL */ | ||
768 | #define WM8903_BYPASSL_TO_MIXSPKL_WIDTH 1 /* BYPASSL_TO_MIXSPKL */ | ||
769 | #define WM8903_BYPASSR_TO_MIXSPKL 0x0001 /* BYPASSR_TO_MIXSPKL */ | ||
770 | #define WM8903_BYPASSR_TO_MIXSPKL_MASK 0x0001 /* BYPASSR_TO_MIXSPKL */ | ||
771 | #define WM8903_BYPASSR_TO_MIXSPKL_SHIFT 0 /* BYPASSR_TO_MIXSPKL */ | ||
772 | #define WM8903_BYPASSR_TO_MIXSPKL_WIDTH 1 /* BYPASSR_TO_MIXSPKL */ | ||
773 | |||
774 | /* | ||
775 | * R53 (0x35) - Analogue Spk Mix Left 1 | ||
776 | */ | ||
777 | #define WM8903_DACL_MIXSPKL_VOL 0x0008 /* DACL_MIXSPKL_VOL */ | ||
778 | #define WM8903_DACL_MIXSPKL_VOL_MASK 0x0008 /* DACL_MIXSPKL_VOL */ | ||
779 | #define WM8903_DACL_MIXSPKL_VOL_SHIFT 3 /* DACL_MIXSPKL_VOL */ | ||
780 | #define WM8903_DACL_MIXSPKL_VOL_WIDTH 1 /* DACL_MIXSPKL_VOL */ | ||
781 | #define WM8903_DACR_MIXSPKL_VOL 0x0004 /* DACR_MIXSPKL_VOL */ | ||
782 | #define WM8903_DACR_MIXSPKL_VOL_MASK 0x0004 /* DACR_MIXSPKL_VOL */ | ||
783 | #define WM8903_DACR_MIXSPKL_VOL_SHIFT 2 /* DACR_MIXSPKL_VOL */ | ||
784 | #define WM8903_DACR_MIXSPKL_VOL_WIDTH 1 /* DACR_MIXSPKL_VOL */ | ||
785 | #define WM8903_BYPASSL_MIXSPKL_VOL 0x0002 /* BYPASSL_MIXSPKL_VOL */ | ||
786 | #define WM8903_BYPASSL_MIXSPKL_VOL_MASK 0x0002 /* BYPASSL_MIXSPKL_VOL */ | ||
787 | #define WM8903_BYPASSL_MIXSPKL_VOL_SHIFT 1 /* BYPASSL_MIXSPKL_VOL */ | ||
788 | #define WM8903_BYPASSL_MIXSPKL_VOL_WIDTH 1 /* BYPASSL_MIXSPKL_VOL */ | ||
789 | #define WM8903_BYPASSR_MIXSPKL_VOL 0x0001 /* BYPASSR_MIXSPKL_VOL */ | ||
790 | #define WM8903_BYPASSR_MIXSPKL_VOL_MASK 0x0001 /* BYPASSR_MIXSPKL_VOL */ | ||
791 | #define WM8903_BYPASSR_MIXSPKL_VOL_SHIFT 0 /* BYPASSR_MIXSPKL_VOL */ | ||
792 | #define WM8903_BYPASSR_MIXSPKL_VOL_WIDTH 1 /* BYPASSR_MIXSPKL_VOL */ | ||
793 | |||
794 | /* | ||
795 | * R54 (0x36) - Analogue Spk Mix Right 0 | ||
796 | */ | ||
797 | #define WM8903_DACL_TO_MIXSPKR 0x0008 /* DACL_TO_MIXSPKR */ | ||
798 | #define WM8903_DACL_TO_MIXSPKR_MASK 0x0008 /* DACL_TO_MIXSPKR */ | ||
799 | #define WM8903_DACL_TO_MIXSPKR_SHIFT 3 /* DACL_TO_MIXSPKR */ | ||
800 | #define WM8903_DACL_TO_MIXSPKR_WIDTH 1 /* DACL_TO_MIXSPKR */ | ||
801 | #define WM8903_DACR_TO_MIXSPKR 0x0004 /* DACR_TO_MIXSPKR */ | ||
802 | #define WM8903_DACR_TO_MIXSPKR_MASK 0x0004 /* DACR_TO_MIXSPKR */ | ||
803 | #define WM8903_DACR_TO_MIXSPKR_SHIFT 2 /* DACR_TO_MIXSPKR */ | ||
804 | #define WM8903_DACR_TO_MIXSPKR_WIDTH 1 /* DACR_TO_MIXSPKR */ | ||
805 | #define WM8903_BYPASSL_TO_MIXSPKR 0x0002 /* BYPASSL_TO_MIXSPKR */ | ||
806 | #define WM8903_BYPASSL_TO_MIXSPKR_MASK 0x0002 /* BYPASSL_TO_MIXSPKR */ | ||
807 | #define WM8903_BYPASSL_TO_MIXSPKR_SHIFT 1 /* BYPASSL_TO_MIXSPKR */ | ||
808 | #define WM8903_BYPASSL_TO_MIXSPKR_WIDTH 1 /* BYPASSL_TO_MIXSPKR */ | ||
809 | #define WM8903_BYPASSR_TO_MIXSPKR 0x0001 /* BYPASSR_TO_MIXSPKR */ | ||
810 | #define WM8903_BYPASSR_TO_MIXSPKR_MASK 0x0001 /* BYPASSR_TO_MIXSPKR */ | ||
811 | #define WM8903_BYPASSR_TO_MIXSPKR_SHIFT 0 /* BYPASSR_TO_MIXSPKR */ | ||
812 | #define WM8903_BYPASSR_TO_MIXSPKR_WIDTH 1 /* BYPASSR_TO_MIXSPKR */ | ||
813 | |||
814 | /* | ||
815 | * R55 (0x37) - Analogue Spk Mix Right 1 | ||
816 | */ | ||
817 | #define WM8903_DACL_MIXSPKR_VOL 0x0008 /* DACL_MIXSPKR_VOL */ | ||
818 | #define WM8903_DACL_MIXSPKR_VOL_MASK 0x0008 /* DACL_MIXSPKR_VOL */ | ||
819 | #define WM8903_DACL_MIXSPKR_VOL_SHIFT 3 /* DACL_MIXSPKR_VOL */ | ||
820 | #define WM8903_DACL_MIXSPKR_VOL_WIDTH 1 /* DACL_MIXSPKR_VOL */ | ||
821 | #define WM8903_DACR_MIXSPKR_VOL 0x0004 /* DACR_MIXSPKR_VOL */ | ||
822 | #define WM8903_DACR_MIXSPKR_VOL_MASK 0x0004 /* DACR_MIXSPKR_VOL */ | ||
823 | #define WM8903_DACR_MIXSPKR_VOL_SHIFT 2 /* DACR_MIXSPKR_VOL */ | ||
824 | #define WM8903_DACR_MIXSPKR_VOL_WIDTH 1 /* DACR_MIXSPKR_VOL */ | ||
825 | #define WM8903_BYPASSL_MIXSPKR_VOL 0x0002 /* BYPASSL_MIXSPKR_VOL */ | ||
826 | #define WM8903_BYPASSL_MIXSPKR_VOL_MASK 0x0002 /* BYPASSL_MIXSPKR_VOL */ | ||
827 | #define WM8903_BYPASSL_MIXSPKR_VOL_SHIFT 1 /* BYPASSL_MIXSPKR_VOL */ | ||
828 | #define WM8903_BYPASSL_MIXSPKR_VOL_WIDTH 1 /* BYPASSL_MIXSPKR_VOL */ | ||
829 | #define WM8903_BYPASSR_MIXSPKR_VOL 0x0001 /* BYPASSR_MIXSPKR_VOL */ | ||
830 | #define WM8903_BYPASSR_MIXSPKR_VOL_MASK 0x0001 /* BYPASSR_MIXSPKR_VOL */ | ||
831 | #define WM8903_BYPASSR_MIXSPKR_VOL_SHIFT 0 /* BYPASSR_MIXSPKR_VOL */ | ||
832 | #define WM8903_BYPASSR_MIXSPKR_VOL_WIDTH 1 /* BYPASSR_MIXSPKR_VOL */ | ||
833 | |||
834 | /* | ||
835 | * R57 (0x39) - Analogue OUT1 Left | ||
836 | */ | ||
837 | #define WM8903_HPL_MUTE 0x0100 /* HPL_MUTE */ | ||
838 | #define WM8903_HPL_MUTE_MASK 0x0100 /* HPL_MUTE */ | ||
839 | #define WM8903_HPL_MUTE_SHIFT 8 /* HPL_MUTE */ | ||
840 | #define WM8903_HPL_MUTE_WIDTH 1 /* HPL_MUTE */ | ||
841 | #define WM8903_HPOUTVU 0x0080 /* HPOUTVU */ | ||
842 | #define WM8903_HPOUTVU_MASK 0x0080 /* HPOUTVU */ | ||
843 | #define WM8903_HPOUTVU_SHIFT 7 /* HPOUTVU */ | ||
844 | #define WM8903_HPOUTVU_WIDTH 1 /* HPOUTVU */ | ||
845 | #define WM8903_HPOUTLZC 0x0040 /* HPOUTLZC */ | ||
846 | #define WM8903_HPOUTLZC_MASK 0x0040 /* HPOUTLZC */ | ||
847 | #define WM8903_HPOUTLZC_SHIFT 6 /* HPOUTLZC */ | ||
848 | #define WM8903_HPOUTLZC_WIDTH 1 /* HPOUTLZC */ | ||
849 | #define WM8903_HPOUTL_VOL_MASK 0x003F /* HPOUTL_VOL - [5:0] */ | ||
850 | #define WM8903_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [5:0] */ | ||
851 | #define WM8903_HPOUTL_VOL_WIDTH 6 /* HPOUTL_VOL - [5:0] */ | ||
852 | |||
853 | /* | ||
854 | * R58 (0x3A) - Analogue OUT1 Right | ||
855 | */ | ||
856 | #define WM8903_HPR_MUTE 0x0100 /* HPR_MUTE */ | ||
857 | #define WM8903_HPR_MUTE_MASK 0x0100 /* HPR_MUTE */ | ||
858 | #define WM8903_HPR_MUTE_SHIFT 8 /* HPR_MUTE */ | ||
859 | #define WM8903_HPR_MUTE_WIDTH 1 /* HPR_MUTE */ | ||
860 | #define WM8903_HPOUTVU 0x0080 /* HPOUTVU */ | ||
861 | #define WM8903_HPOUTVU_MASK 0x0080 /* HPOUTVU */ | ||
862 | #define WM8903_HPOUTVU_SHIFT 7 /* HPOUTVU */ | ||
863 | #define WM8903_HPOUTVU_WIDTH 1 /* HPOUTVU */ | ||
864 | #define WM8903_HPOUTRZC 0x0040 /* HPOUTRZC */ | ||
865 | #define WM8903_HPOUTRZC_MASK 0x0040 /* HPOUTRZC */ | ||
866 | #define WM8903_HPOUTRZC_SHIFT 6 /* HPOUTRZC */ | ||
867 | #define WM8903_HPOUTRZC_WIDTH 1 /* HPOUTRZC */ | ||
868 | #define WM8903_HPOUTR_VOL_MASK 0x003F /* HPOUTR_VOL - [5:0] */ | ||
869 | #define WM8903_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [5:0] */ | ||
870 | #define WM8903_HPOUTR_VOL_WIDTH 6 /* HPOUTR_VOL - [5:0] */ | ||
871 | |||
872 | /* | ||
873 | * R59 (0x3B) - Analogue OUT2 Left | ||
874 | */ | ||
875 | #define WM8903_LINEOUTL_MUTE 0x0100 /* LINEOUTL_MUTE */ | ||
876 | #define WM8903_LINEOUTL_MUTE_MASK 0x0100 /* LINEOUTL_MUTE */ | ||
877 | #define WM8903_LINEOUTL_MUTE_SHIFT 8 /* LINEOUTL_MUTE */ | ||
878 | #define WM8903_LINEOUTL_MUTE_WIDTH 1 /* LINEOUTL_MUTE */ | ||
879 | #define WM8903_LINEOUTVU 0x0080 /* LINEOUTVU */ | ||
880 | #define WM8903_LINEOUTVU_MASK 0x0080 /* LINEOUTVU */ | ||
881 | #define WM8903_LINEOUTVU_SHIFT 7 /* LINEOUTVU */ | ||
882 | #define WM8903_LINEOUTVU_WIDTH 1 /* LINEOUTVU */ | ||
883 | #define WM8903_LINEOUTLZC 0x0040 /* LINEOUTLZC */ | ||
884 | #define WM8903_LINEOUTLZC_MASK 0x0040 /* LINEOUTLZC */ | ||
885 | #define WM8903_LINEOUTLZC_SHIFT 6 /* LINEOUTLZC */ | ||
886 | #define WM8903_LINEOUTLZC_WIDTH 1 /* LINEOUTLZC */ | ||
887 | #define WM8903_LINEOUTL_VOL_MASK 0x003F /* LINEOUTL_VOL - [5:0] */ | ||
888 | #define WM8903_LINEOUTL_VOL_SHIFT 0 /* LINEOUTL_VOL - [5:0] */ | ||
889 | #define WM8903_LINEOUTL_VOL_WIDTH 6 /* LINEOUTL_VOL - [5:0] */ | ||
890 | |||
891 | /* | ||
892 | * R60 (0x3C) - Analogue OUT2 Right | ||
893 | */ | ||
894 | #define WM8903_LINEOUTR_MUTE 0x0100 /* LINEOUTR_MUTE */ | ||
895 | #define WM8903_LINEOUTR_MUTE_MASK 0x0100 /* LINEOUTR_MUTE */ | ||
896 | #define WM8903_LINEOUTR_MUTE_SHIFT 8 /* LINEOUTR_MUTE */ | ||
897 | #define WM8903_LINEOUTR_MUTE_WIDTH 1 /* LINEOUTR_MUTE */ | ||
898 | #define WM8903_LINEOUTVU 0x0080 /* LINEOUTVU */ | ||
899 | #define WM8903_LINEOUTVU_MASK 0x0080 /* LINEOUTVU */ | ||
900 | #define WM8903_LINEOUTVU_SHIFT 7 /* LINEOUTVU */ | ||
901 | #define WM8903_LINEOUTVU_WIDTH 1 /* LINEOUTVU */ | ||
902 | #define WM8903_LINEOUTRZC 0x0040 /* LINEOUTRZC */ | ||
903 | #define WM8903_LINEOUTRZC_MASK 0x0040 /* LINEOUTRZC */ | ||
904 | #define WM8903_LINEOUTRZC_SHIFT 6 /* LINEOUTRZC */ | ||
905 | #define WM8903_LINEOUTRZC_WIDTH 1 /* LINEOUTRZC */ | ||
906 | #define WM8903_LINEOUTR_VOL_MASK 0x003F /* LINEOUTR_VOL - [5:0] */ | ||
907 | #define WM8903_LINEOUTR_VOL_SHIFT 0 /* LINEOUTR_VOL - [5:0] */ | ||
908 | #define WM8903_LINEOUTR_VOL_WIDTH 6 /* LINEOUTR_VOL - [5:0] */ | ||
909 | |||
910 | /* | ||
911 | * R62 (0x3E) - Analogue OUT3 Left | ||
912 | */ | ||
913 | #define WM8903_SPKL_MUTE 0x0100 /* SPKL_MUTE */ | ||
914 | #define WM8903_SPKL_MUTE_MASK 0x0100 /* SPKL_MUTE */ | ||
915 | #define WM8903_SPKL_MUTE_SHIFT 8 /* SPKL_MUTE */ | ||
916 | #define WM8903_SPKL_MUTE_WIDTH 1 /* SPKL_MUTE */ | ||
917 | #define WM8903_SPKVU 0x0080 /* SPKVU */ | ||
918 | #define WM8903_SPKVU_MASK 0x0080 /* SPKVU */ | ||
919 | #define WM8903_SPKVU_SHIFT 7 /* SPKVU */ | ||
920 | #define WM8903_SPKVU_WIDTH 1 /* SPKVU */ | ||
921 | #define WM8903_SPKLZC 0x0040 /* SPKLZC */ | ||
922 | #define WM8903_SPKLZC_MASK 0x0040 /* SPKLZC */ | ||
923 | #define WM8903_SPKLZC_SHIFT 6 /* SPKLZC */ | ||
924 | #define WM8903_SPKLZC_WIDTH 1 /* SPKLZC */ | ||
925 | #define WM8903_SPKL_VOL_MASK 0x003F /* SPKL_VOL - [5:0] */ | ||
926 | #define WM8903_SPKL_VOL_SHIFT 0 /* SPKL_VOL - [5:0] */ | ||
927 | #define WM8903_SPKL_VOL_WIDTH 6 /* SPKL_VOL - [5:0] */ | ||
928 | |||
929 | /* | ||
930 | * R63 (0x3F) - Analogue OUT3 Right | ||
931 | */ | ||
932 | #define WM8903_SPKR_MUTE 0x0100 /* SPKR_MUTE */ | ||
933 | #define WM8903_SPKR_MUTE_MASK 0x0100 /* SPKR_MUTE */ | ||
934 | #define WM8903_SPKR_MUTE_SHIFT 8 /* SPKR_MUTE */ | ||
935 | #define WM8903_SPKR_MUTE_WIDTH 1 /* SPKR_MUTE */ | ||
936 | #define WM8903_SPKVU 0x0080 /* SPKVU */ | ||
937 | #define WM8903_SPKVU_MASK 0x0080 /* SPKVU */ | ||
938 | #define WM8903_SPKVU_SHIFT 7 /* SPKVU */ | ||
939 | #define WM8903_SPKVU_WIDTH 1 /* SPKVU */ | ||
940 | #define WM8903_SPKRZC 0x0040 /* SPKRZC */ | ||
941 | #define WM8903_SPKRZC_MASK 0x0040 /* SPKRZC */ | ||
942 | #define WM8903_SPKRZC_SHIFT 6 /* SPKRZC */ | ||
943 | #define WM8903_SPKRZC_WIDTH 1 /* SPKRZC */ | ||
944 | #define WM8903_SPKR_VOL_MASK 0x003F /* SPKR_VOL - [5:0] */ | ||
945 | #define WM8903_SPKR_VOL_SHIFT 0 /* SPKR_VOL - [5:0] */ | ||
946 | #define WM8903_SPKR_VOL_WIDTH 6 /* SPKR_VOL - [5:0] */ | ||
947 | |||
948 | /* | ||
949 | * R65 (0x41) - Analogue SPK Output Control 0 | ||
950 | */ | ||
951 | #define WM8903_SPK_DISCHARGE 0x0002 /* SPK_DISCHARGE */ | ||
952 | #define WM8903_SPK_DISCHARGE_MASK 0x0002 /* SPK_DISCHARGE */ | ||
953 | #define WM8903_SPK_DISCHARGE_SHIFT 1 /* SPK_DISCHARGE */ | ||
954 | #define WM8903_SPK_DISCHARGE_WIDTH 1 /* SPK_DISCHARGE */ | ||
955 | #define WM8903_VROI 0x0001 /* VROI */ | ||
956 | #define WM8903_VROI_MASK 0x0001 /* VROI */ | ||
957 | #define WM8903_VROI_SHIFT 0 /* VROI */ | ||
958 | #define WM8903_VROI_WIDTH 1 /* VROI */ | ||
959 | |||
960 | /* | ||
961 | * R67 (0x43) - DC Servo 0 | ||
962 | */ | ||
963 | #define WM8903_DCS_MASTER_ENA 0x0010 /* DCS_MASTER_ENA */ | ||
964 | #define WM8903_DCS_MASTER_ENA_MASK 0x0010 /* DCS_MASTER_ENA */ | ||
965 | #define WM8903_DCS_MASTER_ENA_SHIFT 4 /* DCS_MASTER_ENA */ | ||
966 | #define WM8903_DCS_MASTER_ENA_WIDTH 1 /* DCS_MASTER_ENA */ | ||
967 | #define WM8903_DCS_ENA_MASK 0x000F /* DCS_ENA - [3:0] */ | ||
968 | #define WM8903_DCS_ENA_SHIFT 0 /* DCS_ENA - [3:0] */ | ||
969 | #define WM8903_DCS_ENA_WIDTH 4 /* DCS_ENA - [3:0] */ | ||
970 | |||
971 | /* | ||
972 | * R69 (0x45) - DC Servo 2 | ||
973 | */ | ||
974 | #define WM8903_DCS_MODE_MASK 0x0003 /* DCS_MODE - [1:0] */ | ||
975 | #define WM8903_DCS_MODE_SHIFT 0 /* DCS_MODE - [1:0] */ | ||
976 | #define WM8903_DCS_MODE_WIDTH 2 /* DCS_MODE - [1:0] */ | ||
977 | |||
978 | /* | ||
979 | * R90 (0x5A) - Analogue HP 0 | ||
980 | */ | ||
981 | #define WM8903_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */ | ||
982 | #define WM8903_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */ | ||
983 | #define WM8903_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */ | ||
984 | #define WM8903_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */ | ||
985 | #define WM8903_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */ | ||
986 | #define WM8903_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */ | ||
987 | #define WM8903_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */ | ||
988 | #define WM8903_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */ | ||
989 | #define WM8903_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */ | ||
990 | #define WM8903_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */ | ||
991 | #define WM8903_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */ | ||
992 | #define WM8903_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */ | ||
993 | #define WM8903_HPL_ENA 0x0010 /* HPL_ENA */ | ||
994 | #define WM8903_HPL_ENA_MASK 0x0010 /* HPL_ENA */ | ||
995 | #define WM8903_HPL_ENA_SHIFT 4 /* HPL_ENA */ | ||
996 | #define WM8903_HPL_ENA_WIDTH 1 /* HPL_ENA */ | ||
997 | #define WM8903_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */ | ||
998 | #define WM8903_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */ | ||
999 | #define WM8903_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */ | ||
1000 | #define WM8903_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */ | ||
1001 | #define WM8903_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */ | ||
1002 | #define WM8903_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */ | ||
1003 | #define WM8903_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */ | ||
1004 | #define WM8903_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */ | ||
1005 | #define WM8903_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */ | ||
1006 | #define WM8903_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */ | ||
1007 | #define WM8903_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */ | ||
1008 | #define WM8903_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */ | ||
1009 | #define WM8903_HPR_ENA 0x0001 /* HPR_ENA */ | ||
1010 | #define WM8903_HPR_ENA_MASK 0x0001 /* HPR_ENA */ | ||
1011 | #define WM8903_HPR_ENA_SHIFT 0 /* HPR_ENA */ | ||
1012 | #define WM8903_HPR_ENA_WIDTH 1 /* HPR_ENA */ | ||
1013 | |||
1014 | /* | ||
1015 | * R94 (0x5E) - Analogue Lineout 0 | ||
1016 | */ | ||
1017 | #define WM8903_LINEOUTL_RMV_SHORT 0x0080 /* LINEOUTL_RMV_SHORT */ | ||
1018 | #define WM8903_LINEOUTL_RMV_SHORT_MASK 0x0080 /* LINEOUTL_RMV_SHORT */ | ||
1019 | #define WM8903_LINEOUTL_RMV_SHORT_SHIFT 7 /* LINEOUTL_RMV_SHORT */ | ||
1020 | #define WM8903_LINEOUTL_RMV_SHORT_WIDTH 1 /* LINEOUTL_RMV_SHORT */ | ||
1021 | #define WM8903_LINEOUTL_ENA_OUTP 0x0040 /* LINEOUTL_ENA_OUTP */ | ||
1022 | #define WM8903_LINEOUTL_ENA_OUTP_MASK 0x0040 /* LINEOUTL_ENA_OUTP */ | ||
1023 | #define WM8903_LINEOUTL_ENA_OUTP_SHIFT 6 /* LINEOUTL_ENA_OUTP */ | ||
1024 | #define WM8903_LINEOUTL_ENA_OUTP_WIDTH 1 /* LINEOUTL_ENA_OUTP */ | ||
1025 | #define WM8903_LINEOUTL_ENA_DLY 0x0020 /* LINEOUTL_ENA_DLY */ | ||
1026 | #define WM8903_LINEOUTL_ENA_DLY_MASK 0x0020 /* LINEOUTL_ENA_DLY */ | ||
1027 | #define WM8903_LINEOUTL_ENA_DLY_SHIFT 5 /* LINEOUTL_ENA_DLY */ | ||
1028 | #define WM8903_LINEOUTL_ENA_DLY_WIDTH 1 /* LINEOUTL_ENA_DLY */ | ||
1029 | #define WM8903_LINEOUTL_ENA 0x0010 /* LINEOUTL_ENA */ | ||
1030 | #define WM8903_LINEOUTL_ENA_MASK 0x0010 /* LINEOUTL_ENA */ | ||
1031 | #define WM8903_LINEOUTL_ENA_SHIFT 4 /* LINEOUTL_ENA */ | ||
1032 | #define WM8903_LINEOUTL_ENA_WIDTH 1 /* LINEOUTL_ENA */ | ||
1033 | #define WM8903_LINEOUTR_RMV_SHORT 0x0008 /* LINEOUTR_RMV_SHORT */ | ||
1034 | #define WM8903_LINEOUTR_RMV_SHORT_MASK 0x0008 /* LINEOUTR_RMV_SHORT */ | ||
1035 | #define WM8903_LINEOUTR_RMV_SHORT_SHIFT 3 /* LINEOUTR_RMV_SHORT */ | ||
1036 | #define WM8903_LINEOUTR_RMV_SHORT_WIDTH 1 /* LINEOUTR_RMV_SHORT */ | ||
1037 | #define WM8903_LINEOUTR_ENA_OUTP 0x0004 /* LINEOUTR_ENA_OUTP */ | ||
1038 | #define WM8903_LINEOUTR_ENA_OUTP_MASK 0x0004 /* LINEOUTR_ENA_OUTP */ | ||
1039 | #define WM8903_LINEOUTR_ENA_OUTP_SHIFT 2 /* LINEOUTR_ENA_OUTP */ | ||
1040 | #define WM8903_LINEOUTR_ENA_OUTP_WIDTH 1 /* LINEOUTR_ENA_OUTP */ | ||
1041 | #define WM8903_LINEOUTR_ENA_DLY 0x0002 /* LINEOUTR_ENA_DLY */ | ||
1042 | #define WM8903_LINEOUTR_ENA_DLY_MASK 0x0002 /* LINEOUTR_ENA_DLY */ | ||
1043 | #define WM8903_LINEOUTR_ENA_DLY_SHIFT 1 /* LINEOUTR_ENA_DLY */ | ||
1044 | #define WM8903_LINEOUTR_ENA_DLY_WIDTH 1 /* LINEOUTR_ENA_DLY */ | ||
1045 | #define WM8903_LINEOUTR_ENA 0x0001 /* LINEOUTR_ENA */ | ||
1046 | #define WM8903_LINEOUTR_ENA_MASK 0x0001 /* LINEOUTR_ENA */ | ||
1047 | #define WM8903_LINEOUTR_ENA_SHIFT 0 /* LINEOUTR_ENA */ | ||
1048 | #define WM8903_LINEOUTR_ENA_WIDTH 1 /* LINEOUTR_ENA */ | ||
1049 | |||
1050 | /* | ||
1051 | * R98 (0x62) - Charge Pump 0 | ||
1052 | */ | ||
1053 | #define WM8903_CP_ENA 0x0001 /* CP_ENA */ | ||
1054 | #define WM8903_CP_ENA_MASK 0x0001 /* CP_ENA */ | ||
1055 | #define WM8903_CP_ENA_SHIFT 0 /* CP_ENA */ | ||
1056 | #define WM8903_CP_ENA_WIDTH 1 /* CP_ENA */ | ||
1057 | |||
1058 | /* | ||
1059 | * R104 (0x68) - Class W 0 | ||
1060 | */ | ||
1061 | #define WM8903_CP_DYN_FREQ 0x0002 /* CP_DYN_FREQ */ | ||
1062 | #define WM8903_CP_DYN_FREQ_MASK 0x0002 /* CP_DYN_FREQ */ | ||
1063 | #define WM8903_CP_DYN_FREQ_SHIFT 1 /* CP_DYN_FREQ */ | ||
1064 | #define WM8903_CP_DYN_FREQ_WIDTH 1 /* CP_DYN_FREQ */ | ||
1065 | #define WM8903_CP_DYN_V 0x0001 /* CP_DYN_V */ | ||
1066 | #define WM8903_CP_DYN_V_MASK 0x0001 /* CP_DYN_V */ | ||
1067 | #define WM8903_CP_DYN_V_SHIFT 0 /* CP_DYN_V */ | ||
1068 | #define WM8903_CP_DYN_V_WIDTH 1 /* CP_DYN_V */ | ||
1069 | |||
1070 | /* | ||
1071 | * R108 (0x6C) - Write Sequencer 0 | ||
1072 | */ | ||
1073 | #define WM8903_WSEQ_ENA 0x0100 /* WSEQ_ENA */ | ||
1074 | #define WM8903_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */ | ||
1075 | #define WM8903_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */ | ||
1076 | #define WM8903_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ | ||
1077 | #define WM8903_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1078 | #define WM8903_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1079 | #define WM8903_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */ | ||
1080 | |||
1081 | /* | ||
1082 | * R109 (0x6D) - Write Sequencer 1 | ||
1083 | */ | ||
1084 | #define WM8903_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1085 | #define WM8903_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1086 | #define WM8903_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */ | ||
1087 | #define WM8903_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */ | ||
1088 | #define WM8903_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */ | ||
1089 | #define WM8903_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */ | ||
1090 | #define WM8903_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */ | ||
1091 | #define WM8903_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */ | ||
1092 | #define WM8903_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */ | ||
1093 | |||
1094 | /* | ||
1095 | * R110 (0x6E) - Write Sequencer 2 | ||
1096 | */ | ||
1097 | #define WM8903_WSEQ_EOS 0x4000 /* WSEQ_EOS */ | ||
1098 | #define WM8903_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */ | ||
1099 | #define WM8903_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */ | ||
1100 | #define WM8903_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */ | ||
1101 | #define WM8903_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */ | ||
1102 | #define WM8903_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */ | ||
1103 | #define WM8903_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */ | ||
1104 | #define WM8903_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */ | ||
1105 | #define WM8903_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */ | ||
1106 | #define WM8903_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */ | ||
1107 | |||
1108 | /* | ||
1109 | * R111 (0x6F) - Write Sequencer 3 | ||
1110 | */ | ||
1111 | #define WM8903_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ | ||
1112 | #define WM8903_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ | ||
1113 | #define WM8903_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ | ||
1114 | #define WM8903_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ | ||
1115 | #define WM8903_WSEQ_START 0x0100 /* WSEQ_START */ | ||
1116 | #define WM8903_WSEQ_START_MASK 0x0100 /* WSEQ_START */ | ||
1117 | #define WM8903_WSEQ_START_SHIFT 8 /* WSEQ_START */ | ||
1118 | #define WM8903_WSEQ_START_WIDTH 1 /* WSEQ_START */ | ||
1119 | #define WM8903_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */ | ||
1120 | #define WM8903_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */ | ||
1121 | #define WM8903_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */ | ||
1122 | |||
1123 | /* | ||
1124 | * R112 (0x70) - Write Sequencer 4 | ||
1125 | */ | ||
1126 | #define WM8903_WSEQ_CURRENT_INDEX_MASK 0x03F0 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1127 | #define WM8903_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1128 | #define WM8903_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [9:4] */ | ||
1129 | #define WM8903_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ | ||
1130 | #define WM8903_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ | ||
1131 | #define WM8903_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ | ||
1132 | #define WM8903_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ | ||
1133 | |||
1134 | /* | ||
1135 | * R114 (0x72) - Control Interface | ||
1136 | */ | ||
1137 | #define WM8903_MASK_WRITE_ENA 0x0001 /* MASK_WRITE_ENA */ | ||
1138 | #define WM8903_MASK_WRITE_ENA_MASK 0x0001 /* MASK_WRITE_ENA */ | ||
1139 | #define WM8903_MASK_WRITE_ENA_SHIFT 0 /* MASK_WRITE_ENA */ | ||
1140 | #define WM8903_MASK_WRITE_ENA_WIDTH 1 /* MASK_WRITE_ENA */ | ||
1141 | |||
1142 | /* | ||
1143 | * R116 (0x74) - GPIO Control 1 | ||
1144 | */ | ||
1145 | #define WM8903_GP1_FN_MASK 0x1F00 /* GP1_FN - [12:8] */ | ||
1146 | #define WM8903_GP1_FN_SHIFT 8 /* GP1_FN - [12:8] */ | ||
1147 | #define WM8903_GP1_FN_WIDTH 5 /* GP1_FN - [12:8] */ | ||
1148 | #define WM8903_GP1_DIR 0x0080 /* GP1_DIR */ | ||
1149 | #define WM8903_GP1_DIR_MASK 0x0080 /* GP1_DIR */ | ||
1150 | #define WM8903_GP1_DIR_SHIFT 7 /* GP1_DIR */ | ||
1151 | #define WM8903_GP1_DIR_WIDTH 1 /* GP1_DIR */ | ||
1152 | #define WM8903_GP1_OP_CFG 0x0040 /* GP1_OP_CFG */ | ||
1153 | #define WM8903_GP1_OP_CFG_MASK 0x0040 /* GP1_OP_CFG */ | ||
1154 | #define WM8903_GP1_OP_CFG_SHIFT 6 /* GP1_OP_CFG */ | ||
1155 | #define WM8903_GP1_OP_CFG_WIDTH 1 /* GP1_OP_CFG */ | ||
1156 | #define WM8903_GP1_IP_CFG 0x0020 /* GP1_IP_CFG */ | ||
1157 | #define WM8903_GP1_IP_CFG_MASK 0x0020 /* GP1_IP_CFG */ | ||
1158 | #define WM8903_GP1_IP_CFG_SHIFT 5 /* GP1_IP_CFG */ | ||
1159 | #define WM8903_GP1_IP_CFG_WIDTH 1 /* GP1_IP_CFG */ | ||
1160 | #define WM8903_GP1_LVL 0x0010 /* GP1_LVL */ | ||
1161 | #define WM8903_GP1_LVL_MASK 0x0010 /* GP1_LVL */ | ||
1162 | #define WM8903_GP1_LVL_SHIFT 4 /* GP1_LVL */ | ||
1163 | #define WM8903_GP1_LVL_WIDTH 1 /* GP1_LVL */ | ||
1164 | #define WM8903_GP1_PD 0x0008 /* GP1_PD */ | ||
1165 | #define WM8903_GP1_PD_MASK 0x0008 /* GP1_PD */ | ||
1166 | #define WM8903_GP1_PD_SHIFT 3 /* GP1_PD */ | ||
1167 | #define WM8903_GP1_PD_WIDTH 1 /* GP1_PD */ | ||
1168 | #define WM8903_GP1_PU 0x0004 /* GP1_PU */ | ||
1169 | #define WM8903_GP1_PU_MASK 0x0004 /* GP1_PU */ | ||
1170 | #define WM8903_GP1_PU_SHIFT 2 /* GP1_PU */ | ||
1171 | #define WM8903_GP1_PU_WIDTH 1 /* GP1_PU */ | ||
1172 | #define WM8903_GP1_INTMODE 0x0002 /* GP1_INTMODE */ | ||
1173 | #define WM8903_GP1_INTMODE_MASK 0x0002 /* GP1_INTMODE */ | ||
1174 | #define WM8903_GP1_INTMODE_SHIFT 1 /* GP1_INTMODE */ | ||
1175 | #define WM8903_GP1_INTMODE_WIDTH 1 /* GP1_INTMODE */ | ||
1176 | #define WM8903_GP1_DB 0x0001 /* GP1_DB */ | ||
1177 | #define WM8903_GP1_DB_MASK 0x0001 /* GP1_DB */ | ||
1178 | #define WM8903_GP1_DB_SHIFT 0 /* GP1_DB */ | ||
1179 | #define WM8903_GP1_DB_WIDTH 1 /* GP1_DB */ | ||
1180 | |||
1181 | /* | ||
1182 | * R117 (0x75) - GPIO Control 2 | ||
1183 | */ | ||
1184 | #define WM8903_GP2_FN_MASK 0x1F00 /* GP2_FN - [12:8] */ | ||
1185 | #define WM8903_GP2_FN_SHIFT 8 /* GP2_FN - [12:8] */ | ||
1186 | #define WM8903_GP2_FN_WIDTH 5 /* GP2_FN - [12:8] */ | ||
1187 | #define WM8903_GP2_DIR 0x0080 /* GP2_DIR */ | ||
1188 | #define WM8903_GP2_DIR_MASK 0x0080 /* GP2_DIR */ | ||
1189 | #define WM8903_GP2_DIR_SHIFT 7 /* GP2_DIR */ | ||
1190 | #define WM8903_GP2_DIR_WIDTH 1 /* GP2_DIR */ | ||
1191 | #define WM8903_GP2_OP_CFG 0x0040 /* GP2_OP_CFG */ | ||
1192 | #define WM8903_GP2_OP_CFG_MASK 0x0040 /* GP2_OP_CFG */ | ||
1193 | #define WM8903_GP2_OP_CFG_SHIFT 6 /* GP2_OP_CFG */ | ||
1194 | #define WM8903_GP2_OP_CFG_WIDTH 1 /* GP2_OP_CFG */ | ||
1195 | #define WM8903_GP2_IP_CFG 0x0020 /* GP2_IP_CFG */ | ||
1196 | #define WM8903_GP2_IP_CFG_MASK 0x0020 /* GP2_IP_CFG */ | ||
1197 | #define WM8903_GP2_IP_CFG_SHIFT 5 /* GP2_IP_CFG */ | ||
1198 | #define WM8903_GP2_IP_CFG_WIDTH 1 /* GP2_IP_CFG */ | ||
1199 | #define WM8903_GP2_LVL 0x0010 /* GP2_LVL */ | ||
1200 | #define WM8903_GP2_LVL_MASK 0x0010 /* GP2_LVL */ | ||
1201 | #define WM8903_GP2_LVL_SHIFT 4 /* GP2_LVL */ | ||
1202 | #define WM8903_GP2_LVL_WIDTH 1 /* GP2_LVL */ | ||
1203 | #define WM8903_GP2_PD 0x0008 /* GP2_PD */ | ||
1204 | #define WM8903_GP2_PD_MASK 0x0008 /* GP2_PD */ | ||
1205 | #define WM8903_GP2_PD_SHIFT 3 /* GP2_PD */ | ||
1206 | #define WM8903_GP2_PD_WIDTH 1 /* GP2_PD */ | ||
1207 | #define WM8903_GP2_PU 0x0004 /* GP2_PU */ | ||
1208 | #define WM8903_GP2_PU_MASK 0x0004 /* GP2_PU */ | ||
1209 | #define WM8903_GP2_PU_SHIFT 2 /* GP2_PU */ | ||
1210 | #define WM8903_GP2_PU_WIDTH 1 /* GP2_PU */ | ||
1211 | #define WM8903_GP2_INTMODE 0x0002 /* GP2_INTMODE */ | ||
1212 | #define WM8903_GP2_INTMODE_MASK 0x0002 /* GP2_INTMODE */ | ||
1213 | #define WM8903_GP2_INTMODE_SHIFT 1 /* GP2_INTMODE */ | ||
1214 | #define WM8903_GP2_INTMODE_WIDTH 1 /* GP2_INTMODE */ | ||
1215 | #define WM8903_GP2_DB 0x0001 /* GP2_DB */ | ||
1216 | #define WM8903_GP2_DB_MASK 0x0001 /* GP2_DB */ | ||
1217 | #define WM8903_GP2_DB_SHIFT 0 /* GP2_DB */ | ||
1218 | #define WM8903_GP2_DB_WIDTH 1 /* GP2_DB */ | ||
1219 | |||
1220 | /* | ||
1221 | * R118 (0x76) - GPIO Control 3 | ||
1222 | */ | ||
1223 | #define WM8903_GP3_FN_MASK 0x1F00 /* GP3_FN - [12:8] */ | ||
1224 | #define WM8903_GP3_FN_SHIFT 8 /* GP3_FN - [12:8] */ | ||
1225 | #define WM8903_GP3_FN_WIDTH 5 /* GP3_FN - [12:8] */ | ||
1226 | #define WM8903_GP3_DIR 0x0080 /* GP3_DIR */ | ||
1227 | #define WM8903_GP3_DIR_MASK 0x0080 /* GP3_DIR */ | ||
1228 | #define WM8903_GP3_DIR_SHIFT 7 /* GP3_DIR */ | ||
1229 | #define WM8903_GP3_DIR_WIDTH 1 /* GP3_DIR */ | ||
1230 | #define WM8903_GP3_OP_CFG 0x0040 /* GP3_OP_CFG */ | ||
1231 | #define WM8903_GP3_OP_CFG_MASK 0x0040 /* GP3_OP_CFG */ | ||
1232 | #define WM8903_GP3_OP_CFG_SHIFT 6 /* GP3_OP_CFG */ | ||
1233 | #define WM8903_GP3_OP_CFG_WIDTH 1 /* GP3_OP_CFG */ | ||
1234 | #define WM8903_GP3_IP_CFG 0x0020 /* GP3_IP_CFG */ | ||
1235 | #define WM8903_GP3_IP_CFG_MASK 0x0020 /* GP3_IP_CFG */ | ||
1236 | #define WM8903_GP3_IP_CFG_SHIFT 5 /* GP3_IP_CFG */ | ||
1237 | #define WM8903_GP3_IP_CFG_WIDTH 1 /* GP3_IP_CFG */ | ||
1238 | #define WM8903_GP3_LVL 0x0010 /* GP3_LVL */ | ||
1239 | #define WM8903_GP3_LVL_MASK 0x0010 /* GP3_LVL */ | ||
1240 | #define WM8903_GP3_LVL_SHIFT 4 /* GP3_LVL */ | ||
1241 | #define WM8903_GP3_LVL_WIDTH 1 /* GP3_LVL */ | ||
1242 | #define WM8903_GP3_PD 0x0008 /* GP3_PD */ | ||
1243 | #define WM8903_GP3_PD_MASK 0x0008 /* GP3_PD */ | ||
1244 | #define WM8903_GP3_PD_SHIFT 3 /* GP3_PD */ | ||
1245 | #define WM8903_GP3_PD_WIDTH 1 /* GP3_PD */ | ||
1246 | #define WM8903_GP3_PU 0x0004 /* GP3_PU */ | ||
1247 | #define WM8903_GP3_PU_MASK 0x0004 /* GP3_PU */ | ||
1248 | #define WM8903_GP3_PU_SHIFT 2 /* GP3_PU */ | ||
1249 | #define WM8903_GP3_PU_WIDTH 1 /* GP3_PU */ | ||
1250 | #define WM8903_GP3_INTMODE 0x0002 /* GP3_INTMODE */ | ||
1251 | #define WM8903_GP3_INTMODE_MASK 0x0002 /* GP3_INTMODE */ | ||
1252 | #define WM8903_GP3_INTMODE_SHIFT 1 /* GP3_INTMODE */ | ||
1253 | #define WM8903_GP3_INTMODE_WIDTH 1 /* GP3_INTMODE */ | ||
1254 | #define WM8903_GP3_DB 0x0001 /* GP3_DB */ | ||
1255 | #define WM8903_GP3_DB_MASK 0x0001 /* GP3_DB */ | ||
1256 | #define WM8903_GP3_DB_SHIFT 0 /* GP3_DB */ | ||
1257 | #define WM8903_GP3_DB_WIDTH 1 /* GP3_DB */ | ||
1258 | |||
1259 | /* | ||
1260 | * R119 (0x77) - GPIO Control 4 | ||
1261 | */ | ||
1262 | #define WM8903_GP4_FN_MASK 0x1F00 /* GP4_FN - [12:8] */ | ||
1263 | #define WM8903_GP4_FN_SHIFT 8 /* GP4_FN - [12:8] */ | ||
1264 | #define WM8903_GP4_FN_WIDTH 5 /* GP4_FN - [12:8] */ | ||
1265 | #define WM8903_GP4_DIR 0x0080 /* GP4_DIR */ | ||
1266 | #define WM8903_GP4_DIR_MASK 0x0080 /* GP4_DIR */ | ||
1267 | #define WM8903_GP4_DIR_SHIFT 7 /* GP4_DIR */ | ||
1268 | #define WM8903_GP4_DIR_WIDTH 1 /* GP4_DIR */ | ||
1269 | #define WM8903_GP4_OP_CFG 0x0040 /* GP4_OP_CFG */ | ||
1270 | #define WM8903_GP4_OP_CFG_MASK 0x0040 /* GP4_OP_CFG */ | ||
1271 | #define WM8903_GP4_OP_CFG_SHIFT 6 /* GP4_OP_CFG */ | ||
1272 | #define WM8903_GP4_OP_CFG_WIDTH 1 /* GP4_OP_CFG */ | ||
1273 | #define WM8903_GP4_IP_CFG 0x0020 /* GP4_IP_CFG */ | ||
1274 | #define WM8903_GP4_IP_CFG_MASK 0x0020 /* GP4_IP_CFG */ | ||
1275 | #define WM8903_GP4_IP_CFG_SHIFT 5 /* GP4_IP_CFG */ | ||
1276 | #define WM8903_GP4_IP_CFG_WIDTH 1 /* GP4_IP_CFG */ | ||
1277 | #define WM8903_GP4_LVL 0x0010 /* GP4_LVL */ | ||
1278 | #define WM8903_GP4_LVL_MASK 0x0010 /* GP4_LVL */ | ||
1279 | #define WM8903_GP4_LVL_SHIFT 4 /* GP4_LVL */ | ||
1280 | #define WM8903_GP4_LVL_WIDTH 1 /* GP4_LVL */ | ||
1281 | #define WM8903_GP4_PD 0x0008 /* GP4_PD */ | ||
1282 | #define WM8903_GP4_PD_MASK 0x0008 /* GP4_PD */ | ||
1283 | #define WM8903_GP4_PD_SHIFT 3 /* GP4_PD */ | ||
1284 | #define WM8903_GP4_PD_WIDTH 1 /* GP4_PD */ | ||
1285 | #define WM8903_GP4_PU 0x0004 /* GP4_PU */ | ||
1286 | #define WM8903_GP4_PU_MASK 0x0004 /* GP4_PU */ | ||
1287 | #define WM8903_GP4_PU_SHIFT 2 /* GP4_PU */ | ||
1288 | #define WM8903_GP4_PU_WIDTH 1 /* GP4_PU */ | ||
1289 | #define WM8903_GP4_INTMODE 0x0002 /* GP4_INTMODE */ | ||
1290 | #define WM8903_GP4_INTMODE_MASK 0x0002 /* GP4_INTMODE */ | ||
1291 | #define WM8903_GP4_INTMODE_SHIFT 1 /* GP4_INTMODE */ | ||
1292 | #define WM8903_GP4_INTMODE_WIDTH 1 /* GP4_INTMODE */ | ||
1293 | #define WM8903_GP4_DB 0x0001 /* GP4_DB */ | ||
1294 | #define WM8903_GP4_DB_MASK 0x0001 /* GP4_DB */ | ||
1295 | #define WM8903_GP4_DB_SHIFT 0 /* GP4_DB */ | ||
1296 | #define WM8903_GP4_DB_WIDTH 1 /* GP4_DB */ | ||
1297 | |||
1298 | /* | ||
1299 | * R120 (0x78) - GPIO Control 5 | ||
1300 | */ | ||
1301 | #define WM8903_GP5_FN_MASK 0x1F00 /* GP5_FN - [12:8] */ | ||
1302 | #define WM8903_GP5_FN_SHIFT 8 /* GP5_FN - [12:8] */ | ||
1303 | #define WM8903_GP5_FN_WIDTH 5 /* GP5_FN - [12:8] */ | ||
1304 | #define WM8903_GP5_DIR 0x0080 /* GP5_DIR */ | ||
1305 | #define WM8903_GP5_DIR_MASK 0x0080 /* GP5_DIR */ | ||
1306 | #define WM8903_GP5_DIR_SHIFT 7 /* GP5_DIR */ | ||
1307 | #define WM8903_GP5_DIR_WIDTH 1 /* GP5_DIR */ | ||
1308 | #define WM8903_GP5_OP_CFG 0x0040 /* GP5_OP_CFG */ | ||
1309 | #define WM8903_GP5_OP_CFG_MASK 0x0040 /* GP5_OP_CFG */ | ||
1310 | #define WM8903_GP5_OP_CFG_SHIFT 6 /* GP5_OP_CFG */ | ||
1311 | #define WM8903_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */ | ||
1312 | #define WM8903_GP5_IP_CFG 0x0020 /* GP5_IP_CFG */ | ||
1313 | #define WM8903_GP5_IP_CFG_MASK 0x0020 /* GP5_IP_CFG */ | ||
1314 | #define WM8903_GP5_IP_CFG_SHIFT 5 /* GP5_IP_CFG */ | ||
1315 | #define WM8903_GP5_IP_CFG_WIDTH 1 /* GP5_IP_CFG */ | ||
1316 | #define WM8903_GP5_LVL 0x0010 /* GP5_LVL */ | ||
1317 | #define WM8903_GP5_LVL_MASK 0x0010 /* GP5_LVL */ | ||
1318 | #define WM8903_GP5_LVL_SHIFT 4 /* GP5_LVL */ | ||
1319 | #define WM8903_GP5_LVL_WIDTH 1 /* GP5_LVL */ | ||
1320 | #define WM8903_GP5_PD 0x0008 /* GP5_PD */ | ||
1321 | #define WM8903_GP5_PD_MASK 0x0008 /* GP5_PD */ | ||
1322 | #define WM8903_GP5_PD_SHIFT 3 /* GP5_PD */ | ||
1323 | #define WM8903_GP5_PD_WIDTH 1 /* GP5_PD */ | ||
1324 | #define WM8903_GP5_PU 0x0004 /* GP5_PU */ | ||
1325 | #define WM8903_GP5_PU_MASK 0x0004 /* GP5_PU */ | ||
1326 | #define WM8903_GP5_PU_SHIFT 2 /* GP5_PU */ | ||
1327 | #define WM8903_GP5_PU_WIDTH 1 /* GP5_PU */ | ||
1328 | #define WM8903_GP5_INTMODE 0x0002 /* GP5_INTMODE */ | ||
1329 | #define WM8903_GP5_INTMODE_MASK 0x0002 /* GP5_INTMODE */ | ||
1330 | #define WM8903_GP5_INTMODE_SHIFT 1 /* GP5_INTMODE */ | ||
1331 | #define WM8903_GP5_INTMODE_WIDTH 1 /* GP5_INTMODE */ | ||
1332 | #define WM8903_GP5_DB 0x0001 /* GP5_DB */ | ||
1333 | #define WM8903_GP5_DB_MASK 0x0001 /* GP5_DB */ | ||
1334 | #define WM8903_GP5_DB_SHIFT 0 /* GP5_DB */ | ||
1335 | #define WM8903_GP5_DB_WIDTH 1 /* GP5_DB */ | ||
1336 | |||
1337 | /* | ||
1338 | * R121 (0x79) - Interrupt Status 1 | ||
1339 | */ | ||
1340 | #define WM8903_MICSHRT_EINT 0x8000 /* MICSHRT_EINT */ | ||
1341 | #define WM8903_MICSHRT_EINT_MASK 0x8000 /* MICSHRT_EINT */ | ||
1342 | #define WM8903_MICSHRT_EINT_SHIFT 15 /* MICSHRT_EINT */ | ||
1343 | #define WM8903_MICSHRT_EINT_WIDTH 1 /* MICSHRT_EINT */ | ||
1344 | #define WM8903_MICDET_EINT 0x4000 /* MICDET_EINT */ | ||
1345 | #define WM8903_MICDET_EINT_MASK 0x4000 /* MICDET_EINT */ | ||
1346 | #define WM8903_MICDET_EINT_SHIFT 14 /* MICDET_EINT */ | ||
1347 | #define WM8903_MICDET_EINT_WIDTH 1 /* MICDET_EINT */ | ||
1348 | #define WM8903_WSEQ_BUSY_EINT 0x2000 /* WSEQ_BUSY_EINT */ | ||
1349 | #define WM8903_WSEQ_BUSY_EINT_MASK 0x2000 /* WSEQ_BUSY_EINT */ | ||
1350 | #define WM8903_WSEQ_BUSY_EINT_SHIFT 13 /* WSEQ_BUSY_EINT */ | ||
1351 | #define WM8903_WSEQ_BUSY_EINT_WIDTH 1 /* WSEQ_BUSY_EINT */ | ||
1352 | #define WM8903_GP5_EINT 0x0010 /* GP5_EINT */ | ||
1353 | #define WM8903_GP5_EINT_MASK 0x0010 /* GP5_EINT */ | ||
1354 | #define WM8903_GP5_EINT_SHIFT 4 /* GP5_EINT */ | ||
1355 | #define WM8903_GP5_EINT_WIDTH 1 /* GP5_EINT */ | ||
1356 | #define WM8903_GP4_EINT 0x0008 /* GP4_EINT */ | ||
1357 | #define WM8903_GP4_EINT_MASK 0x0008 /* GP4_EINT */ | ||
1358 | #define WM8903_GP4_EINT_SHIFT 3 /* GP4_EINT */ | ||
1359 | #define WM8903_GP4_EINT_WIDTH 1 /* GP4_EINT */ | ||
1360 | #define WM8903_GP3_EINT 0x0004 /* GP3_EINT */ | ||
1361 | #define WM8903_GP3_EINT_MASK 0x0004 /* GP3_EINT */ | ||
1362 | #define WM8903_GP3_EINT_SHIFT 2 /* GP3_EINT */ | ||
1363 | #define WM8903_GP3_EINT_WIDTH 1 /* GP3_EINT */ | ||
1364 | #define WM8903_GP2_EINT 0x0002 /* GP2_EINT */ | ||
1365 | #define WM8903_GP2_EINT_MASK 0x0002 /* GP2_EINT */ | ||
1366 | #define WM8903_GP2_EINT_SHIFT 1 /* GP2_EINT */ | ||
1367 | #define WM8903_GP2_EINT_WIDTH 1 /* GP2_EINT */ | ||
1368 | #define WM8903_GP1_EINT 0x0001 /* GP1_EINT */ | ||
1369 | #define WM8903_GP1_EINT_MASK 0x0001 /* GP1_EINT */ | ||
1370 | #define WM8903_GP1_EINT_SHIFT 0 /* GP1_EINT */ | ||
1371 | #define WM8903_GP1_EINT_WIDTH 1 /* GP1_EINT */ | ||
1372 | |||
1373 | /* | ||
1374 | * R122 (0x7A) - Interrupt Status 1 Mask | ||
1375 | */ | ||
1376 | #define WM8903_IM_MICSHRT_EINT 0x8000 /* IM_MICSHRT_EINT */ | ||
1377 | #define WM8903_IM_MICSHRT_EINT_MASK 0x8000 /* IM_MICSHRT_EINT */ | ||
1378 | #define WM8903_IM_MICSHRT_EINT_SHIFT 15 /* IM_MICSHRT_EINT */ | ||
1379 | #define WM8903_IM_MICSHRT_EINT_WIDTH 1 /* IM_MICSHRT_EINT */ | ||
1380 | #define WM8903_IM_MICDET_EINT 0x4000 /* IM_MICDET_EINT */ | ||
1381 | #define WM8903_IM_MICDET_EINT_MASK 0x4000 /* IM_MICDET_EINT */ | ||
1382 | #define WM8903_IM_MICDET_EINT_SHIFT 14 /* IM_MICDET_EINT */ | ||
1383 | #define WM8903_IM_MICDET_EINT_WIDTH 1 /* IM_MICDET_EINT */ | ||
1384 | #define WM8903_IM_WSEQ_BUSY_EINT 0x2000 /* IM_WSEQ_BUSY_EINT */ | ||
1385 | #define WM8903_IM_WSEQ_BUSY_EINT_MASK 0x2000 /* IM_WSEQ_BUSY_EINT */ | ||
1386 | #define WM8903_IM_WSEQ_BUSY_EINT_SHIFT 13 /* IM_WSEQ_BUSY_EINT */ | ||
1387 | #define WM8903_IM_WSEQ_BUSY_EINT_WIDTH 1 /* IM_WSEQ_BUSY_EINT */ | ||
1388 | #define WM8903_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */ | ||
1389 | #define WM8903_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */ | ||
1390 | #define WM8903_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */ | ||
1391 | #define WM8903_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */ | ||
1392 | #define WM8903_IM_GP4_EINT 0x0008 /* IM_GP4_EINT */ | ||
1393 | #define WM8903_IM_GP4_EINT_MASK 0x0008 /* IM_GP4_EINT */ | ||
1394 | #define WM8903_IM_GP4_EINT_SHIFT 3 /* IM_GP4_EINT */ | ||
1395 | #define WM8903_IM_GP4_EINT_WIDTH 1 /* IM_GP4_EINT */ | ||
1396 | #define WM8903_IM_GP3_EINT 0x0004 /* IM_GP3_EINT */ | ||
1397 | #define WM8903_IM_GP3_EINT_MASK 0x0004 /* IM_GP3_EINT */ | ||
1398 | #define WM8903_IM_GP3_EINT_SHIFT 2 /* IM_GP3_EINT */ | ||
1399 | #define WM8903_IM_GP3_EINT_WIDTH 1 /* IM_GP3_EINT */ | ||
1400 | #define WM8903_IM_GP2_EINT 0x0002 /* IM_GP2_EINT */ | ||
1401 | #define WM8903_IM_GP2_EINT_MASK 0x0002 /* IM_GP2_EINT */ | ||
1402 | #define WM8903_IM_GP2_EINT_SHIFT 1 /* IM_GP2_EINT */ | ||
1403 | #define WM8903_IM_GP2_EINT_WIDTH 1 /* IM_GP2_EINT */ | ||
1404 | #define WM8903_IM_GP1_EINT 0x0001 /* IM_GP1_EINT */ | ||
1405 | #define WM8903_IM_GP1_EINT_MASK 0x0001 /* IM_GP1_EINT */ | ||
1406 | #define WM8903_IM_GP1_EINT_SHIFT 0 /* IM_GP1_EINT */ | ||
1407 | #define WM8903_IM_GP1_EINT_WIDTH 1 /* IM_GP1_EINT */ | ||
1408 | |||
1409 | /* | ||
1410 | * R123 (0x7B) - Interrupt Polarity 1 | ||
1411 | */ | ||
1412 | #define WM8903_MICSHRT_INV 0x8000 /* MICSHRT_INV */ | ||
1413 | #define WM8903_MICSHRT_INV_MASK 0x8000 /* MICSHRT_INV */ | ||
1414 | #define WM8903_MICSHRT_INV_SHIFT 15 /* MICSHRT_INV */ | ||
1415 | #define WM8903_MICSHRT_INV_WIDTH 1 /* MICSHRT_INV */ | ||
1416 | #define WM8903_MICDET_INV 0x4000 /* MICDET_INV */ | ||
1417 | #define WM8903_MICDET_INV_MASK 0x4000 /* MICDET_INV */ | ||
1418 | #define WM8903_MICDET_INV_SHIFT 14 /* MICDET_INV */ | ||
1419 | #define WM8903_MICDET_INV_WIDTH 1 /* MICDET_INV */ | ||
1420 | |||
1421 | /* | ||
1422 | * R126 (0x7E) - Interrupt Control | ||
1423 | */ | ||
1424 | #define WM8903_IRQ_POL 0x0001 /* IRQ_POL */ | ||
1425 | #define WM8903_IRQ_POL_MASK 0x0001 /* IRQ_POL */ | ||
1426 | #define WM8903_IRQ_POL_SHIFT 0 /* IRQ_POL */ | ||
1427 | #define WM8903_IRQ_POL_WIDTH 1 /* IRQ_POL */ | ||
1428 | |||
1429 | /* | ||
1430 | * R129 (0x81) - Control Interface Test 1 | ||
1431 | */ | ||
1432 | #define WM8903_USER_KEY 0x0002 /* USER_KEY */ | ||
1433 | #define WM8903_USER_KEY_MASK 0x0002 /* USER_KEY */ | ||
1434 | #define WM8903_USER_KEY_SHIFT 1 /* USER_KEY */ | ||
1435 | #define WM8903_USER_KEY_WIDTH 1 /* USER_KEY */ | ||
1436 | #define WM8903_TEST_KEY 0x0001 /* TEST_KEY */ | ||
1437 | #define WM8903_TEST_KEY_MASK 0x0001 /* TEST_KEY */ | ||
1438 | #define WM8903_TEST_KEY_SHIFT 0 /* TEST_KEY */ | ||
1439 | #define WM8903_TEST_KEY_WIDTH 1 /* TEST_KEY */ | ||
1440 | |||
1441 | /* | ||
1442 | * R149 (0x95) - Charge Pump Test 1 | ||
1443 | */ | ||
1444 | #define WM8903_CP_SW_KELVIN_MODE_MASK 0x0006 /* CP_SW_KELVIN_MODE - [2:1] */ | ||
1445 | #define WM8903_CP_SW_KELVIN_MODE_SHIFT 1 /* CP_SW_KELVIN_MODE - [2:1] */ | ||
1446 | #define WM8903_CP_SW_KELVIN_MODE_WIDTH 2 /* CP_SW_KELVIN_MODE - [2:1] */ | ||
1447 | |||
1448 | /* | ||
1449 | * R164 (0xA4) - Clock Rate Test 4 | ||
1450 | */ | ||
1451 | #define WM8903_ADC_DIG_MIC 0x0200 /* ADC_DIG_MIC */ | ||
1452 | #define WM8903_ADC_DIG_MIC_MASK 0x0200 /* ADC_DIG_MIC */ | ||
1453 | #define WM8903_ADC_DIG_MIC_SHIFT 9 /* ADC_DIG_MIC */ | ||
1454 | #define WM8903_ADC_DIG_MIC_WIDTH 1 /* ADC_DIG_MIC */ | ||
1455 | |||
1456 | /* | ||
1457 | * R172 (0xAC) - Analogue Output Bias 0 | ||
1458 | */ | ||
1459 | #define WM8903_PGA_BIAS_MASK 0x0070 /* PGA_BIAS - [6:4] */ | ||
1460 | #define WM8903_PGA_BIAS_SHIFT 4 /* PGA_BIAS - [6:4] */ | ||
1461 | #define WM8903_PGA_BIAS_WIDTH 3 /* PGA_BIAS - [6:4] */ | ||
1462 | |||
1463 | #endif | ||
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c new file mode 100644 index 00000000000..974a4cd0f3f --- /dev/null +++ b/sound/soc/codecs/wm8971.c | |||
@@ -0,0 +1,942 @@ | |||
1 | /* | ||
2 | * wm8971.c -- WM8971 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Lab126, Inc. | ||
5 | * | ||
6 | * Author: Kenneth Kiraly <kiraly@lab126.com> | ||
7 | * | ||
8 | * Based on wm8753.c by Liam Girdwood | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | |||
30 | #include "wm8971.h" | ||
31 | |||
32 | #define AUDIO_NAME "wm8971" | ||
33 | #define WM8971_VERSION "0.9" | ||
34 | |||
35 | #define WM8971_REG_COUNT 43 | ||
36 | |||
37 | static struct workqueue_struct *wm8971_workq = NULL; | ||
38 | |||
39 | /* codec private data */ | ||
40 | struct wm8971_priv { | ||
41 | unsigned int sysclk; | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * wm8971 register cache | ||
46 | * We can't read the WM8971 register space when we | ||
47 | * are using 2 wire for device control, so we cache them instead. | ||
48 | */ | ||
49 | static const u16 wm8971_reg[] = { | ||
50 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ | ||
51 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ | ||
52 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ | ||
53 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ | ||
54 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ | ||
55 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ | ||
56 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ | ||
57 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ | ||
58 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ | ||
59 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ | ||
60 | 0x0079, 0x0079, 0x0079, /* 40 */ | ||
61 | }; | ||
62 | |||
63 | static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec, | ||
64 | unsigned int reg) | ||
65 | { | ||
66 | u16 *cache = codec->reg_cache; | ||
67 | if (reg < WM8971_REG_COUNT) | ||
68 | return cache[reg]; | ||
69 | |||
70 | return -1; | ||
71 | } | ||
72 | |||
73 | static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec, | ||
74 | unsigned int reg, unsigned int value) | ||
75 | { | ||
76 | u16 *cache = codec->reg_cache; | ||
77 | if (reg < WM8971_REG_COUNT) | ||
78 | cache[reg] = value; | ||
79 | } | ||
80 | |||
81 | static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg, | ||
82 | unsigned int value) | ||
83 | { | ||
84 | u8 data[2]; | ||
85 | |||
86 | /* data is | ||
87 | * D15..D9 WM8753 register offset | ||
88 | * D8...D0 register data | ||
89 | */ | ||
90 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
91 | data[1] = value & 0x00ff; | ||
92 | |||
93 | wm8971_write_reg_cache (codec, reg, value); | ||
94 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
95 | return 0; | ||
96 | else | ||
97 | return -EIO; | ||
98 | } | ||
99 | |||
100 | #define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0) | ||
101 | |||
102 | /* WM8971 Controls */ | ||
103 | static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; | ||
104 | static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz", | ||
105 | "200Hz @ 48kHz" }; | ||
106 | static const char *wm8971_treble[] = { "8kHz", "4kHz" }; | ||
107 | static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" }; | ||
108 | static const char *wm8971_ng_type[] = { "Constant PGA Gain", | ||
109 | "Mute ADC Output" }; | ||
110 | static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | ||
111 | static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", | ||
112 | "Mono (Right)", "Digital Mono"}; | ||
113 | static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" }; | ||
114 | static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA", | ||
115 | "Differential"}; | ||
116 | static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA", | ||
117 | "Differential"}; | ||
118 | static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"}; | ||
119 | static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"}; | ||
120 | static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", | ||
121 | "L + R Invert"}; | ||
122 | |||
123 | static const struct soc_enum wm8971_enum[] = { | ||
124 | SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass), /* 0 */ | ||
125 | SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter), | ||
126 | SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble), | ||
127 | SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func), | ||
128 | SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type), /* 4 */ | ||
129 | SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp), | ||
130 | SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux), | ||
131 | SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase), | ||
132 | SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */ | ||
133 | SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux), | ||
134 | SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel), | ||
135 | SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel), | ||
136 | SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol), /* 12 */ | ||
137 | SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux), | ||
138 | }; | ||
139 | |||
140 | static const struct snd_kcontrol_new wm8971_snd_controls[] = { | ||
141 | SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0), | ||
142 | SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL, | ||
143 | 6, 1, 0), | ||
144 | SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1), | ||
145 | |||
146 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V, | ||
147 | WM8971_ROUT1V, 7, 1, 0), | ||
148 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V, | ||
149 | WM8971_ROUT2V, 7, 1, 0), | ||
150 | SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0), | ||
151 | |||
152 | SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0), | ||
153 | |||
154 | SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1, | ||
155 | WM8971_LOUTM2, 4, 7, 1), | ||
156 | SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1, | ||
157 | WM8971_ROUTM2, 4, 7, 1), | ||
158 | SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1, | ||
159 | WM8971_MOUTM2, 4, 7, 1), | ||
160 | |||
161 | SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V, | ||
162 | WM8971_ROUT1V, 0, 127, 0), | ||
163 | SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V, | ||
164 | WM8971_ROUT2V, 0, 127, 0), | ||
165 | |||
166 | SOC_ENUM("Bass Boost", wm8971_enum[0]), | ||
167 | SOC_ENUM("Bass Filter", wm8971_enum[1]), | ||
168 | SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1), | ||
169 | |||
170 | SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0), | ||
171 | SOC_ENUM("Treble Cut-off", wm8971_enum[2]), | ||
172 | |||
173 | SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1), | ||
174 | |||
175 | SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0), | ||
176 | SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0), | ||
177 | |||
178 | SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0), | ||
179 | SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0), | ||
180 | SOC_ENUM("ALC Capture Function", wm8971_enum[3]), | ||
181 | SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0), | ||
182 | SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0), | ||
183 | SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0), | ||
184 | SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0), | ||
185 | SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0), | ||
186 | SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]), | ||
187 | SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0), | ||
188 | |||
189 | SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0), | ||
190 | SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0), | ||
191 | |||
192 | SOC_ENUM("Playback De-emphasis", wm8971_enum[5]), | ||
193 | SOC_ENUM("Playback Function", wm8971_enum[6]), | ||
194 | SOC_ENUM("Playback Phase", wm8971_enum[7]), | ||
195 | |||
196 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), | ||
197 | }; | ||
198 | |||
199 | /* add non-DAPM controls */ | ||
200 | static int wm8971_add_controls(struct snd_soc_codec *codec) | ||
201 | { | ||
202 | int err, i; | ||
203 | |||
204 | for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) { | ||
205 | err = snd_ctl_add(codec->card, | ||
206 | snd_soc_cnew(&wm8971_snd_controls[i], | ||
207 | codec, NULL)); | ||
208 | if (err < 0) | ||
209 | return err; | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * DAPM Controls | ||
216 | */ | ||
217 | |||
218 | /* Left Mixer */ | ||
219 | static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = { | ||
220 | SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0), | ||
221 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0), | ||
222 | SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0), | ||
223 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0), | ||
224 | }; | ||
225 | |||
226 | /* Right Mixer */ | ||
227 | static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = { | ||
228 | SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0), | ||
229 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0), | ||
230 | SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0), | ||
231 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0), | ||
232 | }; | ||
233 | |||
234 | /* Mono Mixer */ | ||
235 | static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = { | ||
236 | SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0), | ||
237 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0), | ||
238 | SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0), | ||
239 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0), | ||
240 | }; | ||
241 | |||
242 | /* Left Line Mux */ | ||
243 | static const struct snd_kcontrol_new wm8971_left_line_controls = | ||
244 | SOC_DAPM_ENUM("Route", wm8971_enum[8]); | ||
245 | |||
246 | /* Right Line Mux */ | ||
247 | static const struct snd_kcontrol_new wm8971_right_line_controls = | ||
248 | SOC_DAPM_ENUM("Route", wm8971_enum[9]); | ||
249 | |||
250 | /* Left PGA Mux */ | ||
251 | static const struct snd_kcontrol_new wm8971_left_pga_controls = | ||
252 | SOC_DAPM_ENUM("Route", wm8971_enum[10]); | ||
253 | |||
254 | /* Right PGA Mux */ | ||
255 | static const struct snd_kcontrol_new wm8971_right_pga_controls = | ||
256 | SOC_DAPM_ENUM("Route", wm8971_enum[11]); | ||
257 | |||
258 | /* Mono ADC Mux */ | ||
259 | static const struct snd_kcontrol_new wm8971_monomux_controls = | ||
260 | SOC_DAPM_ENUM("Route", wm8971_enum[13]); | ||
261 | |||
262 | static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { | ||
263 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | ||
264 | &wm8971_left_mixer_controls[0], | ||
265 | ARRAY_SIZE(wm8971_left_mixer_controls)), | ||
266 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | ||
267 | &wm8971_right_mixer_controls[0], | ||
268 | ARRAY_SIZE(wm8971_right_mixer_controls)), | ||
269 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0, | ||
270 | &wm8971_mono_mixer_controls[0], | ||
271 | ARRAY_SIZE(wm8971_mono_mixer_controls)), | ||
272 | |||
273 | SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0), | ||
274 | SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0), | ||
275 | SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0), | ||
276 | SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0), | ||
277 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0), | ||
278 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0), | ||
279 | SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0), | ||
280 | |||
281 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0), | ||
282 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0), | ||
283 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0), | ||
284 | |||
285 | SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, | ||
286 | &wm8971_left_pga_controls), | ||
287 | SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, | ||
288 | &wm8971_right_pga_controls), | ||
289 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | ||
290 | &wm8971_left_line_controls), | ||
291 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | ||
292 | &wm8971_right_line_controls), | ||
293 | |||
294 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | ||
295 | &wm8971_monomux_controls), | ||
296 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | ||
297 | &wm8971_monomux_controls), | ||
298 | |||
299 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
300 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
301 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
302 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
303 | SND_SOC_DAPM_OUTPUT("MONO"), | ||
304 | |||
305 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
306 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
307 | SND_SOC_DAPM_INPUT("MIC"), | ||
308 | }; | ||
309 | |||
310 | static const struct snd_soc_dapm_route audio_map[] = { | ||
311 | /* left mixer */ | ||
312 | {"Left Mixer", "Playback Switch", "Left DAC"}, | ||
313 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
314 | {"Left Mixer", "Right Playback Switch", "Right DAC"}, | ||
315 | {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
316 | |||
317 | /* right mixer */ | ||
318 | {"Right Mixer", "Left Playback Switch", "Left DAC"}, | ||
319 | {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
320 | {"Right Mixer", "Playback Switch", "Right DAC"}, | ||
321 | {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
322 | |||
323 | /* left out 1 */ | ||
324 | {"Left Out 1", NULL, "Left Mixer"}, | ||
325 | {"LOUT1", NULL, "Left Out 1"}, | ||
326 | |||
327 | /* left out 2 */ | ||
328 | {"Left Out 2", NULL, "Left Mixer"}, | ||
329 | {"LOUT2", NULL, "Left Out 2"}, | ||
330 | |||
331 | /* right out 1 */ | ||
332 | {"Right Out 1", NULL, "Right Mixer"}, | ||
333 | {"ROUT1", NULL, "Right Out 1"}, | ||
334 | |||
335 | /* right out 2 */ | ||
336 | {"Right Out 2", NULL, "Right Mixer"}, | ||
337 | {"ROUT2", NULL, "Right Out 2"}, | ||
338 | |||
339 | /* mono mixer */ | ||
340 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, | ||
341 | {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
342 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, | ||
343 | {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
344 | |||
345 | /* mono out */ | ||
346 | {"Mono Out", NULL, "Mono Mixer"}, | ||
347 | {"MONO1", NULL, "Mono Out"}, | ||
348 | |||
349 | /* Left Line Mux */ | ||
350 | {"Left Line Mux", "Line", "LINPUT1"}, | ||
351 | {"Left Line Mux", "PGA", "Left PGA Mux"}, | ||
352 | {"Left Line Mux", "Differential", "Differential Mux"}, | ||
353 | |||
354 | /* Right Line Mux */ | ||
355 | {"Right Line Mux", "Line", "RINPUT1"}, | ||
356 | {"Right Line Mux", "Mic", "MIC"}, | ||
357 | {"Right Line Mux", "PGA", "Right PGA Mux"}, | ||
358 | {"Right Line Mux", "Differential", "Differential Mux"}, | ||
359 | |||
360 | /* Left PGA Mux */ | ||
361 | {"Left PGA Mux", "Line", "LINPUT1"}, | ||
362 | {"Left PGA Mux", "Differential", "Differential Mux"}, | ||
363 | |||
364 | /* Right PGA Mux */ | ||
365 | {"Right PGA Mux", "Line", "RINPUT1"}, | ||
366 | {"Right PGA Mux", "Differential", "Differential Mux"}, | ||
367 | |||
368 | /* Differential Mux */ | ||
369 | {"Differential Mux", "Line", "LINPUT1"}, | ||
370 | {"Differential Mux", "Line", "RINPUT1"}, | ||
371 | |||
372 | /* Left ADC Mux */ | ||
373 | {"Left ADC Mux", "Stereo", "Left PGA Mux"}, | ||
374 | {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, | ||
375 | {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, | ||
376 | |||
377 | /* Right ADC Mux */ | ||
378 | {"Right ADC Mux", "Stereo", "Right PGA Mux"}, | ||
379 | {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, | ||
380 | {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, | ||
381 | |||
382 | /* ADC */ | ||
383 | {"Left ADC", NULL, "Left ADC Mux"}, | ||
384 | {"Right ADC", NULL, "Right ADC Mux"}, | ||
385 | }; | ||
386 | |||
387 | static int wm8971_add_widgets(struct snd_soc_codec *codec) | ||
388 | { | ||
389 | snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets, | ||
390 | ARRAY_SIZE(wm8971_dapm_widgets)); | ||
391 | |||
392 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
393 | |||
394 | snd_soc_dapm_new_widgets(codec); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | struct _coeff_div { | ||
400 | u32 mclk; | ||
401 | u32 rate; | ||
402 | u16 fs; | ||
403 | u8 sr:5; | ||
404 | u8 usb:1; | ||
405 | }; | ||
406 | |||
407 | /* codec hifi mclk clock divider coefficients */ | ||
408 | static const struct _coeff_div coeff_div[] = { | ||
409 | /* 8k */ | ||
410 | {12288000, 8000, 1536, 0x6, 0x0}, | ||
411 | {11289600, 8000, 1408, 0x16, 0x0}, | ||
412 | {18432000, 8000, 2304, 0x7, 0x0}, | ||
413 | {16934400, 8000, 2112, 0x17, 0x0}, | ||
414 | {12000000, 8000, 1500, 0x6, 0x1}, | ||
415 | |||
416 | /* 11.025k */ | ||
417 | {11289600, 11025, 1024, 0x18, 0x0}, | ||
418 | {16934400, 11025, 1536, 0x19, 0x0}, | ||
419 | {12000000, 11025, 1088, 0x19, 0x1}, | ||
420 | |||
421 | /* 16k */ | ||
422 | {12288000, 16000, 768, 0xa, 0x0}, | ||
423 | {18432000, 16000, 1152, 0xb, 0x0}, | ||
424 | {12000000, 16000, 750, 0xa, 0x1}, | ||
425 | |||
426 | /* 22.05k */ | ||
427 | {11289600, 22050, 512, 0x1a, 0x0}, | ||
428 | {16934400, 22050, 768, 0x1b, 0x0}, | ||
429 | {12000000, 22050, 544, 0x1b, 0x1}, | ||
430 | |||
431 | /* 32k */ | ||
432 | {12288000, 32000, 384, 0xc, 0x0}, | ||
433 | {18432000, 32000, 576, 0xd, 0x0}, | ||
434 | {12000000, 32000, 375, 0xa, 0x1}, | ||
435 | |||
436 | /* 44.1k */ | ||
437 | {11289600, 44100, 256, 0x10, 0x0}, | ||
438 | {16934400, 44100, 384, 0x11, 0x0}, | ||
439 | {12000000, 44100, 272, 0x11, 0x1}, | ||
440 | |||
441 | /* 48k */ | ||
442 | {12288000, 48000, 256, 0x0, 0x0}, | ||
443 | {18432000, 48000, 384, 0x1, 0x0}, | ||
444 | {12000000, 48000, 250, 0x0, 0x1}, | ||
445 | |||
446 | /* 88.2k */ | ||
447 | {11289600, 88200, 128, 0x1e, 0x0}, | ||
448 | {16934400, 88200, 192, 0x1f, 0x0}, | ||
449 | {12000000, 88200, 136, 0x1f, 0x1}, | ||
450 | |||
451 | /* 96k */ | ||
452 | {12288000, 96000, 128, 0xe, 0x0}, | ||
453 | {18432000, 96000, 192, 0xf, 0x0}, | ||
454 | {12000000, 96000, 125, 0xe, 0x1}, | ||
455 | }; | ||
456 | |||
457 | static int get_coeff(int mclk, int rate) | ||
458 | { | ||
459 | int i; | ||
460 | |||
461 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
462 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
463 | return i; | ||
464 | } | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | |||
468 | static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
469 | int clk_id, unsigned int freq, int dir) | ||
470 | { | ||
471 | struct snd_soc_codec *codec = codec_dai->codec; | ||
472 | struct wm8971_priv *wm8971 = codec->private_data; | ||
473 | |||
474 | switch (freq) { | ||
475 | case 11289600: | ||
476 | case 12000000: | ||
477 | case 12288000: | ||
478 | case 16934400: | ||
479 | case 18432000: | ||
480 | wm8971->sysclk = freq; | ||
481 | return 0; | ||
482 | } | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | |||
486 | static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
487 | unsigned int fmt) | ||
488 | { | ||
489 | struct snd_soc_codec *codec = codec_dai->codec; | ||
490 | u16 iface = 0; | ||
491 | |||
492 | /* set master/slave audio interface */ | ||
493 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
494 | case SND_SOC_DAIFMT_CBM_CFM: | ||
495 | iface = 0x0040; | ||
496 | break; | ||
497 | case SND_SOC_DAIFMT_CBS_CFS: | ||
498 | break; | ||
499 | default: | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | |||
503 | /* interface format */ | ||
504 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
505 | case SND_SOC_DAIFMT_I2S: | ||
506 | iface |= 0x0002; | ||
507 | break; | ||
508 | case SND_SOC_DAIFMT_RIGHT_J: | ||
509 | break; | ||
510 | case SND_SOC_DAIFMT_LEFT_J: | ||
511 | iface |= 0x0001; | ||
512 | break; | ||
513 | case SND_SOC_DAIFMT_DSP_A: | ||
514 | iface |= 0x0003; | ||
515 | break; | ||
516 | case SND_SOC_DAIFMT_DSP_B: | ||
517 | iface |= 0x0013; | ||
518 | break; | ||
519 | default: | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
523 | /* clock inversion */ | ||
524 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
525 | case SND_SOC_DAIFMT_NB_NF: | ||
526 | break; | ||
527 | case SND_SOC_DAIFMT_IB_IF: | ||
528 | iface |= 0x0090; | ||
529 | break; | ||
530 | case SND_SOC_DAIFMT_IB_NF: | ||
531 | iface |= 0x0080; | ||
532 | break; | ||
533 | case SND_SOC_DAIFMT_NB_IF: | ||
534 | iface |= 0x0010; | ||
535 | break; | ||
536 | default: | ||
537 | return -EINVAL; | ||
538 | } | ||
539 | |||
540 | wm8971_write(codec, WM8971_IFACE, iface); | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, | ||
545 | struct snd_pcm_hw_params *params) | ||
546 | { | ||
547 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
548 | struct snd_soc_device *socdev = rtd->socdev; | ||
549 | struct snd_soc_codec *codec = socdev->codec; | ||
550 | struct wm8971_priv *wm8971 = codec->private_data; | ||
551 | u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; | ||
552 | u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; | ||
553 | int coeff = get_coeff(wm8971->sysclk, params_rate(params)); | ||
554 | |||
555 | /* bit size */ | ||
556 | switch (params_format(params)) { | ||
557 | case SNDRV_PCM_FORMAT_S16_LE: | ||
558 | break; | ||
559 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
560 | iface |= 0x0004; | ||
561 | break; | ||
562 | case SNDRV_PCM_FORMAT_S24_LE: | ||
563 | iface |= 0x0008; | ||
564 | break; | ||
565 | case SNDRV_PCM_FORMAT_S32_LE: | ||
566 | iface |= 0x000c; | ||
567 | break; | ||
568 | } | ||
569 | |||
570 | /* set iface & srate */ | ||
571 | wm8971_write(codec, WM8971_IFACE, iface); | ||
572 | if (coeff >= 0) | ||
573 | wm8971_write(codec, WM8971_SRATE, srate | | ||
574 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | ||
575 | |||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static int wm8971_mute(struct snd_soc_dai *dai, int mute) | ||
580 | { | ||
581 | struct snd_soc_codec *codec = dai->codec; | ||
582 | u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7; | ||
583 | |||
584 | if (mute) | ||
585 | wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8); | ||
586 | else | ||
587 | wm8971_write(codec, WM8971_ADCDAC, mute_reg); | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int wm8971_set_bias_level(struct snd_soc_codec *codec, | ||
592 | enum snd_soc_bias_level level) | ||
593 | { | ||
594 | u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
595 | |||
596 | switch (level) { | ||
597 | case SND_SOC_BIAS_ON: | ||
598 | /* set vmid to 50k and unmute dac */ | ||
599 | wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); | ||
600 | break; | ||
601 | case SND_SOC_BIAS_PREPARE: | ||
602 | break; | ||
603 | case SND_SOC_BIAS_STANDBY: | ||
604 | /* mute dac and set vmid to 500k, enable VREF */ | ||
605 | wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140); | ||
606 | break; | ||
607 | case SND_SOC_BIAS_OFF: | ||
608 | wm8971_write(codec, WM8971_PWR1, 0x0001); | ||
609 | break; | ||
610 | } | ||
611 | codec->bias_level = level; | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | #define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
616 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
617 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
618 | |||
619 | #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
620 | SNDRV_PCM_FMTBIT_S24_LE) | ||
621 | |||
622 | struct snd_soc_dai wm8971_dai = { | ||
623 | .name = "WM8971", | ||
624 | .playback = { | ||
625 | .stream_name = "Playback", | ||
626 | .channels_min = 1, | ||
627 | .channels_max = 2, | ||
628 | .rates = WM8971_RATES, | ||
629 | .formats = WM8971_FORMATS,}, | ||
630 | .capture = { | ||
631 | .stream_name = "Capture", | ||
632 | .channels_min = 1, | ||
633 | .channels_max = 2, | ||
634 | .rates = WM8971_RATES, | ||
635 | .formats = WM8971_FORMATS,}, | ||
636 | .ops = { | ||
637 | .hw_params = wm8971_pcm_hw_params, | ||
638 | }, | ||
639 | .dai_ops = { | ||
640 | .digital_mute = wm8971_mute, | ||
641 | .set_fmt = wm8971_set_dai_fmt, | ||
642 | .set_sysclk = wm8971_set_dai_sysclk, | ||
643 | }, | ||
644 | }; | ||
645 | EXPORT_SYMBOL_GPL(wm8971_dai); | ||
646 | |||
647 | static void wm8971_work(struct work_struct *work) | ||
648 | { | ||
649 | struct snd_soc_codec *codec = | ||
650 | container_of(work, struct snd_soc_codec, delayed_work.work); | ||
651 | wm8971_set_bias_level(codec, codec->bias_level); | ||
652 | } | ||
653 | |||
654 | static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) | ||
655 | { | ||
656 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
657 | struct snd_soc_codec *codec = socdev->codec; | ||
658 | |||
659 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static int wm8971_resume(struct platform_device *pdev) | ||
664 | { | ||
665 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
666 | struct snd_soc_codec *codec = socdev->codec; | ||
667 | int i; | ||
668 | u8 data[2]; | ||
669 | u16 *cache = codec->reg_cache; | ||
670 | u16 reg; | ||
671 | |||
672 | /* Sync reg_cache with the hardware */ | ||
673 | for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) { | ||
674 | if (i + 1 == WM8971_RESET) | ||
675 | continue; | ||
676 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
677 | data[1] = cache[i] & 0x00ff; | ||
678 | codec->hw_write(codec->control_data, data, 2); | ||
679 | } | ||
680 | |||
681 | wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
682 | |||
683 | /* charge wm8971 caps */ | ||
684 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | ||
685 | reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
686 | wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); | ||
687 | codec->bias_level = SND_SOC_BIAS_ON; | ||
688 | queue_delayed_work(wm8971_workq, &codec->delayed_work, | ||
689 | msecs_to_jiffies(1000)); | ||
690 | } | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int wm8971_init(struct snd_soc_device *socdev) | ||
696 | { | ||
697 | struct snd_soc_codec *codec = socdev->codec; | ||
698 | int reg, ret = 0; | ||
699 | |||
700 | codec->name = "WM8971"; | ||
701 | codec->owner = THIS_MODULE; | ||
702 | codec->read = wm8971_read_reg_cache; | ||
703 | codec->write = wm8971_write; | ||
704 | codec->set_bias_level = wm8971_set_bias_level; | ||
705 | codec->dai = &wm8971_dai; | ||
706 | codec->reg_cache_size = ARRAY_SIZE(wm8971_reg); | ||
707 | codec->num_dai = 1; | ||
708 | codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL); | ||
709 | |||
710 | if (codec->reg_cache == NULL) | ||
711 | return -ENOMEM; | ||
712 | |||
713 | wm8971_reset(codec); | ||
714 | |||
715 | /* register pcms */ | ||
716 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
717 | if (ret < 0) { | ||
718 | printk(KERN_ERR "wm8971: failed to create pcms\n"); | ||
719 | goto pcm_err; | ||
720 | } | ||
721 | |||
722 | /* charge output caps - set vmid to 5k for quick power up */ | ||
723 | reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
724 | wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); | ||
725 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
726 | queue_delayed_work(wm8971_workq, &codec->delayed_work, | ||
727 | msecs_to_jiffies(1000)); | ||
728 | |||
729 | /* set the update bits */ | ||
730 | reg = wm8971_read_reg_cache(codec, WM8971_LDAC); | ||
731 | wm8971_write(codec, WM8971_LDAC, reg | 0x0100); | ||
732 | reg = wm8971_read_reg_cache(codec, WM8971_RDAC); | ||
733 | wm8971_write(codec, WM8971_RDAC, reg | 0x0100); | ||
734 | |||
735 | reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V); | ||
736 | wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100); | ||
737 | reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V); | ||
738 | wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100); | ||
739 | |||
740 | reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V); | ||
741 | wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100); | ||
742 | reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V); | ||
743 | wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100); | ||
744 | |||
745 | reg = wm8971_read_reg_cache(codec, WM8971_LINVOL); | ||
746 | wm8971_write(codec, WM8971_LINVOL, reg | 0x0100); | ||
747 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); | ||
748 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); | ||
749 | |||
750 | wm8971_add_controls(codec); | ||
751 | wm8971_add_widgets(codec); | ||
752 | ret = snd_soc_register_card(socdev); | ||
753 | if (ret < 0) { | ||
754 | printk(KERN_ERR "wm8971: failed to register card\n"); | ||
755 | goto card_err; | ||
756 | } | ||
757 | return ret; | ||
758 | |||
759 | card_err: | ||
760 | snd_soc_free_pcms(socdev); | ||
761 | snd_soc_dapm_free(socdev); | ||
762 | pcm_err: | ||
763 | kfree(codec->reg_cache); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
768 | around */ | ||
769 | static struct snd_soc_device *wm8971_socdev; | ||
770 | |||
771 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
772 | |||
773 | static int wm8971_i2c_probe(struct i2c_client *i2c, | ||
774 | const struct i2c_device_id *id) | ||
775 | { | ||
776 | struct snd_soc_device *socdev = wm8971_socdev; | ||
777 | struct snd_soc_codec *codec = socdev->codec; | ||
778 | int ret; | ||
779 | |||
780 | i2c_set_clientdata(i2c, codec); | ||
781 | |||
782 | codec->control_data = i2c; | ||
783 | |||
784 | ret = wm8971_init(socdev); | ||
785 | if (ret < 0) | ||
786 | pr_err("failed to initialise WM8971\n"); | ||
787 | |||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | static int wm8971_i2c_remove(struct i2c_client *client) | ||
792 | { | ||
793 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
794 | kfree(codec->reg_cache); | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static const struct i2c_device_id wm8971_i2c_id[] = { | ||
799 | { "wm8971", 0 }, | ||
800 | { } | ||
801 | }; | ||
802 | MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id); | ||
803 | |||
804 | static struct i2c_driver wm8971_i2c_driver = { | ||
805 | .driver = { | ||
806 | .name = "WM8971 I2C Codec", | ||
807 | .owner = THIS_MODULE, | ||
808 | }, | ||
809 | .probe = wm8971_i2c_probe, | ||
810 | .remove = wm8971_i2c_remove, | ||
811 | .id_table = wm8971_i2c_id, | ||
812 | }; | ||
813 | |||
814 | static int wm8971_add_i2c_device(struct platform_device *pdev, | ||
815 | const struct wm8971_setup_data *setup) | ||
816 | { | ||
817 | struct i2c_board_info info; | ||
818 | struct i2c_adapter *adapter; | ||
819 | struct i2c_client *client; | ||
820 | int ret; | ||
821 | |||
822 | ret = i2c_add_driver(&wm8971_i2c_driver); | ||
823 | if (ret != 0) { | ||
824 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
829 | info.addr = setup->i2c_address; | ||
830 | strlcpy(info.type, "wm8971", I2C_NAME_SIZE); | ||
831 | |||
832 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
833 | if (!adapter) { | ||
834 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
835 | setup->i2c_bus); | ||
836 | goto err_driver; | ||
837 | } | ||
838 | |||
839 | client = i2c_new_device(adapter, &info); | ||
840 | i2c_put_adapter(adapter); | ||
841 | if (!client) { | ||
842 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
843 | (unsigned int)info.addr); | ||
844 | goto err_driver; | ||
845 | } | ||
846 | |||
847 | return 0; | ||
848 | |||
849 | err_driver: | ||
850 | i2c_del_driver(&wm8971_i2c_driver); | ||
851 | return -ENODEV; | ||
852 | } | ||
853 | |||
854 | #endif | ||
855 | |||
856 | static int wm8971_probe(struct platform_device *pdev) | ||
857 | { | ||
858 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
859 | struct wm8971_setup_data *setup; | ||
860 | struct snd_soc_codec *codec; | ||
861 | struct wm8971_priv *wm8971; | ||
862 | int ret = 0; | ||
863 | |||
864 | pr_info("WM8971 Audio Codec %s", WM8971_VERSION); | ||
865 | |||
866 | setup = socdev->codec_data; | ||
867 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
868 | if (codec == NULL) | ||
869 | return -ENOMEM; | ||
870 | |||
871 | wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL); | ||
872 | if (wm8971 == NULL) { | ||
873 | kfree(codec); | ||
874 | return -ENOMEM; | ||
875 | } | ||
876 | |||
877 | codec->private_data = wm8971; | ||
878 | socdev->codec = codec; | ||
879 | mutex_init(&codec->mutex); | ||
880 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
881 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
882 | wm8971_socdev = socdev; | ||
883 | |||
884 | INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work); | ||
885 | wm8971_workq = create_workqueue("wm8971"); | ||
886 | if (wm8971_workq == NULL) { | ||
887 | kfree(codec->private_data); | ||
888 | kfree(codec); | ||
889 | return -ENOMEM; | ||
890 | } | ||
891 | |||
892 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
893 | if (setup->i2c_address) { | ||
894 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
895 | ret = wm8971_add_i2c_device(pdev, setup); | ||
896 | } | ||
897 | #endif | ||
898 | /* Add other interfaces here */ | ||
899 | |||
900 | if (ret != 0) { | ||
901 | destroy_workqueue(wm8971_workq); | ||
902 | kfree(codec->private_data); | ||
903 | kfree(codec); | ||
904 | } | ||
905 | |||
906 | return ret; | ||
907 | } | ||
908 | |||
909 | /* power down chip */ | ||
910 | static int wm8971_remove(struct platform_device *pdev) | ||
911 | { | ||
912 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
913 | struct snd_soc_codec *codec = socdev->codec; | ||
914 | |||
915 | if (codec->control_data) | ||
916 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
917 | if (wm8971_workq) | ||
918 | destroy_workqueue(wm8971_workq); | ||
919 | snd_soc_free_pcms(socdev); | ||
920 | snd_soc_dapm_free(socdev); | ||
921 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
922 | i2c_unregister_device(codec->control_data); | ||
923 | i2c_del_driver(&wm8971_i2c_driver); | ||
924 | #endif | ||
925 | kfree(codec->private_data); | ||
926 | kfree(codec); | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | struct snd_soc_codec_device soc_codec_dev_wm8971 = { | ||
932 | .probe = wm8971_probe, | ||
933 | .remove = wm8971_remove, | ||
934 | .suspend = wm8971_suspend, | ||
935 | .resume = wm8971_resume, | ||
936 | }; | ||
937 | |||
938 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); | ||
939 | |||
940 | MODULE_DESCRIPTION("ASoC WM8971 driver"); | ||
941 | MODULE_AUTHOR("Lab126"); | ||
942 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h new file mode 100644 index 00000000000..ef4f08f9f34 --- /dev/null +++ b/sound/soc/codecs/wm8971.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * wm8971.h -- audio driver for WM8971 | ||
3 | * | ||
4 | * Copyright 2005 Lab126, Inc. | ||
5 | * | ||
6 | * Author: Kenneth Kiraly <kiraly@lab126.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef _WM8971_H | ||
16 | #define _WM8971_H | ||
17 | |||
18 | #define WM8971_LINVOL 0x00 | ||
19 | #define WM8971_RINVOL 0x01 | ||
20 | #define WM8971_LOUT1V 0x02 | ||
21 | #define WM8971_ROUT1V 0x03 | ||
22 | #define WM8971_ADCDAC 0x05 | ||
23 | #define WM8971_IFACE 0x07 | ||
24 | #define WM8971_SRATE 0x08 | ||
25 | #define WM8971_LDAC 0x0a | ||
26 | #define WM8971_RDAC 0x0b | ||
27 | #define WM8971_BASS 0x0c | ||
28 | #define WM8971_TREBLE 0x0d | ||
29 | #define WM8971_RESET 0x0f | ||
30 | #define WM8971_ALC1 0x11 | ||
31 | #define WM8971_ALC2 0x12 | ||
32 | #define WM8971_ALC3 0x13 | ||
33 | #define WM8971_NGATE 0x14 | ||
34 | #define WM8971_LADC 0x15 | ||
35 | #define WM8971_RADC 0x16 | ||
36 | #define WM8971_ADCTL1 0x17 | ||
37 | #define WM8971_ADCTL2 0x18 | ||
38 | #define WM8971_PWR1 0x19 | ||
39 | #define WM8971_PWR2 0x1a | ||
40 | #define WM8971_ADCTL3 0x1b | ||
41 | #define WM8971_ADCIN 0x1f | ||
42 | #define WM8971_LADCIN 0x20 | ||
43 | #define WM8971_RADCIN 0x21 | ||
44 | #define WM8971_LOUTM1 0x22 | ||
45 | #define WM8971_LOUTM2 0x23 | ||
46 | #define WM8971_ROUTM1 0x24 | ||
47 | #define WM8971_ROUTM2 0x25 | ||
48 | #define WM8971_MOUTM1 0x26 | ||
49 | #define WM8971_MOUTM2 0x27 | ||
50 | #define WM8971_LOUT2V 0x28 | ||
51 | #define WM8971_ROUT2V 0x29 | ||
52 | #define WM8971_MOUTV 0x2A | ||
53 | |||
54 | #define WM8971_SYSCLK 0 | ||
55 | |||
56 | struct wm8971_setup_data { | ||
57 | int i2c_bus; | ||
58 | unsigned short i2c_address; | ||
59 | }; | ||
60 | |||
61 | extern struct snd_soc_dai wm8971_dai; | ||
62 | extern struct snd_soc_codec_device soc_codec_dev_wm8971; | ||
63 | |||
64 | #endif | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index dd995ef448b..63410d7b5ef 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1477,81 +1477,86 @@ static struct snd_soc_device *wm8990_socdev; | |||
1477 | * low = 0x34 | 1477 | * low = 0x34 |
1478 | * high = 0x36 | 1478 | * high = 0x36 |
1479 | */ | 1479 | */ |
1480 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1481 | 1480 | ||
1482 | /* Magic definition of all other variables and things */ | 1481 | static int wm8990_i2c_probe(struct i2c_client *i2c, |
1483 | I2C_CLIENT_INSMOD; | 1482 | const struct i2c_device_id *id) |
1484 | |||
1485 | static struct i2c_driver wm8990_i2c_driver; | ||
1486 | static struct i2c_client client_template; | ||
1487 | |||
1488 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1489 | { | 1483 | { |
1490 | struct snd_soc_device *socdev = wm8990_socdev; | 1484 | struct snd_soc_device *socdev = wm8990_socdev; |
1491 | struct wm8990_setup_data *setup = socdev->codec_data; | ||
1492 | struct snd_soc_codec *codec = socdev->codec; | 1485 | struct snd_soc_codec *codec = socdev->codec; |
1493 | struct i2c_client *i2c; | ||
1494 | int ret; | 1486 | int ret; |
1495 | 1487 | ||
1496 | if (addr != setup->i2c_address) | ||
1497 | return -ENODEV; | ||
1498 | |||
1499 | client_template.adapter = adap; | ||
1500 | client_template.addr = addr; | ||
1501 | |||
1502 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1503 | if (i2c == NULL) | ||
1504 | return -ENOMEM; | ||
1505 | |||
1506 | i2c_set_clientdata(i2c, codec); | 1488 | i2c_set_clientdata(i2c, codec); |
1507 | codec->control_data = i2c; | 1489 | codec->control_data = i2c; |
1508 | 1490 | ||
1509 | ret = i2c_attach_client(i2c); | ||
1510 | if (ret < 0) { | ||
1511 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1512 | goto err; | ||
1513 | } | ||
1514 | |||
1515 | ret = wm8990_init(socdev); | 1491 | ret = wm8990_init(socdev); |
1516 | if (ret < 0) { | 1492 | if (ret < 0) |
1517 | pr_err("failed to initialise WM8990\n"); | 1493 | pr_err("failed to initialise WM8990\n"); |
1518 | goto err; | ||
1519 | } | ||
1520 | return ret; | ||
1521 | 1494 | ||
1522 | err: | ||
1523 | kfree(i2c); | ||
1524 | return ret; | 1495 | return ret; |
1525 | } | 1496 | } |
1526 | 1497 | ||
1527 | static int wm8990_i2c_detach(struct i2c_client *client) | 1498 | static int wm8990_i2c_remove(struct i2c_client *client) |
1528 | { | 1499 | { |
1529 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1500 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1530 | i2c_detach_client(client); | ||
1531 | kfree(codec->reg_cache); | 1501 | kfree(codec->reg_cache); |
1532 | kfree(client); | ||
1533 | return 0; | 1502 | return 0; |
1534 | } | 1503 | } |
1535 | 1504 | ||
1536 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | 1505 | static const struct i2c_device_id wm8990_i2c_id[] = { |
1537 | { | 1506 | { "wm8990", 0 }, |
1538 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | 1507 | { } |
1539 | } | 1508 | }; |
1509 | MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); | ||
1540 | 1510 | ||
1541 | static struct i2c_driver wm8990_i2c_driver = { | 1511 | static struct i2c_driver wm8990_i2c_driver = { |
1542 | .driver = { | 1512 | .driver = { |
1543 | .name = "WM8990 I2C Codec", | 1513 | .name = "WM8990 I2C Codec", |
1544 | .owner = THIS_MODULE, | 1514 | .owner = THIS_MODULE, |
1545 | }, | 1515 | }, |
1546 | .attach_adapter = wm8990_i2c_attach, | 1516 | .probe = wm8990_i2c_probe, |
1547 | .detach_client = wm8990_i2c_detach, | 1517 | .remove = wm8990_i2c_remove, |
1548 | .command = NULL, | 1518 | .id_table = wm8990_i2c_id, |
1549 | }; | 1519 | }; |
1550 | 1520 | ||
1551 | static struct i2c_client client_template = { | 1521 | static int wm8990_add_i2c_device(struct platform_device *pdev, |
1552 | .name = "WM8990", | 1522 | const struct wm8990_setup_data *setup) |
1553 | .driver = &wm8990_i2c_driver, | 1523 | { |
1554 | }; | 1524 | struct i2c_board_info info; |
1525 | struct i2c_adapter *adapter; | ||
1526 | struct i2c_client *client; | ||
1527 | int ret; | ||
1528 | |||
1529 | ret = i2c_add_driver(&wm8990_i2c_driver); | ||
1530 | if (ret != 0) { | ||
1531 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1532 | return ret; | ||
1533 | } | ||
1534 | |||
1535 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1536 | info.addr = setup->i2c_address; | ||
1537 | strlcpy(info.type, "wm8990", I2C_NAME_SIZE); | ||
1538 | |||
1539 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1540 | if (!adapter) { | ||
1541 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1542 | setup->i2c_bus); | ||
1543 | goto err_driver; | ||
1544 | } | ||
1545 | |||
1546 | client = i2c_new_device(adapter, &info); | ||
1547 | i2c_put_adapter(adapter); | ||
1548 | if (!client) { | ||
1549 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1550 | (unsigned int)info.addr); | ||
1551 | goto err_driver; | ||
1552 | } | ||
1553 | |||
1554 | return 0; | ||
1555 | |||
1556 | err_driver: | ||
1557 | i2c_del_driver(&wm8990_i2c_driver); | ||
1558 | return -ENODEV; | ||
1559 | } | ||
1555 | #endif | 1560 | #endif |
1556 | 1561 | ||
1557 | static int wm8990_probe(struct platform_device *pdev) | 1562 | static int wm8990_probe(struct platform_device *pdev) |
@@ -1560,7 +1565,7 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1560 | struct wm8990_setup_data *setup; | 1565 | struct wm8990_setup_data *setup; |
1561 | struct snd_soc_codec *codec; | 1566 | struct snd_soc_codec *codec; |
1562 | struct wm8990_priv *wm8990; | 1567 | struct wm8990_priv *wm8990; |
1563 | int ret = 0; | 1568 | int ret; |
1564 | 1569 | ||
1565 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | 1570 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); |
1566 | 1571 | ||
@@ -1582,16 +1587,13 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1582 | INIT_LIST_HEAD(&codec->dapm_paths); | 1587 | INIT_LIST_HEAD(&codec->dapm_paths); |
1583 | wm8990_socdev = socdev; | 1588 | wm8990_socdev = socdev; |
1584 | 1589 | ||
1590 | ret = -ENODEV; | ||
1591 | |||
1585 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1592 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1586 | if (setup->i2c_address) { | 1593 | if (setup->i2c_address) { |
1587 | normal_i2c[0] = setup->i2c_address; | ||
1588 | codec->hw_write = (hw_write_t)i2c_master_send; | 1594 | codec->hw_write = (hw_write_t)i2c_master_send; |
1589 | ret = i2c_add_driver(&wm8990_i2c_driver); | 1595 | ret = wm8990_add_i2c_device(pdev, setup); |
1590 | if (ret != 0) | ||
1591 | printk(KERN_ERR "can't add i2c driver"); | ||
1592 | } | 1596 | } |
1593 | #else | ||
1594 | /* Add other interfaces here */ | ||
1595 | #endif | 1597 | #endif |
1596 | 1598 | ||
1597 | if (ret != 0) { | 1599 | if (ret != 0) { |
@@ -1612,6 +1614,7 @@ static int wm8990_remove(struct platform_device *pdev) | |||
1612 | snd_soc_free_pcms(socdev); | 1614 | snd_soc_free_pcms(socdev); |
1613 | snd_soc_dapm_free(socdev); | 1615 | snd_soc_dapm_free(socdev); |
1614 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1616 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1617 | i2c_unregister_device(codec->control_data); | ||
1615 | i2c_del_driver(&wm8990_i2c_driver); | 1618 | i2c_del_driver(&wm8990_i2c_driver); |
1616 | #endif | 1619 | #endif |
1617 | kfree(codec->private_data); | 1620 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 0a08325d544..0e192f3b078 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h | |||
@@ -827,6 +827,7 @@ | |||
827 | #define WM8990_AINRMUX_PWR_BIT 3 | 827 | #define WM8990_AINRMUX_PWR_BIT 3 |
828 | 828 | ||
829 | struct wm8990_setup_data { | 829 | struct wm8990_setup_data { |
830 | unsigned i2c_bus; | ||
830 | unsigned short i2c_address; | 831 | unsigned short i2c_address; |
831 | }; | 832 | }; |
832 | 833 | ||
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 38d1fe0971f..441d0580db1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -419,8 +419,12 @@ SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | |||
419 | SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | 419 | SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), |
420 | SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1), | 420 | SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1), |
421 | SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1), | 421 | SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1), |
422 | SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", AC97_EXTENDED_MID, 5, 1), | 422 | SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0), |
423 | SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", AC97_EXTENDED_MID, 4, 1), | 423 | SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0), |
424 | SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
425 | SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
426 | SND_SOC_DAPM_ADC("Left Voice ADC", "Left Voice Capture", SND_SOC_NOPM, 0, 0), | ||
427 | SND_SOC_DAPM_ADC("Right Voice ADC", "Right Voice Capture", SND_SOC_NOPM, 0, 0), | ||
424 | SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0), | 428 | SND_SOC_DAPM_PGA("Left Headphone", AC97_EXTENDED_MSTATUS, 10, 1, NULL, 0), |
425 | SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0), | 429 | SND_SOC_DAPM_PGA("Right Headphone", AC97_EXTENDED_MSTATUS, 9, 1, NULL, 0), |
426 | SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0), | 430 | SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0), |
@@ -583,9 +587,13 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 587 | ||
584 | /* left ADC */ | 588 | /* left ADC */ |
585 | {"Left ADC", NULL, "Left Capture Source"}, | 589 | {"Left ADC", NULL, "Left Capture Source"}, |
590 | {"Left Voice ADC", NULL, "Left ADC"}, | ||
591 | {"Left HiFi ADC", NULL, "Left ADC"}, | ||
586 | 592 | ||
587 | /* right ADC */ | 593 | /* right ADC */ |
588 | {"Right ADC", NULL, "Right Capture Source"}, | 594 | {"Right ADC", NULL, "Right Capture Source"}, |
595 | {"Right Voice ADC", NULL, "Right ADC"}, | ||
596 | {"Right HiFi ADC", NULL, "Right ADC"}, | ||
589 | 597 | ||
590 | /* mic */ | 598 | /* mic */ |
591 | {"Mic A Pre Amp", NULL, "Mic A Source"}, | 599 | {"Mic A Pre Amp", NULL, "Mic A Source"}, |
@@ -949,17 +957,17 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, | |||
949 | 957 | ||
950 | static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) | 958 | static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) |
951 | { | 959 | { |
952 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 960 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
953 | struct snd_soc_device *socdev = rtd->socdev; | 961 | struct snd_soc_device *socdev = rtd->socdev; |
954 | struct snd_soc_codec *codec = socdev->codec; | 962 | struct snd_soc_codec *codec = socdev->codec; |
955 | u16 status; | 963 | u16 status; |
956 | 964 | ||
957 | /* Gracefully shut down the voice interface. */ | 965 | /* Gracefully shut down the voice interface. */ |
958 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; | 966 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; |
959 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); | 967 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); |
960 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | 968 | schedule_timeout_interruptible(msecs_to_jiffies(1)); |
961 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); | 969 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); |
962 | ac97_write(codec, AC97_EXTENDED_MID, status); | 970 | ac97_write(codec, AC97_EXTENDED_MID, status); |
963 | } | 971 | } |
964 | 972 | ||
965 | static int ac97_hifi_prepare(struct snd_pcm_substream *substream) | 973 | static int ac97_hifi_prepare(struct snd_pcm_substream *substream) |