diff options
Diffstat (limited to 'sound/soc/codecs')
40 files changed, 10782 insertions, 588 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1db04a28a53d..38a0e3b620a7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1,32 +1,45 @@ | |||
1 | config SND_SOC_AC97_CODEC | 1 | config SND_SOC_ALL_CODECS |
2 | tristate | 2 | tristate "Build all ASoC CODEC drivers" |
3 | select SND_AC97_CODEC | 3 | depends on I2C |
4 | 4 | select SPI | |
5 | config SND_SOC_AK4535 | 5 | select SPI_MASTER |
6 | tristate | 6 | select SND_SOC_AD73311 |
7 | 7 | select SND_SOC_AK4535 | |
8 | config SND_SOC_UDA1380 | 8 | select SND_SOC_CS4270 |
9 | tristate | 9 | select SND_SOC_SSM2602 |
10 | select SND_SOC_TLV320AIC23 | ||
11 | select SND_SOC_TLV320AIC26 | ||
12 | select SND_SOC_TLV320AIC3X | ||
13 | select SND_SOC_UDA1380 | ||
14 | select SND_SOC_WM8510 | ||
15 | select SND_SOC_WM8580 | ||
16 | select SND_SOC_WM8731 | ||
17 | select SND_SOC_WM8750 | ||
18 | select SND_SOC_WM8753 | ||
19 | select SND_SOC_WM8900 | ||
20 | select SND_SOC_WM8903 | ||
21 | select SND_SOC_WM8971 | ||
22 | select SND_SOC_WM8990 | ||
23 | help | ||
24 | Normally ASoC codec drivers are only built if a machine driver which | ||
25 | uses them is also built since they are only usable with a machine | ||
26 | driver. Selecting this option will allow these drivers to be built | ||
27 | without an explicit machine driver for test and development purposes. | ||
10 | 28 | ||
11 | config SND_SOC_WM8510 | 29 | If unsure select "N". |
12 | tristate | ||
13 | 30 | ||
14 | config SND_SOC_WM8731 | ||
15 | tristate | ||
16 | 31 | ||
17 | config SND_SOC_WM8750 | 32 | config SND_SOC_AC97_CODEC |
18 | tristate | ||
19 | |||
20 | config SND_SOC_WM8753 | ||
21 | tristate | 33 | tristate |
34 | select SND_AC97_CODEC | ||
22 | 35 | ||
23 | config SND_SOC_WM8990 | 36 | config SND_SOC_AD1980 |
24 | tristate | 37 | tristate |
25 | 38 | ||
26 | config SND_SOC_WM9712 | 39 | config SND_SOC_AD73311 |
27 | tristate | 40 | tristate |
28 | 41 | ||
29 | config SND_SOC_WM9713 | 42 | config SND_SOC_AK4535 |
30 | tristate | 43 | tristate |
31 | 44 | ||
32 | # Cirrus Logic CS4270 Codec | 45 | # Cirrus Logic CS4270 Codec |
@@ -47,6 +60,53 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
47 | bool | 60 | bool |
48 | depends on SND_SOC_CS4270 | 61 | depends on SND_SOC_CS4270 |
49 | 62 | ||
63 | config SND_SOC_SSM2602 | ||
64 | tristate | ||
65 | |||
66 | config SND_SOC_TLV320AIC23 | ||
67 | tristate | ||
68 | depends on I2C | ||
69 | |||
70 | config SND_SOC_TLV320AIC26 | ||
71 | tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE | ||
72 | depends on SPI | ||
73 | |||
50 | config SND_SOC_TLV320AIC3X | 74 | config SND_SOC_TLV320AIC3X |
51 | tristate | 75 | tristate |
52 | depends on I2C | 76 | depends on I2C |
77 | |||
78 | config SND_SOC_UDA1380 | ||
79 | tristate | ||
80 | |||
81 | config SND_SOC_WM8510 | ||
82 | tristate | ||
83 | |||
84 | config SND_SOC_WM8580 | ||
85 | tristate | ||
86 | |||
87 | config SND_SOC_WM8731 | ||
88 | tristate | ||
89 | |||
90 | config SND_SOC_WM8750 | ||
91 | tristate | ||
92 | |||
93 | config SND_SOC_WM8753 | ||
94 | tristate | ||
95 | |||
96 | config SND_SOC_WM8900 | ||
97 | tristate | ||
98 | |||
99 | config SND_SOC_WM8903 | ||
100 | tristate | ||
101 | |||
102 | config SND_SOC_WM8971 | ||
103 | tristate | ||
104 | |||
105 | config SND_SOC_WM8990 | ||
106 | tristate | ||
107 | |||
108 | config SND_SOC_WM9712 | ||
109 | tristate | ||
110 | |||
111 | config SND_SOC_WM9713 | ||
112 | tristate | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d7b97abcf729..90f0a585fc70 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,25 +1,43 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ad1980-objs := ad1980.o | ||
3 | snd-soc-ad73311-objs := ad73311.o | ||
2 | snd-soc-ak4535-objs := ak4535.o | 4 | snd-soc-ak4535-objs := ak4535.o |
5 | snd-soc-cs4270-objs := cs4270.o | ||
6 | snd-soc-ssm2602-objs := ssm2602.o | ||
7 | snd-soc-tlv320aic23-objs := tlv320aic23.o | ||
8 | snd-soc-tlv320aic26-objs := tlv320aic26.o | ||
9 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
3 | snd-soc-uda1380-objs := uda1380.o | 10 | snd-soc-uda1380-objs := uda1380.o |
4 | snd-soc-wm8510-objs := wm8510.o | 11 | snd-soc-wm8510-objs := wm8510.o |
12 | snd-soc-wm8580-objs := wm8580.o | ||
5 | snd-soc-wm8731-objs := wm8731.o | 13 | snd-soc-wm8731-objs := wm8731.o |
6 | snd-soc-wm8750-objs := wm8750.o | 14 | snd-soc-wm8750-objs := wm8750.o |
7 | snd-soc-wm8753-objs := wm8753.o | 15 | snd-soc-wm8753-objs := wm8753.o |
16 | snd-soc-wm8900-objs := wm8900.o | ||
17 | snd-soc-wm8903-objs := wm8903.o | ||
18 | snd-soc-wm8971-objs := wm8971.o | ||
8 | snd-soc-wm8990-objs := wm8990.o | 19 | snd-soc-wm8990-objs := wm8990.o |
9 | snd-soc-wm9712-objs := wm9712.o | 20 | snd-soc-wm9712-objs := wm9712.o |
10 | snd-soc-wm9713-objs := wm9713.o | 21 | snd-soc-wm9713-objs := wm9713.o |
11 | snd-soc-cs4270-objs := cs4270.o | ||
12 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
13 | 22 | ||
14 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 23 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
24 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | ||
25 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | ||
15 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 26 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
27 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | ||
28 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | ||
29 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | ||
30 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | ||
31 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
16 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | 32 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o |
17 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 33 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
34 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o | ||
18 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 35 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
19 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 36 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
20 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 37 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
38 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | ||
39 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | ||
40 | obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o | ||
21 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 41 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
22 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 42 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
23 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 43 | 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/ac97.c b/sound/soc/codecs/ac97.c index 61fd96ca7bc7..bd1ebdc6c86c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * ac97.c -- ALSA Soc AC97 codec support | 2 | * ac97.c -- ALSA Soc AC97 codec support |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * 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 | 8 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c new file mode 100644 index 000000000000..1397b8e06c0b --- /dev/null +++ b/sound/soc/codecs/ad1980.c | |||
@@ -0,0 +1,308 @@ | |||
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/kernel.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/ac97_codec.h> | ||
21 | #include <sound/initval.h> | ||
22 | #include <sound/soc.h> | ||
23 | #include <sound/soc-dapm.h> | ||
24 | |||
25 | #include "ad1980.h" | ||
26 | |||
27 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
28 | unsigned int reg); | ||
29 | static int ac97_write(struct snd_soc_codec *codec, | ||
30 | unsigned int reg, unsigned int val); | ||
31 | |||
32 | /* | ||
33 | * AD1980 register cache | ||
34 | */ | ||
35 | static const u16 ad1980_reg[] = { | ||
36 | 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ | ||
37 | 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ | ||
38 | 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ | ||
39 | 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ | ||
40 | 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ | ||
41 | 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ | ||
42 | 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ | ||
43 | 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ | ||
44 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
45 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
46 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
47 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
48 | 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ | ||
49 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | ||
50 | 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ | ||
51 | 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ | ||
52 | }; | ||
53 | |||
54 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", | ||
55 | "Stereo Mix", "Mono Mix", "Phone"}; | ||
56 | |||
57 | static const struct soc_enum ad1980_cap_src = | ||
58 | SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); | ||
59 | |||
60 | static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { | ||
61 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), | ||
62 | SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1), | ||
63 | |||
64 | SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1), | ||
65 | SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1), | ||
66 | |||
67 | SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1), | ||
68 | SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1), | ||
69 | |||
70 | SOC_DOUBLE("PCM Capture Volume", AC97_REC_GAIN, 8, 0, 31, 0), | ||
71 | SOC_SINGLE("PCM Capture Switch", AC97_REC_GAIN, 15, 1, 1), | ||
72 | |||
73 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), | ||
74 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | ||
75 | |||
76 | SOC_SINGLE("Phone Capture Volume", AC97_PHONE, 0, 31, 1), | ||
77 | SOC_SINGLE("Phone Capture Switch", AC97_PHONE, 15, 1, 1), | ||
78 | |||
79 | SOC_SINGLE("Mic Volume", AC97_MIC, 0, 31, 1), | ||
80 | SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), | ||
81 | |||
82 | SOC_SINGLE("Stereo Mic Switch", AC97_AD_MISC, 6, 1, 0), | ||
83 | SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), | ||
84 | |||
85 | SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), | ||
86 | SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), | ||
87 | |||
88 | SOC_ENUM("Capture Source", ad1980_cap_src), | ||
89 | |||
90 | SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), | ||
91 | }; | ||
92 | |||
93 | /* add non dapm controls */ | ||
94 | static int ad1980_add_controls(struct snd_soc_codec *codec) | ||
95 | { | ||
96 | int err, i; | ||
97 | |||
98 | for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) { | ||
99 | err = snd_ctl_add(codec->card, snd_soc_cnew( | ||
100 | &ad1980_snd_ac97_controls[i], codec, NULL)); | ||
101 | if (err < 0) | ||
102 | return err; | ||
103 | } | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
108 | unsigned int reg) | ||
109 | { | ||
110 | u16 *cache = codec->reg_cache; | ||
111 | |||
112 | switch (reg) { | ||
113 | case AC97_RESET: | ||
114 | case AC97_INT_PAGING: | ||
115 | case AC97_POWERDOWN: | ||
116 | case AC97_EXTENDED_STATUS: | ||
117 | case AC97_VENDOR_ID1: | ||
118 | case AC97_VENDOR_ID2: | ||
119 | return soc_ac97_ops.read(codec->ac97, reg); | ||
120 | default: | ||
121 | reg = reg >> 1; | ||
122 | |||
123 | if (reg >= (ARRAY_SIZE(ad1980_reg))) | ||
124 | return -EINVAL; | ||
125 | |||
126 | return cache[reg]; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
131 | unsigned int val) | ||
132 | { | ||
133 | u16 *cache = codec->reg_cache; | ||
134 | |||
135 | soc_ac97_ops.write(codec->ac97, reg, val); | ||
136 | reg = reg >> 1; | ||
137 | if (reg < (ARRAY_SIZE(ad1980_reg))) | ||
138 | cache[reg] = val; | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | struct snd_soc_dai ad1980_dai = { | ||
144 | .name = "AC97", | ||
145 | .playback = { | ||
146 | .stream_name = "Playback", | ||
147 | .channels_min = 2, | ||
148 | .channels_max = 2, | ||
149 | .rates = SNDRV_PCM_RATE_48000, | ||
150 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
151 | .capture = { | ||
152 | .stream_name = "Capture", | ||
153 | .channels_min = 2, | ||
154 | .channels_max = 2, | ||
155 | .rates = SNDRV_PCM_RATE_48000, | ||
156 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
157 | }; | ||
158 | EXPORT_SYMBOL_GPL(ad1980_dai); | ||
159 | |||
160 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) | ||
161 | { | ||
162 | u16 retry_cnt = 0; | ||
163 | |||
164 | retry: | ||
165 | if (try_warm && soc_ac97_ops.warm_reset) { | ||
166 | soc_ac97_ops.warm_reset(codec->ac97); | ||
167 | if (ac97_read(codec, AC97_RESET) == 0x0090) | ||
168 | return 1; | ||
169 | } | ||
170 | |||
171 | soc_ac97_ops.reset(codec->ac97); | ||
172 | /* Set bit 16slot in register 74h, then every slot will has only 16 | ||
173 | * bits. This command is sent out in 20bit mode, in which case the | ||
174 | * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ | ||
175 | ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); | ||
176 | |||
177 | if (ac97_read(codec, AC97_RESET) != 0x0090) | ||
178 | goto err; | ||
179 | return 0; | ||
180 | |||
181 | err: | ||
182 | while (retry_cnt++ < 10) | ||
183 | goto retry; | ||
184 | |||
185 | printk(KERN_ERR "AD1980 AC97 reset failed\n"); | ||
186 | return -EIO; | ||
187 | } | ||
188 | |||
189 | static int ad1980_soc_probe(struct platform_device *pdev) | ||
190 | { | ||
191 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
192 | struct snd_soc_codec *codec; | ||
193 | int ret = 0; | ||
194 | u16 vendor_id2; | ||
195 | |||
196 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | ||
197 | |||
198 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
199 | if (socdev->codec == NULL) | ||
200 | return -ENOMEM; | ||
201 | codec = socdev->codec; | ||
202 | mutex_init(&codec->mutex); | ||
203 | |||
204 | codec->reg_cache = | ||
205 | kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL); | ||
206 | if (codec->reg_cache == NULL) { | ||
207 | ret = -ENOMEM; | ||
208 | goto cache_err; | ||
209 | } | ||
210 | memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \ | ||
211 | ARRAY_SIZE(ad1980_reg)); | ||
212 | codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg); | ||
213 | codec->reg_cache_step = 2; | ||
214 | codec->name = "AD1980"; | ||
215 | codec->owner = THIS_MODULE; | ||
216 | codec->dai = &ad1980_dai; | ||
217 | codec->num_dai = 1; | ||
218 | codec->write = ac97_write; | ||
219 | codec->read = ac97_read; | ||
220 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
221 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
222 | |||
223 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
224 | if (ret < 0) { | ||
225 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); | ||
226 | goto codec_err; | ||
227 | } | ||
228 | |||
229 | /* register pcms */ | ||
230 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
231 | if (ret < 0) | ||
232 | goto pcm_err; | ||
233 | |||
234 | |||
235 | ret = ad1980_reset(codec, 0); | ||
236 | if (ret < 0) { | ||
237 | printk(KERN_ERR "AC97 link error\n"); | ||
238 | goto reset_err; | ||
239 | } | ||
240 | |||
241 | /* Read out vendor ID to make sure it is ad1980 */ | ||
242 | if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) | ||
243 | goto reset_err; | ||
244 | |||
245 | vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); | ||
246 | |||
247 | if (vendor_id2 != 0x5370) { | ||
248 | if (vendor_id2 != 0x5374) | ||
249 | goto reset_err; | ||
250 | else | ||
251 | printk(KERN_WARNING "ad1980: " | ||
252 | "Found AD1981 - only 2/2 IN/OUT Channels " | ||
253 | "supported\n"); | ||
254 | } | ||
255 | |||
256 | ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ | ||
257 | ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ | ||
258 | ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ | ||
259 | |||
260 | ad1980_add_controls(codec); | ||
261 | ret = snd_soc_register_card(socdev); | ||
262 | if (ret < 0) { | ||
263 | printk(KERN_ERR "ad1980: failed to register card\n"); | ||
264 | goto reset_err; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | |||
269 | reset_err: | ||
270 | snd_soc_free_pcms(socdev); | ||
271 | |||
272 | pcm_err: | ||
273 | snd_soc_free_ac97_codec(codec); | ||
274 | |||
275 | codec_err: | ||
276 | kfree(codec->reg_cache); | ||
277 | |||
278 | cache_err: | ||
279 | kfree(socdev->codec); | ||
280 | socdev->codec = NULL; | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static int ad1980_soc_remove(struct platform_device *pdev) | ||
285 | { | ||
286 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
287 | struct snd_soc_codec *codec = socdev->codec; | ||
288 | |||
289 | if (codec == NULL) | ||
290 | return 0; | ||
291 | |||
292 | snd_soc_dapm_free(socdev); | ||
293 | snd_soc_free_pcms(socdev); | ||
294 | snd_soc_free_ac97_codec(codec); | ||
295 | kfree(codec->reg_cache); | ||
296 | kfree(codec); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | struct snd_soc_codec_device soc_codec_dev_ad1980 = { | ||
301 | .probe = ad1980_soc_probe, | ||
302 | .remove = ad1980_soc_remove, | ||
303 | }; | ||
304 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); | ||
305 | |||
306 | MODULE_DESCRIPTION("ASoC ad1980 driver"); | ||
307 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); | ||
308 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h new file mode 100644 index 000000000000..db6c8500d66b --- /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/ad73311.c b/sound/soc/codecs/ad73311.c new file mode 100644 index 000000000000..37af8607b00a --- /dev/null +++ b/sound/soc/codecs/ad73311.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * ad73311.c -- ALSA Soc AD73311 codec support | ||
3 | * | ||
4 | * Copyright: Analog Device Inc. | ||
5 | * Author: Cliff Cai <cliff.cai@analog.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 | * Revision history | ||
13 | * 25th Sep 2008 Initial version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/ac97_codec.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "ad73311.h" | ||
28 | |||
29 | struct snd_soc_dai ad73311_dai = { | ||
30 | .name = "AD73311", | ||
31 | .playback = { | ||
32 | .stream_name = "Playback", | ||
33 | .channels_min = 1, | ||
34 | .channels_max = 1, | ||
35 | .rates = SNDRV_PCM_RATE_8000, | ||
36 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
37 | .capture = { | ||
38 | .stream_name = "Capture", | ||
39 | .channels_min = 1, | ||
40 | .channels_max = 1, | ||
41 | .rates = SNDRV_PCM_RATE_8000, | ||
42 | .formats = SNDRV_PCM_FMTBIT_S16_LE, }, | ||
43 | }; | ||
44 | EXPORT_SYMBOL_GPL(ad73311_dai); | ||
45 | |||
46 | static int ad73311_soc_probe(struct platform_device *pdev) | ||
47 | { | ||
48 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
49 | struct snd_soc_codec *codec; | ||
50 | int ret = 0; | ||
51 | |||
52 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
53 | if (codec == NULL) | ||
54 | return -ENOMEM; | ||
55 | mutex_init(&codec->mutex); | ||
56 | codec->name = "AD73311"; | ||
57 | codec->owner = THIS_MODULE; | ||
58 | codec->dai = &ad73311_dai; | ||
59 | codec->num_dai = 1; | ||
60 | socdev->codec = codec; | ||
61 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
62 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
63 | |||
64 | /* register pcms */ | ||
65 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
66 | if (ret < 0) { | ||
67 | printk(KERN_ERR "ad73311: failed to create pcms\n"); | ||
68 | goto pcm_err; | ||
69 | } | ||
70 | |||
71 | ret = snd_soc_register_card(socdev); | ||
72 | if (ret < 0) { | ||
73 | printk(KERN_ERR "ad73311: failed to register card\n"); | ||
74 | goto register_err; | ||
75 | } | ||
76 | |||
77 | return ret; | ||
78 | |||
79 | register_err: | ||
80 | snd_soc_free_pcms(socdev); | ||
81 | pcm_err: | ||
82 | kfree(socdev->codec); | ||
83 | socdev->codec = NULL; | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static int ad73311_soc_remove(struct platform_device *pdev) | ||
88 | { | ||
89 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
90 | struct snd_soc_codec *codec = socdev->codec; | ||
91 | |||
92 | if (codec == NULL) | ||
93 | return 0; | ||
94 | snd_soc_free_pcms(socdev); | ||
95 | kfree(codec); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | struct snd_soc_codec_device soc_codec_dev_ad73311 = { | ||
100 | .probe = ad73311_soc_probe, | ||
101 | .remove = ad73311_soc_remove, | ||
102 | }; | ||
103 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); | ||
104 | |||
105 | MODULE_DESCRIPTION("ASoC ad73311 driver"); | ||
106 | MODULE_AUTHOR("Cliff Cai "); | ||
107 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h new file mode 100644 index 000000000000..507ce0c30edf --- /dev/null +++ b/sound/soc/codecs/ad73311.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * File: sound/soc/codec/ad73311.h | ||
3 | * Based on: | ||
4 | * Author: Cliff Cai <cliff.cai@analog.com> | ||
5 | * | ||
6 | * Created: Thur Sep 25, 2008 | ||
7 | * Description: definitions for AD73311 registers | ||
8 | * | ||
9 | * | ||
10 | * Modified: | ||
11 | * Copyright 2006 Analog Devices Inc. | ||
12 | * | ||
13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, see the file COPYING, or write | ||
27 | * to the Free Software Foundation, Inc., | ||
28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
29 | */ | ||
30 | |||
31 | #ifndef __AD73311_H__ | ||
32 | #define __AD73311_H__ | ||
33 | |||
34 | #define AD_CONTROL 0x8000 | ||
35 | #define AD_DATA 0x0000 | ||
36 | #define AD_READ 0x4000 | ||
37 | #define AD_WRITE 0x0000 | ||
38 | |||
39 | /* Control register A */ | ||
40 | #define CTRL_REG_A (0 << 8) | ||
41 | |||
42 | #define REGA_MODE_PRO 0x00 | ||
43 | #define REGA_MODE_DATA 0x01 | ||
44 | #define REGA_MODE_MIXED 0x03 | ||
45 | #define REGA_DLB 0x04 | ||
46 | #define REGA_SLB 0x08 | ||
47 | #define REGA_DEVC(x) ((x & 0x7) << 4) | ||
48 | #define REGA_RESET 0x80 | ||
49 | |||
50 | /* Control register B */ | ||
51 | #define CTRL_REG_B (1 << 8) | ||
52 | |||
53 | #define REGB_DIRATE(x) (x & 0x3) | ||
54 | #define REGB_SCDIV(x) ((x & 0x3) << 2) | ||
55 | #define REGB_MCDIV(x) ((x & 0x7) << 4) | ||
56 | #define REGB_CEE (1 << 7) | ||
57 | |||
58 | /* Control register C */ | ||
59 | #define CTRL_REG_C (2 << 8) | ||
60 | |||
61 | #define REGC_PUDEV (1 << 0) | ||
62 | #define REGC_PUADC (1 << 3) | ||
63 | #define REGC_PUDAC (1 << 4) | ||
64 | #define REGC_PUREF (1 << 5) | ||
65 | #define REGC_REFUSE (1 << 6) | ||
66 | |||
67 | /* Control register D */ | ||
68 | #define CTRL_REG_D (3 << 8) | ||
69 | |||
70 | #define REGD_IGS(x) (x & 0x7) | ||
71 | #define REGD_RMOD (1 << 3) | ||
72 | #define REGD_OGS(x) ((x & 0x7) << 4) | ||
73 | #define REGD_MUTE (x << 7) | ||
74 | |||
75 | /* Control register E */ | ||
76 | #define CTRL_REG_E (4 << 8) | ||
77 | |||
78 | #define REGE_DA(x) (x & 0x1f) | ||
79 | #define REGE_IBYP (1 << 5) | ||
80 | |||
81 | /* Control register F */ | ||
82 | #define CTRL_REG_F (5 << 8) | ||
83 | |||
84 | #define REGF_SEEN (1 << 5) | ||
85 | #define REGF_INV (1 << 6) | ||
86 | #define REGF_ALB (1 << 7) | ||
87 | |||
88 | extern struct snd_soc_dai ad73311_dai; | ||
89 | extern struct snd_soc_codec_device soc_codec_dev_ad73311; | ||
90 | #endif | ||
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 7da9f467b7b8..2a89b5888e11 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -28,7 +28,6 @@ | |||
28 | 28 | ||
29 | #include "ak4535.h" | 29 | #include "ak4535.h" |
30 | 30 | ||
31 | #define AUDIO_NAME "ak4535" | ||
32 | #define AK4535_VERSION "0.3" | 31 | #define AK4535_VERSION "0.3" |
33 | 32 | ||
34 | struct snd_soc_codec_device soc_codec_dev_ak4535; | 33 | struct snd_soc_codec_device soc_codec_dev_ak4535; |
@@ -535,87 +534,85 @@ static struct snd_soc_device *ak4535_socdev; | |||
535 | 534 | ||
536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 535 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
537 | 536 | ||
538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | 537 | static int ak4535_i2c_probe(struct i2c_client *i2c, |
539 | 538 | 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 | { | 539 | { |
552 | struct snd_soc_device *socdev = ak4535_socdev; | 540 | struct snd_soc_device *socdev = ak4535_socdev; |
553 | struct ak4535_setup_data *setup = socdev->codec_data; | ||
554 | struct snd_soc_codec *codec = socdev->codec; | 541 | struct snd_soc_codec *codec = socdev->codec; |
555 | struct i2c_client *i2c; | ||
556 | int ret; | 542 | int ret; |
557 | 543 | ||
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); | 544 | i2c_set_clientdata(i2c, codec); |
569 | codec->control_data = i2c; | 545 | codec->control_data = i2c; |
570 | 546 | ||
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); | 547 | ret = ak4535_init(socdev); |
578 | if (ret < 0) { | 548 | if (ret < 0) |
579 | printk(KERN_ERR "failed to initialise AK4535\n"); | 549 | printk(KERN_ERR "failed to initialise AK4535\n"); |
580 | goto err; | ||
581 | } | ||
582 | return ret; | ||
583 | 550 | ||
584 | err: | ||
585 | kfree(i2c); | ||
586 | return ret; | 551 | return ret; |
587 | } | 552 | } |
588 | 553 | ||
589 | static int ak4535_i2c_detach(struct i2c_client *client) | 554 | static int ak4535_i2c_remove(struct i2c_client *client) |
590 | { | 555 | { |
591 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 556 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
592 | i2c_detach_client(client); | ||
593 | kfree(codec->reg_cache); | 557 | kfree(codec->reg_cache); |
594 | kfree(client); | ||
595 | return 0; | 558 | return 0; |
596 | } | 559 | } |
597 | 560 | ||
598 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | 561 | static const struct i2c_device_id ak4535_i2c_id[] = { |
599 | { | 562 | { "ak4535", 0 }, |
600 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | 563 | { } |
601 | } | 564 | }; |
565 | MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); | ||
602 | 566 | ||
603 | /* corgi i2c codec control layer */ | ||
604 | static struct i2c_driver ak4535_i2c_driver = { | 567 | static struct i2c_driver ak4535_i2c_driver = { |
605 | .driver = { | 568 | .driver = { |
606 | .name = "AK4535 I2C Codec", | 569 | .name = "AK4535 I2C Codec", |
607 | .owner = THIS_MODULE, | 570 | .owner = THIS_MODULE, |
608 | }, | 571 | }, |
609 | .id = I2C_DRIVERID_AK4535, | 572 | .probe = ak4535_i2c_probe, |
610 | .attach_adapter = ak4535_i2c_attach, | 573 | .remove = ak4535_i2c_remove, |
611 | .detach_client = ak4535_i2c_detach, | 574 | .id_table = ak4535_i2c_id, |
612 | .command = NULL, | ||
613 | }; | 575 | }; |
614 | 576 | ||
615 | static struct i2c_client client_template = { | 577 | static int ak4535_add_i2c_device(struct platform_device *pdev, |
616 | .name = "AK4535", | 578 | const struct ak4535_setup_data *setup) |
617 | .driver = &ak4535_i2c_driver, | 579 | { |
618 | }; | 580 | struct i2c_board_info info; |
581 | struct i2c_adapter *adapter; | ||
582 | struct i2c_client *client; | ||
583 | int ret; | ||
584 | |||
585 | ret = i2c_add_driver(&ak4535_i2c_driver); | ||
586 | if (ret != 0) { | ||
587 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
592 | info.addr = setup->i2c_address; | ||
593 | strlcpy(info.type, "ak4535", I2C_NAME_SIZE); | ||
594 | |||
595 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
596 | if (!adapter) { | ||
597 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
598 | setup->i2c_bus); | ||
599 | goto err_driver; | ||
600 | } | ||
601 | |||
602 | client = i2c_new_device(adapter, &info); | ||
603 | i2c_put_adapter(adapter); | ||
604 | if (!client) { | ||
605 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
606 | (unsigned int)info.addr); | ||
607 | goto err_driver; | ||
608 | } | ||
609 | |||
610 | return 0; | ||
611 | |||
612 | err_driver: | ||
613 | i2c_del_driver(&ak4535_i2c_driver); | ||
614 | return -ENODEV; | ||
615 | } | ||
619 | #endif | 616 | #endif |
620 | 617 | ||
621 | static int ak4535_probe(struct platform_device *pdev) | 618 | static int ak4535_probe(struct platform_device *pdev) |
@@ -624,7 +621,7 @@ static int ak4535_probe(struct platform_device *pdev) | |||
624 | struct ak4535_setup_data *setup; | 621 | struct ak4535_setup_data *setup; |
625 | struct snd_soc_codec *codec; | 622 | struct snd_soc_codec *codec; |
626 | struct ak4535_priv *ak4535; | 623 | struct ak4535_priv *ak4535; |
627 | int ret = 0; | 624 | int ret; |
628 | 625 | ||
629 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | 626 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); |
630 | 627 | ||
@@ -646,17 +643,14 @@ static int ak4535_probe(struct platform_device *pdev) | |||
646 | INIT_LIST_HEAD(&codec->dapm_paths); | 643 | INIT_LIST_HEAD(&codec->dapm_paths); |
647 | 644 | ||
648 | ak4535_socdev = socdev; | 645 | ak4535_socdev = socdev; |
646 | ret = -ENODEV; | ||
647 | |||
649 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 648 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
650 | if (setup->i2c_address) { | 649 | if (setup->i2c_address) { |
651 | normal_i2c[0] = setup->i2c_address; | ||
652 | codec->hw_write = (hw_write_t)i2c_master_send; | 650 | codec->hw_write = (hw_write_t)i2c_master_send; |
653 | codec->hw_read = (hw_read_t)i2c_master_recv; | 651 | codec->hw_read = (hw_read_t)i2c_master_recv; |
654 | ret = i2c_add_driver(&ak4535_i2c_driver); | 652 | ret = ak4535_add_i2c_device(pdev, setup); |
655 | if (ret != 0) | ||
656 | printk(KERN_ERR "can't add i2c driver"); | ||
657 | } | 653 | } |
658 | #else | ||
659 | /* Add other interfaces here */ | ||
660 | #endif | 654 | #endif |
661 | 655 | ||
662 | if (ret != 0) { | 656 | if (ret != 0) { |
@@ -678,6 +672,7 @@ static int ak4535_remove(struct platform_device *pdev) | |||
678 | snd_soc_free_pcms(socdev); | 672 | snd_soc_free_pcms(socdev); |
679 | snd_soc_dapm_free(socdev); | 673 | snd_soc_dapm_free(socdev); |
680 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 674 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
675 | i2c_unregister_device(codec->control_data); | ||
681 | i2c_del_driver(&ak4535_i2c_driver); | 676 | i2c_del_driver(&ak4535_i2c_driver); |
682 | #endif | 677 | #endif |
683 | kfree(codec->private_data); | 678 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h index e9fe30e2c056..c7a58703ea39 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 9deb8c74fdfd..0bbd94501d7e 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 000000000000..44ef0dacd564 --- /dev/null +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -0,0 +1,775 @@ | |||
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 SSM2602_VERSION "0.1" | ||
46 | |||
47 | struct snd_soc_codec_device soc_codec_dev_ssm2602; | ||
48 | |||
49 | /* codec private data */ | ||
50 | struct ssm2602_priv { | ||
51 | unsigned int sysclk; | ||
52 | struct snd_pcm_substream *master_substream; | ||
53 | struct snd_pcm_substream *slave_substream; | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * ssm2602 register cache | ||
58 | * We can't read the ssm2602 register space when we are | ||
59 | * using 2 wire for device control, so we cache them instead. | ||
60 | * There is no point in caching the reset register | ||
61 | */ | ||
62 | static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { | ||
63 | 0x0017, 0x0017, 0x0079, 0x0079, | ||
64 | 0x0000, 0x0000, 0x0000, 0x000a, | ||
65 | 0x0000, 0x0000 | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * read ssm2602 register cache | ||
70 | */ | ||
71 | static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec, | ||
72 | unsigned int reg) | ||
73 | { | ||
74 | u16 *cache = codec->reg_cache; | ||
75 | if (reg == SSM2602_RESET) | ||
76 | return 0; | ||
77 | if (reg >= SSM2602_CACHEREGNUM) | ||
78 | return -1; | ||
79 | return cache[reg]; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * write ssm2602 register cache | ||
84 | */ | ||
85 | static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec, | ||
86 | u16 reg, unsigned int value) | ||
87 | { | ||
88 | u16 *cache = codec->reg_cache; | ||
89 | if (reg >= SSM2602_CACHEREGNUM) | ||
90 | return; | ||
91 | cache[reg] = value; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * write to the ssm2602 register space | ||
96 | */ | ||
97 | static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg, | ||
98 | unsigned int value) | ||
99 | { | ||
100 | u8 data[2]; | ||
101 | |||
102 | /* data is | ||
103 | * D15..D9 ssm2602 register offset | ||
104 | * D8...D0 register data | ||
105 | */ | ||
106 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
107 | data[1] = value & 0x00ff; | ||
108 | |||
109 | ssm2602_write_reg_cache(codec, reg, value); | ||
110 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
111 | return 0; | ||
112 | else | ||
113 | return -EIO; | ||
114 | } | ||
115 | |||
116 | #define ssm2602_reset(c) ssm2602_write(c, SSM2602_RESET, 0) | ||
117 | |||
118 | /*Appending several "None"s just for OSS mixer use*/ | ||
119 | static const char *ssm2602_input_select[] = { | ||
120 | "Line", "Mic", "None", "None", "None", | ||
121 | "None", "None", "None", | ||
122 | }; | ||
123 | |||
124 | static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
125 | |||
126 | static const struct soc_enum ssm2602_enum[] = { | ||
127 | SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select), | ||
128 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), | ||
129 | }; | ||
130 | |||
131 | static const struct snd_kcontrol_new ssm2602_snd_controls[] = { | ||
132 | |||
133 | SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
134 | 0, 127, 0), | ||
135 | SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V, | ||
136 | 7, 1, 0), | ||
137 | |||
138 | SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), | ||
139 | SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), | ||
140 | |||
141 | SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), | ||
142 | SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), | ||
143 | |||
144 | SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1), | ||
145 | |||
146 | SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1), | ||
147 | SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0), | ||
148 | |||
149 | SOC_ENUM("Capture Source", ssm2602_enum[0]), | ||
150 | |||
151 | SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]), | ||
152 | }; | ||
153 | |||
154 | /* add non dapm controls */ | ||
155 | static int ssm2602_add_controls(struct snd_soc_codec *codec) | ||
156 | { | ||
157 | int err, i; | ||
158 | |||
159 | for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) { | ||
160 | err = snd_ctl_add(codec->card, | ||
161 | snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL)); | ||
162 | if (err < 0) | ||
163 | return err; | ||
164 | } | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* Output Mixer */ | ||
170 | static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = { | ||
171 | SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0), | ||
172 | SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), | ||
173 | SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), | ||
174 | }; | ||
175 | |||
176 | /* Input mux */ | ||
177 | static const struct snd_kcontrol_new ssm2602_input_mux_controls = | ||
178 | SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); | ||
179 | |||
180 | static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = { | ||
181 | SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, | ||
182 | &ssm2602_output_mixer_controls[0], | ||
183 | ARRAY_SIZE(ssm2602_output_mixer_controls)), | ||
184 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), | ||
185 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
186 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
187 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
188 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
189 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), | ||
190 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), | ||
191 | SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0), | ||
192 | SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), | ||
193 | SND_SOC_DAPM_INPUT("MICIN"), | ||
194 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
195 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
196 | }; | ||
197 | |||
198 | static const struct snd_soc_dapm_route audio_conn[] = { | ||
199 | /* output mixer */ | ||
200 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
201 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | ||
202 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | ||
203 | |||
204 | /* outputs */ | ||
205 | {"RHPOUT", NULL, "Output Mixer"}, | ||
206 | {"ROUT", NULL, "Output Mixer"}, | ||
207 | {"LHPOUT", NULL, "Output Mixer"}, | ||
208 | {"LOUT", NULL, "Output Mixer"}, | ||
209 | |||
210 | /* input mux */ | ||
211 | {"Input Mux", "Line", "Line Input"}, | ||
212 | {"Input Mux", "Mic", "Mic Bias"}, | ||
213 | {"ADC", NULL, "Input Mux"}, | ||
214 | |||
215 | /* inputs */ | ||
216 | {"Line Input", NULL, "LLINEIN"}, | ||
217 | {"Line Input", NULL, "RLINEIN"}, | ||
218 | {"Mic Bias", NULL, "MICIN"}, | ||
219 | }; | ||
220 | |||
221 | static int ssm2602_add_widgets(struct snd_soc_codec *codec) | ||
222 | { | ||
223 | snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets, | ||
224 | ARRAY_SIZE(ssm2602_dapm_widgets)); | ||
225 | |||
226 | snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn)); | ||
227 | |||
228 | snd_soc_dapm_new_widgets(codec); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | struct _coeff_div { | ||
233 | u32 mclk; | ||
234 | u32 rate; | ||
235 | u16 fs; | ||
236 | u8 sr:4; | ||
237 | u8 bosr:1; | ||
238 | u8 usb:1; | ||
239 | }; | ||
240 | |||
241 | /* codec mclk clock divider coefficients */ | ||
242 | static const struct _coeff_div coeff_div[] = { | ||
243 | /* 48k */ | ||
244 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | ||
245 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | ||
246 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | ||
247 | |||
248 | /* 32k */ | ||
249 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | ||
250 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | ||
251 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | ||
252 | |||
253 | /* 8k */ | ||
254 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | ||
255 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | ||
256 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | ||
257 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | ||
258 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | ||
259 | |||
260 | /* 96k */ | ||
261 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | ||
262 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | ||
263 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | ||
264 | |||
265 | /* 44.1k */ | ||
266 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | ||
267 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | ||
268 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | ||
269 | |||
270 | /* 88.2k */ | ||
271 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | ||
272 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | ||
273 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | ||
274 | }; | ||
275 | |||
276 | static inline int get_coeff(int mclk, int rate) | ||
277 | { | ||
278 | int i; | ||
279 | |||
280 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
281 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
282 | return i; | ||
283 | } | ||
284 | return i; | ||
285 | } | ||
286 | |||
287 | static int ssm2602_hw_params(struct snd_pcm_substream *substream, | ||
288 | struct snd_pcm_hw_params *params) | ||
289 | { | ||
290 | u16 srate; | ||
291 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
292 | struct snd_soc_device *socdev = rtd->socdev; | ||
293 | struct snd_soc_codec *codec = socdev->codec; | ||
294 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
295 | u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; | ||
296 | int i = get_coeff(ssm2602->sysclk, params_rate(params)); | ||
297 | |||
298 | /*no match is found*/ | ||
299 | if (i == ARRAY_SIZE(coeff_div)) | ||
300 | return -EINVAL; | ||
301 | |||
302 | srate = (coeff_div[i].sr << 2) | | ||
303 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | ||
304 | |||
305 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
306 | ssm2602_write(codec, SSM2602_SRATE, srate); | ||
307 | |||
308 | /* bit size */ | ||
309 | switch (params_format(params)) { | ||
310 | case SNDRV_PCM_FORMAT_S16_LE: | ||
311 | break; | ||
312 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
313 | iface |= 0x0004; | ||
314 | break; | ||
315 | case SNDRV_PCM_FORMAT_S24_LE: | ||
316 | iface |= 0x0008; | ||
317 | break; | ||
318 | case SNDRV_PCM_FORMAT_S32_LE: | ||
319 | iface |= 0x000c; | ||
320 | break; | ||
321 | } | ||
322 | ssm2602_write(codec, SSM2602_IFACE, iface); | ||
323 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int ssm2602_startup(struct snd_pcm_substream *substream) | ||
328 | { | ||
329 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
330 | struct snd_soc_device *socdev = rtd->socdev; | ||
331 | struct snd_soc_codec *codec = socdev->codec; | ||
332 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
333 | struct snd_pcm_runtime *master_runtime; | ||
334 | |||
335 | /* The DAI has shared clocks so if we already have a playback or | ||
336 | * capture going then constrain this substream to match it. | ||
337 | */ | ||
338 | if (ssm2602->master_substream) { | ||
339 | master_runtime = ssm2602->master_substream->runtime; | ||
340 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
341 | SNDRV_PCM_HW_PARAM_RATE, | ||
342 | master_runtime->rate, | ||
343 | master_runtime->rate); | ||
344 | |||
345 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
346 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
347 | master_runtime->sample_bits, | ||
348 | master_runtime->sample_bits); | ||
349 | |||
350 | ssm2602->slave_substream = substream; | ||
351 | } else | ||
352 | ssm2602->master_substream = substream; | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) | ||
358 | { | ||
359 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
360 | struct snd_soc_device *socdev = rtd->socdev; | ||
361 | struct snd_soc_codec *codec = socdev->codec; | ||
362 | /* set active */ | ||
363 | ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static void ssm2602_shutdown(struct snd_pcm_substream *substream) | ||
369 | { | ||
370 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
371 | struct snd_soc_device *socdev = rtd->socdev; | ||
372 | struct snd_soc_codec *codec = socdev->codec; | ||
373 | /* deactivate */ | ||
374 | if (!codec->active) | ||
375 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
376 | } | ||
377 | |||
378 | static int ssm2602_mute(struct snd_soc_dai *dai, int mute) | ||
379 | { | ||
380 | struct snd_soc_codec *codec = dai->codec; | ||
381 | u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE; | ||
382 | if (mute) | ||
383 | ssm2602_write(codec, SSM2602_APDIGI, | ||
384 | mute_reg | APDIGI_ENABLE_DAC_MUTE); | ||
385 | else | ||
386 | ssm2602_write(codec, SSM2602_APDIGI, mute_reg); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
391 | int clk_id, unsigned int freq, int dir) | ||
392 | { | ||
393 | struct snd_soc_codec *codec = codec_dai->codec; | ||
394 | struct ssm2602_priv *ssm2602 = codec->private_data; | ||
395 | switch (freq) { | ||
396 | case 11289600: | ||
397 | case 12000000: | ||
398 | case 12288000: | ||
399 | case 16934400: | ||
400 | case 18432000: | ||
401 | ssm2602->sysclk = freq; | ||
402 | return 0; | ||
403 | } | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
408 | unsigned int fmt) | ||
409 | { | ||
410 | struct snd_soc_codec *codec = codec_dai->codec; | ||
411 | u16 iface = 0; | ||
412 | |||
413 | /* set master/slave audio interface */ | ||
414 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
415 | case SND_SOC_DAIFMT_CBM_CFM: | ||
416 | iface |= 0x0040; | ||
417 | break; | ||
418 | case SND_SOC_DAIFMT_CBS_CFS: | ||
419 | break; | ||
420 | default: | ||
421 | return -EINVAL; | ||
422 | } | ||
423 | |||
424 | /* interface format */ | ||
425 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
426 | case SND_SOC_DAIFMT_I2S: | ||
427 | iface |= 0x0002; | ||
428 | break; | ||
429 | case SND_SOC_DAIFMT_RIGHT_J: | ||
430 | break; | ||
431 | case SND_SOC_DAIFMT_LEFT_J: | ||
432 | iface |= 0x0001; | ||
433 | break; | ||
434 | case SND_SOC_DAIFMT_DSP_A: | ||
435 | iface |= 0x0003; | ||
436 | break; | ||
437 | case SND_SOC_DAIFMT_DSP_B: | ||
438 | iface |= 0x0013; | ||
439 | break; | ||
440 | default: | ||
441 | return -EINVAL; | ||
442 | } | ||
443 | |||
444 | /* clock inversion */ | ||
445 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
446 | case SND_SOC_DAIFMT_NB_NF: | ||
447 | break; | ||
448 | case SND_SOC_DAIFMT_IB_IF: | ||
449 | iface |= 0x0090; | ||
450 | break; | ||
451 | case SND_SOC_DAIFMT_IB_NF: | ||
452 | iface |= 0x0080; | ||
453 | break; | ||
454 | case SND_SOC_DAIFMT_NB_IF: | ||
455 | iface |= 0x0010; | ||
456 | break; | ||
457 | default: | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | /* set iface */ | ||
462 | ssm2602_write(codec, SSM2602_IFACE, iface); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | ||
467 | enum snd_soc_bias_level level) | ||
468 | { | ||
469 | u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f; | ||
470 | |||
471 | switch (level) { | ||
472 | case SND_SOC_BIAS_ON: | ||
473 | /* vref/mid, osc on, dac unmute */ | ||
474 | ssm2602_write(codec, SSM2602_PWR, reg); | ||
475 | break; | ||
476 | case SND_SOC_BIAS_PREPARE: | ||
477 | break; | ||
478 | case SND_SOC_BIAS_STANDBY: | ||
479 | /* everything off except vref/vmid, */ | ||
480 | ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); | ||
481 | break; | ||
482 | case SND_SOC_BIAS_OFF: | ||
483 | /* everything off, dac mute, inactive */ | ||
484 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
485 | ssm2602_write(codec, SSM2602_PWR, 0xffff); | ||
486 | break; | ||
487 | |||
488 | } | ||
489 | codec->bias_level = level; | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | #define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
494 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
495 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
496 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | ||
497 | SNDRV_PCM_RATE_96000) | ||
498 | |||
499 | struct snd_soc_dai ssm2602_dai = { | ||
500 | .name = "SSM2602", | ||
501 | .playback = { | ||
502 | .stream_name = "Playback", | ||
503 | .channels_min = 2, | ||
504 | .channels_max = 2, | ||
505 | .rates = SSM2602_RATES, | ||
506 | .formats = SNDRV_PCM_FMTBIT_S32_LE,}, | ||
507 | .capture = { | ||
508 | .stream_name = "Capture", | ||
509 | .channels_min = 2, | ||
510 | .channels_max = 2, | ||
511 | .rates = SSM2602_RATES, | ||
512 | .formats = SNDRV_PCM_FMTBIT_S32_LE,}, | ||
513 | .ops = { | ||
514 | .startup = ssm2602_startup, | ||
515 | .prepare = ssm2602_pcm_prepare, | ||
516 | .hw_params = ssm2602_hw_params, | ||
517 | .shutdown = ssm2602_shutdown, | ||
518 | }, | ||
519 | .dai_ops = { | ||
520 | .digital_mute = ssm2602_mute, | ||
521 | .set_sysclk = ssm2602_set_dai_sysclk, | ||
522 | .set_fmt = ssm2602_set_dai_fmt, | ||
523 | } | ||
524 | }; | ||
525 | EXPORT_SYMBOL_GPL(ssm2602_dai); | ||
526 | |||
527 | static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state) | ||
528 | { | ||
529 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
530 | struct snd_soc_codec *codec = socdev->codec; | ||
531 | |||
532 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int ssm2602_resume(struct platform_device *pdev) | ||
537 | { | ||
538 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
539 | struct snd_soc_codec *codec = socdev->codec; | ||
540 | int i; | ||
541 | u8 data[2]; | ||
542 | u16 *cache = codec->reg_cache; | ||
543 | |||
544 | /* Sync reg_cache with the hardware */ | ||
545 | for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) { | ||
546 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
547 | data[1] = cache[i] & 0x00ff; | ||
548 | codec->hw_write(codec->control_data, data, 2); | ||
549 | } | ||
550 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
551 | ssm2602_set_bias_level(codec, codec->suspend_bias_level); | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | /* | ||
556 | * initialise the ssm2602 driver | ||
557 | * register the mixer and dsp interfaces with the kernel | ||
558 | */ | ||
559 | static int ssm2602_init(struct snd_soc_device *socdev) | ||
560 | { | ||
561 | struct snd_soc_codec *codec = socdev->codec; | ||
562 | int reg, ret = 0; | ||
563 | |||
564 | codec->name = "SSM2602"; | ||
565 | codec->owner = THIS_MODULE; | ||
566 | codec->read = ssm2602_read_reg_cache; | ||
567 | codec->write = ssm2602_write; | ||
568 | codec->set_bias_level = ssm2602_set_bias_level; | ||
569 | codec->dai = &ssm2602_dai; | ||
570 | codec->num_dai = 1; | ||
571 | codec->reg_cache_size = sizeof(ssm2602_reg); | ||
572 | codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg), | ||
573 | GFP_KERNEL); | ||
574 | if (codec->reg_cache == NULL) | ||
575 | return -ENOMEM; | ||
576 | |||
577 | ssm2602_reset(codec); | ||
578 | |||
579 | /* register pcms */ | ||
580 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
581 | if (ret < 0) { | ||
582 | pr_err("ssm2602: failed to create pcms\n"); | ||
583 | goto pcm_err; | ||
584 | } | ||
585 | /*power on device*/ | ||
586 | ssm2602_write(codec, SSM2602_ACTIVE, 0); | ||
587 | /* set the update bits */ | ||
588 | reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL); | ||
589 | ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); | ||
590 | reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL); | ||
591 | ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); | ||
592 | reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V); | ||
593 | ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); | ||
594 | reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V); | ||
595 | ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); | ||
596 | /*select Line in as default input*/ | ||
597 | ssm2602_write(codec, SSM2602_APANA, | ||
598 | APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC | | ||
599 | APANA_ENABLE_MIC_BOOST); | ||
600 | ssm2602_write(codec, SSM2602_PWR, 0); | ||
601 | |||
602 | ssm2602_add_controls(codec); | ||
603 | ssm2602_add_widgets(codec); | ||
604 | ret = snd_soc_register_card(socdev); | ||
605 | if (ret < 0) { | ||
606 | pr_err("ssm2602: failed to register card\n"); | ||
607 | goto card_err; | ||
608 | } | ||
609 | |||
610 | return ret; | ||
611 | |||
612 | card_err: | ||
613 | snd_soc_free_pcms(socdev); | ||
614 | snd_soc_dapm_free(socdev); | ||
615 | pcm_err: | ||
616 | kfree(codec->reg_cache); | ||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | static struct snd_soc_device *ssm2602_socdev; | ||
621 | |||
622 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
623 | /* | ||
624 | * ssm2602 2 wire address is determined by GPIO5 | ||
625 | * state during powerup. | ||
626 | * low = 0x1a | ||
627 | * high = 0x1b | ||
628 | */ | ||
629 | static int ssm2602_i2c_probe(struct i2c_client *i2c, | ||
630 | const struct i2c_device_id *id) | ||
631 | { | ||
632 | struct snd_soc_device *socdev = ssm2602_socdev; | ||
633 | struct snd_soc_codec *codec = socdev->codec; | ||
634 | int ret; | ||
635 | |||
636 | i2c_set_clientdata(i2c, codec); | ||
637 | codec->control_data = i2c; | ||
638 | |||
639 | ret = ssm2602_init(socdev); | ||
640 | if (ret < 0) | ||
641 | pr_err("failed to initialise SSM2602\n"); | ||
642 | |||
643 | return ret; | ||
644 | } | ||
645 | |||
646 | static int ssm2602_i2c_remove(struct i2c_client *client) | ||
647 | { | ||
648 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
649 | kfree(codec->reg_cache); | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static const struct i2c_device_id ssm2602_i2c_id[] = { | ||
654 | { "ssm2602", 0 }, | ||
655 | { } | ||
656 | }; | ||
657 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | ||
658 | /* corgi i2c codec control layer */ | ||
659 | static struct i2c_driver ssm2602_i2c_driver = { | ||
660 | .driver = { | ||
661 | .name = "SSM2602 I2C Codec", | ||
662 | .owner = THIS_MODULE, | ||
663 | }, | ||
664 | .probe = ssm2602_i2c_probe, | ||
665 | .remove = ssm2602_i2c_remove, | ||
666 | .id_table = ssm2602_i2c_id, | ||
667 | }; | ||
668 | |||
669 | static int ssm2602_add_i2c_device(struct platform_device *pdev, | ||
670 | const struct ssm2602_setup_data *setup) | ||
671 | { | ||
672 | struct i2c_board_info info; | ||
673 | struct i2c_adapter *adapter; | ||
674 | struct i2c_client *client; | ||
675 | int ret; | ||
676 | |||
677 | ret = i2c_add_driver(&ssm2602_i2c_driver); | ||
678 | if (ret != 0) { | ||
679 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
680 | return ret; | ||
681 | } | ||
682 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
683 | info.addr = setup->i2c_address; | ||
684 | strlcpy(info.type, "ssm2602", I2C_NAME_SIZE); | ||
685 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
686 | if (!adapter) { | ||
687 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
688 | setup->i2c_bus); | ||
689 | goto err_driver; | ||
690 | } | ||
691 | client = i2c_new_device(adapter, &info); | ||
692 | i2c_put_adapter(adapter); | ||
693 | if (!client) { | ||
694 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
695 | (unsigned int)info.addr); | ||
696 | goto err_driver; | ||
697 | } | ||
698 | return 0; | ||
699 | err_driver: | ||
700 | i2c_del_driver(&ssm2602_i2c_driver); | ||
701 | return -ENODEV; | ||
702 | } | ||
703 | #endif | ||
704 | |||
705 | static int ssm2602_probe(struct platform_device *pdev) | ||
706 | { | ||
707 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
708 | struct ssm2602_setup_data *setup; | ||
709 | struct snd_soc_codec *codec; | ||
710 | struct ssm2602_priv *ssm2602; | ||
711 | int ret = 0; | ||
712 | |||
713 | pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); | ||
714 | |||
715 | setup = socdev->codec_data; | ||
716 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
717 | if (codec == NULL) | ||
718 | return -ENOMEM; | ||
719 | |||
720 | ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL); | ||
721 | if (ssm2602 == NULL) { | ||
722 | kfree(codec); | ||
723 | return -ENOMEM; | ||
724 | } | ||
725 | |||
726 | codec->private_data = ssm2602; | ||
727 | socdev->codec = codec; | ||
728 | mutex_init(&codec->mutex); | ||
729 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
730 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
731 | |||
732 | ssm2602_socdev = socdev; | ||
733 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
734 | if (setup->i2c_address) { | ||
735 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
736 | ret = ssm2602_add_i2c_device(pdev, setup); | ||
737 | } | ||
738 | #else | ||
739 | /* other interfaces */ | ||
740 | #endif | ||
741 | return ret; | ||
742 | } | ||
743 | |||
744 | /* remove everything here */ | ||
745 | static int ssm2602_remove(struct platform_device *pdev) | ||
746 | { | ||
747 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
748 | struct snd_soc_codec *codec = socdev->codec; | ||
749 | |||
750 | if (codec->control_data) | ||
751 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
752 | |||
753 | snd_soc_free_pcms(socdev); | ||
754 | snd_soc_dapm_free(socdev); | ||
755 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
756 | i2c_unregister_device(codec->control_data); | ||
757 | i2c_del_driver(&ssm2602_i2c_driver); | ||
758 | #endif | ||
759 | kfree(codec->private_data); | ||
760 | kfree(codec); | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | struct snd_soc_codec_device soc_codec_dev_ssm2602 = { | ||
766 | .probe = ssm2602_probe, | ||
767 | .remove = ssm2602_remove, | ||
768 | .suspend = ssm2602_suspend, | ||
769 | .resume = ssm2602_resume, | ||
770 | }; | ||
771 | EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); | ||
772 | |||
773 | MODULE_DESCRIPTION("ASoC ssm2602 driver"); | ||
774 | MODULE_AUTHOR("Cliff Cai"); | ||
775 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h new file mode 100644 index 000000000000..f344e6d76e31 --- /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/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c new file mode 100644 index 000000000000..44308dac9e18 --- /dev/null +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -0,0 +1,714 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC23 codec driver | ||
3 | * | ||
4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., | ||
6 | * | ||
7 | * Based on sound/soc/codecs/wm8731.c by Richard Purdie | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Notes: | ||
14 | * The AIC23 is a driver for a low power stereo audio | ||
15 | * codec tlv320aic23 | ||
16 | * | ||
17 | * The machine layer should disable unsupported inputs/outputs by | ||
18 | * snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.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 | |||
36 | #include "tlv320aic23.h" | ||
37 | |||
38 | #define AIC23_VERSION "0.1" | ||
39 | |||
40 | struct tlv320aic23_srate_reg_info { | ||
41 | u32 sample_rate; | ||
42 | u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ | ||
43 | u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ | ||
44 | }; | ||
45 | |||
46 | /* | ||
47 | * AIC23 register cache | ||
48 | */ | ||
49 | static const u16 tlv320aic23_reg[] = { | ||
50 | 0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */ | ||
51 | 0x001A, 0x0004, 0x0007, 0x0001, /* 4 */ | ||
52 | 0x0020, 0x0000, 0x0000, 0x0000, /* 8 */ | ||
53 | 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */ | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * read tlv320aic23 register cache | ||
58 | */ | ||
59 | static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec | ||
60 | *codec, unsigned int reg) | ||
61 | { | ||
62 | u16 *cache = codec->reg_cache; | ||
63 | if (reg >= ARRAY_SIZE(tlv320aic23_reg)) | ||
64 | return -1; | ||
65 | return cache[reg]; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * write tlv320aic23 register cache | ||
70 | */ | ||
71 | static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec, | ||
72 | u8 reg, u16 value) | ||
73 | { | ||
74 | u16 *cache = codec->reg_cache; | ||
75 | if (reg >= ARRAY_SIZE(tlv320aic23_reg)) | ||
76 | return; | ||
77 | cache[reg] = value; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * write to the tlv320aic23 register space | ||
82 | */ | ||
83 | static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, | ||
84 | unsigned int value) | ||
85 | { | ||
86 | |||
87 | u8 data[2]; | ||
88 | |||
89 | /* TLV320AIC23 has 7 bit address and 9 bits of data | ||
90 | * so we need to switch one data bit into reg and rest | ||
91 | * of data into val | ||
92 | */ | ||
93 | |||
94 | if ((reg < 0 || reg > 9) && (reg != 15)) { | ||
95 | printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg); | ||
96 | return -1; | ||
97 | } | ||
98 | |||
99 | data[0] = (reg << 1) | (value >> 8 & 0x01); | ||
100 | data[1] = value & 0xff; | ||
101 | |||
102 | tlv320aic23_write_reg_cache(codec, reg, value); | ||
103 | |||
104 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
105 | return 0; | ||
106 | |||
107 | printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__, | ||
108 | value, reg); | ||
109 | |||
110 | return -EIO; | ||
111 | } | ||
112 | |||
113 | static const char *rec_src_text[] = { "Line", "Mic" }; | ||
114 | static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
115 | |||
116 | static const struct soc_enum rec_src_enum = | ||
117 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | ||
118 | |||
119 | static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = | ||
120 | SOC_DAPM_ENUM("Input Select", rec_src_enum); | ||
121 | |||
122 | static const struct soc_enum tlv320aic23_rec_src = | ||
123 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | ||
124 | static const struct soc_enum tlv320aic23_deemph = | ||
125 | SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text); | ||
126 | |||
127 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); | ||
128 | static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); | ||
129 | static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0); | ||
130 | |||
131 | static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol, | ||
132 | struct snd_ctl_elem_value *ucontrol) | ||
133 | { | ||
134 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
135 | u16 val, reg; | ||
136 | |||
137 | val = (ucontrol->value.integer.value[0] & 0x07); | ||
138 | |||
139 | /* linear conversion to userspace | ||
140 | * 000 = -6db | ||
141 | * 001 = -9db | ||
142 | * 010 = -12db | ||
143 | * 011 = -18db (Min) | ||
144 | * 100 = 0db (Max) | ||
145 | */ | ||
146 | val = (val >= 4) ? 4 : (3 - val); | ||
147 | |||
148 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0); | ||
149 | tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6)); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol, | ||
155 | struct snd_ctl_elem_value *ucontrol) | ||
156 | { | ||
157 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
158 | u16 val; | ||
159 | |||
160 | val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0); | ||
161 | val = val >> 6; | ||
162 | val = (val >= 4) ? 4 : (3 - val); | ||
163 | ucontrol->value.integer.value[0] = val; | ||
164 | return 0; | ||
165 | |||
166 | } | ||
167 | |||
168 | #define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ | ||
169 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
170 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
171 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
172 | .tlv.p = (tlv_array), \ | ||
173 | .info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\ | ||
174 | .put = snd_soc_tlv320aic23_put_volsw, \ | ||
175 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
176 | |||
177 | static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = { | ||
178 | SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL, | ||
179 | TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv), | ||
180 | SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1), | ||
181 | SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL, | ||
182 | TLV320AIC23_RINVOL, 7, 1, 0), | ||
183 | SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL, | ||
184 | TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv), | ||
185 | SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1), | ||
186 | SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0), | ||
187 | SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG, | ||
188 | 6, 4, 0, sidetone_vol_tlv), | ||
189 | SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), | ||
190 | }; | ||
191 | |||
192 | /* add non dapm controls */ | ||
193 | static int tlv320aic23_add_controls(struct snd_soc_codec *codec) | ||
194 | { | ||
195 | |||
196 | int err, i; | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) { | ||
199 | err = snd_ctl_add(codec->card, | ||
200 | snd_soc_cnew(&tlv320aic23_snd_controls[i], | ||
201 | codec, NULL)); | ||
202 | if (err < 0) | ||
203 | return err; | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | |||
208 | } | ||
209 | |||
210 | /* PGA Mixer controls for Line and Mic switch */ | ||
211 | static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = { | ||
212 | SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0), | ||
213 | SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0), | ||
214 | SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0), | ||
215 | }; | ||
216 | |||
217 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
218 | SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1), | ||
219 | SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1), | ||
220 | SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0, | ||
221 | &tlv320aic23_rec_src_mux_controls), | ||
222 | SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1, | ||
223 | &tlv320aic23_output_mixer_controls[0], | ||
224 | ARRAY_SIZE(tlv320aic23_output_mixer_controls)), | ||
225 | SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0), | ||
226 | SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0), | ||
227 | |||
228 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
229 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
230 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
231 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
232 | |||
233 | SND_SOC_DAPM_INPUT("LLINEIN"), | ||
234 | SND_SOC_DAPM_INPUT("RLINEIN"), | ||
235 | |||
236 | SND_SOC_DAPM_INPUT("MICIN"), | ||
237 | }; | ||
238 | |||
239 | static const struct snd_soc_dapm_route intercon[] = { | ||
240 | /* Output Mixer */ | ||
241 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
242 | {"Output Mixer", "Playback Switch", "DAC"}, | ||
243 | {"Output Mixer", "Mic Sidetone Switch", "Mic Input"}, | ||
244 | |||
245 | /* Outputs */ | ||
246 | {"RHPOUT", NULL, "Output Mixer"}, | ||
247 | {"LHPOUT", NULL, "Output Mixer"}, | ||
248 | {"LOUT", NULL, "Output Mixer"}, | ||
249 | {"ROUT", NULL, "Output Mixer"}, | ||
250 | |||
251 | /* Inputs */ | ||
252 | {"Line Input", "NULL", "LLINEIN"}, | ||
253 | {"Line Input", "NULL", "RLINEIN"}, | ||
254 | |||
255 | {"Mic Input", "NULL", "MICIN"}, | ||
256 | |||
257 | /* input mux */ | ||
258 | {"Capture Source", "Line", "Line Input"}, | ||
259 | {"Capture Source", "Mic", "Mic Input"}, | ||
260 | {"ADC", NULL, "Capture Source"}, | ||
261 | |||
262 | }; | ||
263 | |||
264 | /* tlv320aic23 related */ | ||
265 | static const struct tlv320aic23_srate_reg_info srate_reg_info[] = { | ||
266 | {4000, 0x06, 1}, /* 4000 */ | ||
267 | {8000, 0x06, 0}, /* 8000 */ | ||
268 | {16000, 0x0C, 1}, /* 16000 */ | ||
269 | {22050, 0x11, 1}, /* 22050 */ | ||
270 | {24000, 0x00, 1}, /* 24000 */ | ||
271 | {32000, 0x0C, 0}, /* 32000 */ | ||
272 | {44100, 0x11, 0}, /* 44100 */ | ||
273 | {48000, 0x00, 0}, /* 48000 */ | ||
274 | {88200, 0x1F, 0}, /* 88200 */ | ||
275 | {96000, 0x0E, 0}, /* 96000 */ | ||
276 | }; | ||
277 | |||
278 | static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) | ||
279 | { | ||
280 | snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, | ||
281 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | ||
282 | |||
283 | /* set up audio path interconnects */ | ||
284 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
285 | |||
286 | snd_soc_dapm_new_widgets(codec); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, | ||
291 | struct snd_pcm_hw_params *params) | ||
292 | { | ||
293 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
294 | struct snd_soc_device *socdev = rtd->socdev; | ||
295 | struct snd_soc_codec *codec = socdev->codec; | ||
296 | u16 iface_reg, data; | ||
297 | u8 count = 0; | ||
298 | |||
299 | iface_reg = | ||
300 | tlv320aic23_read_reg_cache(codec, | ||
301 | TLV320AIC23_DIGT_FMT) & ~(0x03 << 2); | ||
302 | |||
303 | /* Search for the right sample rate */ | ||
304 | /* Verify what happens if the rate is not supported | ||
305 | * now it goes to 96Khz */ | ||
306 | while ((srate_reg_info[count].sample_rate != params_rate(params)) && | ||
307 | (count < ARRAY_SIZE(srate_reg_info))) { | ||
308 | count++; | ||
309 | } | ||
310 | |||
311 | data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) | | ||
312 | (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) | | ||
313 | TLV320AIC23_USB_CLK_ON; | ||
314 | |||
315 | tlv320aic23_write(codec, TLV320AIC23_SRATE, data); | ||
316 | |||
317 | switch (params_format(params)) { | ||
318 | case SNDRV_PCM_FORMAT_S16_LE: | ||
319 | break; | ||
320 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
321 | iface_reg |= (0x01 << 2); | ||
322 | break; | ||
323 | case SNDRV_PCM_FORMAT_S24_LE: | ||
324 | iface_reg |= (0x02 << 2); | ||
325 | break; | ||
326 | case SNDRV_PCM_FORMAT_S32_LE: | ||
327 | iface_reg |= (0x03 << 2); | ||
328 | break; | ||
329 | } | ||
330 | tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg); | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) | ||
336 | { | ||
337 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
338 | struct snd_soc_device *socdev = rtd->socdev; | ||
339 | struct snd_soc_codec *codec = socdev->codec; | ||
340 | |||
341 | /* set active */ | ||
342 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) | ||
348 | { | ||
349 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
350 | struct snd_soc_device *socdev = rtd->socdev; | ||
351 | struct snd_soc_codec *codec = socdev->codec; | ||
352 | |||
353 | /* deactivate */ | ||
354 | if (!codec->active) { | ||
355 | udelay(50); | ||
356 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute) | ||
361 | { | ||
362 | struct snd_soc_codec *codec = dai->codec; | ||
363 | u16 reg; | ||
364 | |||
365 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT); | ||
366 | if (mute) | ||
367 | reg |= TLV320AIC23_DACM_MUTE; | ||
368 | |||
369 | else | ||
370 | reg &= ~TLV320AIC23_DACM_MUTE; | ||
371 | |||
372 | tlv320aic23_write(codec, TLV320AIC23_DIGT, reg); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
378 | unsigned int fmt) | ||
379 | { | ||
380 | struct snd_soc_codec *codec = codec_dai->codec; | ||
381 | u16 iface_reg; | ||
382 | |||
383 | iface_reg = | ||
384 | tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03); | ||
385 | |||
386 | /* set master/slave audio interface */ | ||
387 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
388 | case SND_SOC_DAIFMT_CBM_CFM: | ||
389 | iface_reg |= TLV320AIC23_MS_MASTER; | ||
390 | break; | ||
391 | case SND_SOC_DAIFMT_CBS_CFS: | ||
392 | break; | ||
393 | default: | ||
394 | return -EINVAL; | ||
395 | |||
396 | } | ||
397 | |||
398 | /* interface format */ | ||
399 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
400 | case SND_SOC_DAIFMT_I2S: | ||
401 | iface_reg |= TLV320AIC23_FOR_I2S; | ||
402 | break; | ||
403 | case SND_SOC_DAIFMT_DSP_A: | ||
404 | iface_reg |= TLV320AIC23_FOR_DSP; | ||
405 | break; | ||
406 | case SND_SOC_DAIFMT_RIGHT_J: | ||
407 | break; | ||
408 | case SND_SOC_DAIFMT_LEFT_J: | ||
409 | iface_reg |= TLV320AIC23_FOR_LJUST; | ||
410 | break; | ||
411 | default: | ||
412 | return -EINVAL; | ||
413 | |||
414 | } | ||
415 | |||
416 | tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
422 | int clk_id, unsigned int freq, int dir) | ||
423 | { | ||
424 | struct snd_soc_codec *codec = codec_dai->codec; | ||
425 | |||
426 | switch (freq) { | ||
427 | case 12000000: | ||
428 | return 0; | ||
429 | } | ||
430 | return -EINVAL; | ||
431 | } | ||
432 | |||
433 | static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | ||
434 | enum snd_soc_bias_level level) | ||
435 | { | ||
436 | u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f; | ||
437 | |||
438 | switch (level) { | ||
439 | case SND_SOC_BIAS_ON: | ||
440 | /* vref/mid, osc on, dac unmute */ | ||
441 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg); | ||
442 | break; | ||
443 | case SND_SOC_BIAS_PREPARE: | ||
444 | break; | ||
445 | case SND_SOC_BIAS_STANDBY: | ||
446 | /* everything off except vref/vmid, */ | ||
447 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040); | ||
448 | break; | ||
449 | case SND_SOC_BIAS_OFF: | ||
450 | /* everything off, dac mute, inactive */ | ||
451 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
452 | tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff); | ||
453 | break; | ||
454 | } | ||
455 | codec->bias_level = level; | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | #define AIC23_RATES SNDRV_PCM_RATE_8000_96000 | ||
460 | #define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
461 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
462 | |||
463 | struct snd_soc_dai tlv320aic23_dai = { | ||
464 | .name = "tlv320aic23", | ||
465 | .playback = { | ||
466 | .stream_name = "Playback", | ||
467 | .channels_min = 2, | ||
468 | .channels_max = 2, | ||
469 | .rates = AIC23_RATES, | ||
470 | .formats = AIC23_FORMATS,}, | ||
471 | .capture = { | ||
472 | .stream_name = "Capture", | ||
473 | .channels_min = 2, | ||
474 | .channels_max = 2, | ||
475 | .rates = AIC23_RATES, | ||
476 | .formats = AIC23_FORMATS,}, | ||
477 | .ops = { | ||
478 | .prepare = tlv320aic23_pcm_prepare, | ||
479 | .hw_params = tlv320aic23_hw_params, | ||
480 | .shutdown = tlv320aic23_shutdown, | ||
481 | }, | ||
482 | .dai_ops = { | ||
483 | .digital_mute = tlv320aic23_mute, | ||
484 | .set_fmt = tlv320aic23_set_dai_fmt, | ||
485 | .set_sysclk = tlv320aic23_set_dai_sysclk, | ||
486 | } | ||
487 | }; | ||
488 | EXPORT_SYMBOL_GPL(tlv320aic23_dai); | ||
489 | |||
490 | static int tlv320aic23_suspend(struct platform_device *pdev, | ||
491 | pm_message_t state) | ||
492 | { | ||
493 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
494 | struct snd_soc_codec *codec = socdev->codec; | ||
495 | |||
496 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
497 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int tlv320aic23_resume(struct platform_device *pdev) | ||
503 | { | ||
504 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
505 | struct snd_soc_codec *codec = socdev->codec; | ||
506 | int i; | ||
507 | u16 reg; | ||
508 | |||
509 | /* Sync reg_cache with the hardware */ | ||
510 | for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) { | ||
511 | u16 val = tlv320aic23_read_reg_cache(codec, reg); | ||
512 | tlv320aic23_write(codec, reg, val); | ||
513 | } | ||
514 | |||
515 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
516 | tlv320aic23_set_bias_level(codec, codec->suspend_bias_level); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * initialise the AIC23 driver | ||
523 | * register the mixer and dsp interfaces with the kernel | ||
524 | */ | ||
525 | static int tlv320aic23_init(struct snd_soc_device *socdev) | ||
526 | { | ||
527 | struct snd_soc_codec *codec = socdev->codec; | ||
528 | int ret = 0; | ||
529 | u16 reg; | ||
530 | |||
531 | codec->name = "tlv320aic23"; | ||
532 | codec->owner = THIS_MODULE; | ||
533 | codec->read = tlv320aic23_read_reg_cache; | ||
534 | codec->write = tlv320aic23_write; | ||
535 | codec->set_bias_level = tlv320aic23_set_bias_level; | ||
536 | codec->dai = &tlv320aic23_dai; | ||
537 | codec->num_dai = 1; | ||
538 | codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg); | ||
539 | codec->reg_cache = | ||
540 | kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL); | ||
541 | if (codec->reg_cache == NULL) | ||
542 | return -ENOMEM; | ||
543 | |||
544 | /* Reset codec */ | ||
545 | tlv320aic23_write(codec, TLV320AIC23_RESET, 0); | ||
546 | |||
547 | /* register pcms */ | ||
548 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
549 | if (ret < 0) { | ||
550 | printk(KERN_ERR "tlv320aic23: failed to create pcms\n"); | ||
551 | goto pcm_err; | ||
552 | } | ||
553 | |||
554 | /* power on device */ | ||
555 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
556 | |||
557 | tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); | ||
558 | |||
559 | /* Unmute input */ | ||
560 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL); | ||
561 | tlv320aic23_write(codec, TLV320AIC23_LINVOL, | ||
562 | (reg & (~TLV320AIC23_LIM_MUTED)) | | ||
563 | (TLV320AIC23_LRS_ENABLED)); | ||
564 | |||
565 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL); | ||
566 | tlv320aic23_write(codec, TLV320AIC23_RINVOL, | ||
567 | (reg & (~TLV320AIC23_LIM_MUTED)) | | ||
568 | TLV320AIC23_LRS_ENABLED); | ||
569 | |||
570 | reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG); | ||
571 | tlv320aic23_write(codec, TLV320AIC23_ANLG, | ||
572 | (reg) & (~TLV320AIC23_BYPASS_ON) & | ||
573 | (~TLV320AIC23_MICM_MUTED)); | ||
574 | |||
575 | /* Default output volume */ | ||
576 | tlv320aic23_write(codec, TLV320AIC23_LCHNVOL, | ||
577 | TLV320AIC23_DEFAULT_OUT_VOL & | ||
578 | TLV320AIC23_OUT_VOL_MASK); | ||
579 | tlv320aic23_write(codec, TLV320AIC23_RCHNVOL, | ||
580 | TLV320AIC23_DEFAULT_OUT_VOL & | ||
581 | TLV320AIC23_OUT_VOL_MASK); | ||
582 | |||
583 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); | ||
584 | |||
585 | tlv320aic23_add_controls(codec); | ||
586 | tlv320aic23_add_widgets(codec); | ||
587 | ret = snd_soc_register_card(socdev); | ||
588 | if (ret < 0) { | ||
589 | printk(KERN_ERR "tlv320aic23: failed to register card\n"); | ||
590 | goto card_err; | ||
591 | } | ||
592 | |||
593 | return ret; | ||
594 | |||
595 | card_err: | ||
596 | snd_soc_free_pcms(socdev); | ||
597 | snd_soc_dapm_free(socdev); | ||
598 | pcm_err: | ||
599 | kfree(codec->reg_cache); | ||
600 | return ret; | ||
601 | } | ||
602 | static struct snd_soc_device *tlv320aic23_socdev; | ||
603 | |||
604 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
605 | /* | ||
606 | * If the i2c layer weren't so broken, we could pass this kind of data | ||
607 | * around | ||
608 | */ | ||
609 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, | ||
610 | const struct i2c_device_id *i2c_id) | ||
611 | { | ||
612 | struct snd_soc_device *socdev = tlv320aic23_socdev; | ||
613 | struct snd_soc_codec *codec = socdev->codec; | ||
614 | int ret; | ||
615 | |||
616 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
617 | return -EINVAL; | ||
618 | |||
619 | i2c_set_clientdata(i2c, codec); | ||
620 | codec->control_data = i2c; | ||
621 | |||
622 | ret = tlv320aic23_init(socdev); | ||
623 | if (ret < 0) { | ||
624 | printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n"); | ||
625 | goto err; | ||
626 | } | ||
627 | return ret; | ||
628 | |||
629 | err: | ||
630 | kfree(codec); | ||
631 | kfree(i2c); | ||
632 | return ret; | ||
633 | } | ||
634 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | ||
635 | { | ||
636 | put_device(&i2c->dev); | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static const struct i2c_device_id tlv320aic23_id[] = { | ||
641 | {"tlv320aic23", 0}, | ||
642 | {} | ||
643 | }; | ||
644 | |||
645 | MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | ||
646 | |||
647 | static struct i2c_driver tlv320aic23_i2c_driver = { | ||
648 | .driver = { | ||
649 | .name = "tlv320aic23", | ||
650 | }, | ||
651 | .probe = tlv320aic23_codec_probe, | ||
652 | .remove = __exit_p(tlv320aic23_i2c_remove), | ||
653 | .id_table = tlv320aic23_id, | ||
654 | }; | ||
655 | |||
656 | #endif | ||
657 | |||
658 | static int tlv320aic23_probe(struct platform_device *pdev) | ||
659 | { | ||
660 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
661 | struct snd_soc_codec *codec; | ||
662 | int ret = 0; | ||
663 | |||
664 | printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); | ||
665 | |||
666 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
667 | if (codec == NULL) | ||
668 | return -ENOMEM; | ||
669 | |||
670 | socdev->codec = codec; | ||
671 | mutex_init(&codec->mutex); | ||
672 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
673 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
674 | |||
675 | tlv320aic23_socdev = socdev; | ||
676 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
677 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
678 | codec->hw_read = NULL; | ||
679 | ret = i2c_add_driver(&tlv320aic23_i2c_driver); | ||
680 | if (ret != 0) | ||
681 | printk(KERN_ERR "can't add i2c driver"); | ||
682 | #endif | ||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | static int tlv320aic23_remove(struct platform_device *pdev) | ||
687 | { | ||
688 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
689 | struct snd_soc_codec *codec = socdev->codec; | ||
690 | |||
691 | if (codec->control_data) | ||
692 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
693 | |||
694 | snd_soc_free_pcms(socdev); | ||
695 | snd_soc_dapm_free(socdev); | ||
696 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
697 | i2c_del_driver(&tlv320aic23_i2c_driver); | ||
698 | #endif | ||
699 | kfree(codec->reg_cache); | ||
700 | kfree(codec); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { | ||
705 | .probe = tlv320aic23_probe, | ||
706 | .remove = tlv320aic23_remove, | ||
707 | .suspend = tlv320aic23_suspend, | ||
708 | .resume = tlv320aic23_resume, | ||
709 | }; | ||
710 | EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); | ||
711 | |||
712 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); | ||
713 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
714 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h new file mode 100644 index 000000000000..79d1faf8e570 --- /dev/null +++ b/sound/soc/codecs/tlv320aic23.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC23 codec driver | ||
3 | * | ||
4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _TLV320AIC23_H | ||
13 | #define _TLV320AIC23_H | ||
14 | |||
15 | /* Codec TLV320AIC23 */ | ||
16 | #define TLV320AIC23_LINVOL 0x00 | ||
17 | #define TLV320AIC23_RINVOL 0x01 | ||
18 | #define TLV320AIC23_LCHNVOL 0x02 | ||
19 | #define TLV320AIC23_RCHNVOL 0x03 | ||
20 | #define TLV320AIC23_ANLG 0x04 | ||
21 | #define TLV320AIC23_DIGT 0x05 | ||
22 | #define TLV320AIC23_PWR 0x06 | ||
23 | #define TLV320AIC23_DIGT_FMT 0x07 | ||
24 | #define TLV320AIC23_SRATE 0x08 | ||
25 | #define TLV320AIC23_ACTIVE 0x09 | ||
26 | #define TLV320AIC23_RESET 0x0F | ||
27 | |||
28 | /* Left (right) line input volume control register */ | ||
29 | #define TLV320AIC23_LRS_ENABLED 0x0100 | ||
30 | #define TLV320AIC23_LIM_MUTED 0x0080 | ||
31 | #define TLV320AIC23_LIV_DEFAULT 0x0017 | ||
32 | #define TLV320AIC23_LIV_MAX 0x001f | ||
33 | #define TLV320AIC23_LIV_MIN 0x0000 | ||
34 | |||
35 | /* Left (right) channel headphone volume control register */ | ||
36 | #define TLV320AIC23_LZC_ON 0x0080 | ||
37 | #define TLV320AIC23_LHV_DEFAULT 0x0079 | ||
38 | #define TLV320AIC23_LHV_MAX 0x007f | ||
39 | #define TLV320AIC23_LHV_MIN 0x0000 | ||
40 | |||
41 | /* Analog audio path control register */ | ||
42 | #define TLV320AIC23_STA_REG(x) ((x)<<6) | ||
43 | #define TLV320AIC23_STE_ENABLED 0x0020 | ||
44 | #define TLV320AIC23_DAC_SELECTED 0x0010 | ||
45 | #define TLV320AIC23_BYPASS_ON 0x0008 | ||
46 | #define TLV320AIC23_INSEL_MIC 0x0004 | ||
47 | #define TLV320AIC23_MICM_MUTED 0x0002 | ||
48 | #define TLV320AIC23_MICB_20DB 0x0001 | ||
49 | |||
50 | /* Digital audio path control register */ | ||
51 | #define TLV320AIC23_DACM_MUTE 0x0008 | ||
52 | #define TLV320AIC23_DEEMP_32K 0x0002 | ||
53 | #define TLV320AIC23_DEEMP_44K 0x0004 | ||
54 | #define TLV320AIC23_DEEMP_48K 0x0006 | ||
55 | #define TLV320AIC23_ADCHP_ON 0x0001 | ||
56 | |||
57 | /* Power control down register */ | ||
58 | #define TLV320AIC23_DEVICE_PWR_OFF 0x0080 | ||
59 | #define TLV320AIC23_CLK_OFF 0x0040 | ||
60 | #define TLV320AIC23_OSC_OFF 0x0020 | ||
61 | #define TLV320AIC23_OUT_OFF 0x0010 | ||
62 | #define TLV320AIC23_DAC_OFF 0x0008 | ||
63 | #define TLV320AIC23_ADC_OFF 0x0004 | ||
64 | #define TLV320AIC23_MIC_OFF 0x0002 | ||
65 | #define TLV320AIC23_LINE_OFF 0x0001 | ||
66 | |||
67 | /* Digital audio interface register */ | ||
68 | #define TLV320AIC23_MS_MASTER 0x0040 | ||
69 | #define TLV320AIC23_LRSWAP_ON 0x0020 | ||
70 | #define TLV320AIC23_LRP_ON 0x0010 | ||
71 | #define TLV320AIC23_IWL_16 0x0000 | ||
72 | #define TLV320AIC23_IWL_20 0x0004 | ||
73 | #define TLV320AIC23_IWL_24 0x0008 | ||
74 | #define TLV320AIC23_IWL_32 0x000C | ||
75 | #define TLV320AIC23_FOR_I2S 0x0002 | ||
76 | #define TLV320AIC23_FOR_DSP 0x0003 | ||
77 | #define TLV320AIC23_FOR_LJUST 0x0001 | ||
78 | |||
79 | /* Sample rate control register */ | ||
80 | #define TLV320AIC23_CLKOUT_HALF 0x0080 | ||
81 | #define TLV320AIC23_CLKIN_HALF 0x0040 | ||
82 | #define TLV320AIC23_BOSR_384fs 0x0002 /* BOSR_272fs in USB mode */ | ||
83 | #define TLV320AIC23_USB_CLK_ON 0x0001 | ||
84 | #define TLV320AIC23_SR_MASK 0xf | ||
85 | #define TLV320AIC23_CLKOUT_SHIFT 7 | ||
86 | #define TLV320AIC23_CLKIN_SHIFT 6 | ||
87 | #define TLV320AIC23_SR_SHIFT 2 | ||
88 | #define TLV320AIC23_BOSR_SHIFT 1 | ||
89 | |||
90 | /* Digital interface register */ | ||
91 | #define TLV320AIC23_ACT_ON 0x0001 | ||
92 | |||
93 | /* | ||
94 | * AUDIO related MACROS | ||
95 | */ | ||
96 | |||
97 | #define TLV320AIC23_DEFAULT_OUT_VOL 0x70 | ||
98 | #define TLV320AIC23_DEFAULT_IN_VOLUME 0x10 | ||
99 | |||
100 | #define TLV320AIC23_OUT_VOL_MIN TLV320AIC23_LHV_MIN | ||
101 | #define TLV320AIC23_OUT_VOL_MAX TLV320AIC23_LHV_MAX | ||
102 | #define TLV320AIC23_OUT_VO_RANGE (TLV320AIC23_OUT_VOL_MAX - \ | ||
103 | TLV320AIC23_OUT_VOL_MIN) | ||
104 | #define TLV320AIC23_OUT_VOL_MASK TLV320AIC23_OUT_VOL_MAX | ||
105 | |||
106 | #define TLV320AIC23_IN_VOL_MIN TLV320AIC23_LIV_MIN | ||
107 | #define TLV320AIC23_IN_VOL_MAX TLV320AIC23_LIV_MAX | ||
108 | #define TLV320AIC23_IN_VOL_RANGE (TLV320AIC23_IN_VOL_MAX - \ | ||
109 | TLV320AIC23_IN_VOL_MIN) | ||
110 | #define TLV320AIC23_IN_VOL_MASK TLV320AIC23_IN_VOL_MAX | ||
111 | |||
112 | #define TLV320AIC23_SIDETONE_MASK 0x1c0 | ||
113 | #define TLV320AIC23_SIDETONE_0 0x100 | ||
114 | #define TLV320AIC23_SIDETONE_6 0x000 | ||
115 | #define TLV320AIC23_SIDETONE_9 0x040 | ||
116 | #define TLV320AIC23_SIDETONE_12 0x080 | ||
117 | #define TLV320AIC23_SIDETONE_18 0x0c0 | ||
118 | |||
119 | extern struct snd_soc_dai tlv320aic23_dai; | ||
120 | extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23; | ||
121 | |||
122 | #endif /* _TLV320AIC23_H */ | ||
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c new file mode 100644 index 000000000000..bed8a9e63ddc --- /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 000000000000..786ba16c945f --- /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 5f9abb199435..05336ed7e493 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 |
@@ -48,7 +48,6 @@ | |||
48 | 48 | ||
49 | #include "tlv320aic3x.h" | 49 | #include "tlv320aic3x.h" |
50 | 50 | ||
51 | #define AUDIO_NAME "aic3x" | ||
52 | #define AIC3X_VERSION "0.2" | 51 | #define AIC3X_VERSION "0.2" |
53 | 52 | ||
54 | /* codec private data */ | 53 | /* codec private data */ |
@@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected); | |||
991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 990 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
992 | 991 | ||
993 | struct snd_soc_dai aic3x_dai = { | 992 | struct snd_soc_dai aic3x_dai = { |
994 | .name = "aic3x", | 993 | .name = "tlv320aic3x", |
995 | .playback = { | 994 | .playback = { |
996 | .stream_name = "Playback", | 995 | .stream_name = "Playback", |
997 | .channels_min = 1, | 996 | .channels_min = 1, |
@@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1055 | struct aic3x_setup_data *setup = socdev->codec_data; | 1054 | struct aic3x_setup_data *setup = socdev->codec_data; |
1056 | int reg, ret = 0; | 1055 | int reg, ret = 0; |
1057 | 1056 | ||
1058 | codec->name = "aic3x"; | 1057 | codec->name = "tlv320aic3x"; |
1059 | codec->owner = THIS_MODULE; | 1058 | codec->owner = THIS_MODULE; |
1060 | codec->read = aic3x_read_reg_cache; | 1059 | codec->read = aic3x_read_reg_cache; |
1061 | codec->write = aic3x_write; | 1060 | codec->write = aic3x_write; |
@@ -1172,71 +1171,39 @@ static struct snd_soc_device *aic3x_socdev; | |||
1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses | 1171 | * AIC3X 2 wire address can be up to 4 devices with device addresses |
1173 | * 0x18, 0x19, 0x1A, 0x1B | 1172 | * 0x18, 0x19, 0x1A, 0x1B |
1174 | */ | 1173 | */ |
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 | 1174 | ||
1183 | /* | 1175 | /* |
1184 | * If the i2c layer weren't so broken, we could pass this kind of data | 1176 | * If the i2c layer weren't so broken, we could pass this kind of data |
1185 | * around | 1177 | * around |
1186 | */ | 1178 | */ |
1187 | static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 1179 | static int aic3x_i2c_probe(struct i2c_client *i2c, |
1180 | const struct i2c_device_id *id) | ||
1188 | { | 1181 | { |
1189 | struct snd_soc_device *socdev = aic3x_socdev; | 1182 | struct snd_soc_device *socdev = aic3x_socdev; |
1190 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
1191 | struct snd_soc_codec *codec = socdev->codec; | 1183 | struct snd_soc_codec *codec = socdev->codec; |
1192 | struct i2c_client *i2c; | ||
1193 | int ret; | 1184 | int ret; |
1194 | 1185 | ||
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); | 1186 | i2c_set_clientdata(i2c, codec); |
1206 | codec->control_data = i2c; | 1187 | codec->control_data = i2c; |
1207 | 1188 | ||
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); | 1189 | ret = aic3x_init(socdev); |
1216 | if (ret < 0) { | 1190 | if (ret < 0) |
1217 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); | 1191 | 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; | 1192 | return ret; |
1225 | } | 1193 | } |
1226 | 1194 | ||
1227 | static int aic3x_i2c_detach(struct i2c_client *client) | 1195 | static int aic3x_i2c_remove(struct i2c_client *client) |
1228 | { | 1196 | { |
1229 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1197 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1230 | i2c_detach_client(client); | ||
1231 | kfree(codec->reg_cache); | 1198 | kfree(codec->reg_cache); |
1232 | kfree(client); | ||
1233 | return 0; | 1199 | return 0; |
1234 | } | 1200 | } |
1235 | 1201 | ||
1236 | static int aic3x_i2c_attach(struct i2c_adapter *adap) | 1202 | static const struct i2c_device_id aic3x_i2c_id[] = { |
1237 | { | 1203 | { "tlv320aic3x", 0 }, |
1238 | return i2c_probe(adap, &addr_data, aic3x_codec_probe); | 1204 | { } |
1239 | } | 1205 | }; |
1206 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1240 | 1207 | ||
1241 | /* machine i2c codec control layer */ | 1208 | /* machine i2c codec control layer */ |
1242 | static struct i2c_driver aic3x_i2c_driver = { | 1209 | static struct i2c_driver aic3x_i2c_driver = { |
@@ -1244,13 +1211,9 @@ static struct i2c_driver aic3x_i2c_driver = { | |||
1244 | .name = "aic3x I2C Codec", | 1211 | .name = "aic3x I2C Codec", |
1245 | .owner = THIS_MODULE, | 1212 | .owner = THIS_MODULE, |
1246 | }, | 1213 | }, |
1247 | .attach_adapter = aic3x_i2c_attach, | 1214 | .probe = aic3x_i2c_probe, |
1248 | .detach_client = aic3x_i2c_detach, | 1215 | .remove = aic3x_i2c_remove, |
1249 | }; | 1216 | .id_table = aic3x_i2c_id, |
1250 | |||
1251 | static struct i2c_client client_template = { | ||
1252 | .name = "AIC3X", | ||
1253 | .driver = &aic3x_i2c_driver, | ||
1254 | }; | 1217 | }; |
1255 | 1218 | ||
1256 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | 1219 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) |
@@ -1258,6 +1221,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]); | 1221 | value[0] = i2c_smbus_read_byte_data(client, value[0]); |
1259 | return (len == 1); | 1222 | return (len == 1); |
1260 | } | 1223 | } |
1224 | |||
1225 | static int aic3x_add_i2c_device(struct platform_device *pdev, | ||
1226 | const struct aic3x_setup_data *setup) | ||
1227 | { | ||
1228 | struct i2c_board_info info; | ||
1229 | struct i2c_adapter *adapter; | ||
1230 | struct i2c_client *client; | ||
1231 | int ret; | ||
1232 | |||
1233 | ret = i2c_add_driver(&aic3x_i2c_driver); | ||
1234 | if (ret != 0) { | ||
1235 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1236 | return ret; | ||
1237 | } | ||
1238 | |||
1239 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1240 | info.addr = setup->i2c_address; | ||
1241 | strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE); | ||
1242 | |||
1243 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1244 | if (!adapter) { | ||
1245 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1246 | setup->i2c_bus); | ||
1247 | goto err_driver; | ||
1248 | } | ||
1249 | |||
1250 | client = i2c_new_device(adapter, &info); | ||
1251 | i2c_put_adapter(adapter); | ||
1252 | if (!client) { | ||
1253 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1254 | (unsigned int)info.addr); | ||
1255 | goto err_driver; | ||
1256 | } | ||
1257 | |||
1258 | return 0; | ||
1259 | |||
1260 | err_driver: | ||
1261 | i2c_del_driver(&aic3x_i2c_driver); | ||
1262 | return -ENODEV; | ||
1263 | } | ||
1261 | #endif | 1264 | #endif |
1262 | 1265 | ||
1263 | static int aic3x_probe(struct platform_device *pdev) | 1266 | static int aic3x_probe(struct platform_device *pdev) |
@@ -1290,12 +1293,9 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1290 | aic3x_socdev = socdev; | 1293 | aic3x_socdev = socdev; |
1291 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1294 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1292 | if (setup->i2c_address) { | 1295 | if (setup->i2c_address) { |
1293 | normal_i2c[0] = setup->i2c_address; | ||
1294 | codec->hw_write = (hw_write_t) i2c_master_send; | 1296 | codec->hw_write = (hw_write_t) i2c_master_send; |
1295 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | 1297 | codec->hw_read = (hw_read_t) aic3x_i2c_read; |
1296 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1298 | ret = aic3x_add_i2c_device(pdev, setup); |
1297 | if (ret != 0) | ||
1298 | printk(KERN_ERR "can't add i2c driver"); | ||
1299 | } | 1299 | } |
1300 | #else | 1300 | #else |
1301 | /* Add other interfaces here */ | 1301 | /* Add other interfaces here */ |
@@ -1320,6 +1320,7 @@ static int aic3x_remove(struct platform_device *pdev) | |||
1320 | snd_soc_free_pcms(socdev); | 1320 | snd_soc_free_pcms(socdev); |
1321 | snd_soc_dapm_free(socdev); | 1321 | snd_soc_dapm_free(socdev); |
1322 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1322 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1323 | i2c_unregister_device(codec->control_data); | ||
1323 | i2c_del_driver(&aic3x_i2c_driver); | 1324 | i2c_del_driver(&aic3x_i2c_driver); |
1324 | #endif | 1325 | #endif |
1325 | kfree(codec->private_data); | 1326 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d76c079b86e7..00a195aa02e4 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 807318fbdc8f..a69ee72a7af5 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include "uda1380.h" | 36 | #include "uda1380.h" |
37 | 37 | ||
38 | #define UDA1380_VERSION "0.6" | 38 | #define UDA1380_VERSION "0.6" |
39 | #define AUDIO_NAME "uda1380" | ||
40 | 39 | ||
41 | /* | 40 | /* |
42 | * uda1380 register cache | 41 | * uda1380 register cache |
@@ -701,87 +700,86 @@ static struct snd_soc_device *uda1380_socdev; | |||
701 | 700 | ||
702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 701 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
703 | 702 | ||
704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | 703 | static int uda1380_i2c_probe(struct i2c_client *i2c, |
705 | 704 | 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 | { | 705 | { |
719 | struct snd_soc_device *socdev = uda1380_socdev; | 706 | struct snd_soc_device *socdev = uda1380_socdev; |
720 | struct uda1380_setup_data *setup = socdev->codec_data; | 707 | struct uda1380_setup_data *setup = socdev->codec_data; |
721 | struct snd_soc_codec *codec = socdev->codec; | 708 | struct snd_soc_codec *codec = socdev->codec; |
722 | struct i2c_client *i2c; | ||
723 | int ret; | 709 | int ret; |
724 | 710 | ||
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); | 711 | i2c_set_clientdata(i2c, codec); |
736 | codec->control_data = i2c; | 712 | codec->control_data = i2c; |
737 | 713 | ||
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); | 714 | ret = uda1380_init(socdev, setup->dac_clk); |
745 | if (ret < 0) { | 715 | if (ret < 0) |
746 | pr_err("uda1380: failed to initialise UDA1380\n"); | 716 | pr_err("uda1380: failed to initialise UDA1380\n"); |
747 | goto err; | ||
748 | } | ||
749 | return ret; | ||
750 | 717 | ||
751 | err: | ||
752 | kfree(i2c); | ||
753 | return ret; | 718 | return ret; |
754 | } | 719 | } |
755 | 720 | ||
756 | static int uda1380_i2c_detach(struct i2c_client *client) | 721 | static int uda1380_i2c_remove(struct i2c_client *client) |
757 | { | 722 | { |
758 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 723 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
759 | i2c_detach_client(client); | ||
760 | kfree(codec->reg_cache); | 724 | kfree(codec->reg_cache); |
761 | kfree(client); | ||
762 | return 0; | 725 | return 0; |
763 | } | 726 | } |
764 | 727 | ||
765 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | 728 | static const struct i2c_device_id uda1380_i2c_id[] = { |
766 | { | 729 | { "uda1380", 0 }, |
767 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | 730 | { } |
768 | } | 731 | }; |
732 | MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); | ||
769 | 733 | ||
770 | static struct i2c_driver uda1380_i2c_driver = { | 734 | static struct i2c_driver uda1380_i2c_driver = { |
771 | .driver = { | 735 | .driver = { |
772 | .name = "UDA1380 I2C Codec", | 736 | .name = "UDA1380 I2C Codec", |
773 | .owner = THIS_MODULE, | 737 | .owner = THIS_MODULE, |
774 | }, | 738 | }, |
775 | .id = I2C_DRIVERID_UDA1380, | 739 | .probe = uda1380_i2c_probe, |
776 | .attach_adapter = uda1380_i2c_attach, | 740 | .remove = uda1380_i2c_remove, |
777 | .detach_client = uda1380_i2c_detach, | 741 | .id_table = uda1380_i2c_id, |
778 | .command = NULL, | ||
779 | }; | 742 | }; |
780 | 743 | ||
781 | static struct i2c_client client_template = { | 744 | static int uda1380_add_i2c_device(struct platform_device *pdev, |
782 | .name = "UDA1380", | 745 | const struct uda1380_setup_data *setup) |
783 | .driver = &uda1380_i2c_driver, | 746 | { |
784 | }; | 747 | struct i2c_board_info info; |
748 | struct i2c_adapter *adapter; | ||
749 | struct i2c_client *client; | ||
750 | int ret; | ||
751 | |||
752 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
753 | if (ret != 0) { | ||
754 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
759 | info.addr = setup->i2c_address; | ||
760 | strlcpy(info.type, "uda1380", I2C_NAME_SIZE); | ||
761 | |||
762 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
763 | if (!adapter) { | ||
764 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
765 | setup->i2c_bus); | ||
766 | goto err_driver; | ||
767 | } | ||
768 | |||
769 | client = i2c_new_device(adapter, &info); | ||
770 | i2c_put_adapter(adapter); | ||
771 | if (!client) { | ||
772 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
773 | (unsigned int)info.addr); | ||
774 | goto err_driver; | ||
775 | } | ||
776 | |||
777 | return 0; | ||
778 | |||
779 | err_driver: | ||
780 | i2c_del_driver(&uda1380_i2c_driver); | ||
781 | return -ENODEV; | ||
782 | } | ||
785 | #endif | 783 | #endif |
786 | 784 | ||
787 | static int uda1380_probe(struct platform_device *pdev) | 785 | static int uda1380_probe(struct platform_device *pdev) |
@@ -789,7 +787,7 @@ static int uda1380_probe(struct platform_device *pdev) | |||
789 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 787 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
790 | struct uda1380_setup_data *setup; | 788 | struct uda1380_setup_data *setup; |
791 | struct snd_soc_codec *codec; | 789 | struct snd_soc_codec *codec; |
792 | int ret = 0; | 790 | int ret; |
793 | 791 | ||
794 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | 792 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); |
795 | 793 | ||
@@ -804,16 +802,13 @@ static int uda1380_probe(struct platform_device *pdev) | |||
804 | INIT_LIST_HEAD(&codec->dapm_paths); | 802 | INIT_LIST_HEAD(&codec->dapm_paths); |
805 | 803 | ||
806 | uda1380_socdev = socdev; | 804 | uda1380_socdev = socdev; |
805 | ret = -ENODEV; | ||
806 | |||
807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
808 | if (setup->i2c_address) { | 808 | if (setup->i2c_address) { |
809 | normal_i2c[0] = setup->i2c_address; | ||
810 | codec->hw_write = (hw_write_t)i2c_master_send; | 809 | codec->hw_write = (hw_write_t)i2c_master_send; |
811 | ret = i2c_add_driver(&uda1380_i2c_driver); | 810 | ret = uda1380_add_i2c_device(pdev, setup); |
812 | if (ret != 0) | ||
813 | printk(KERN_ERR "can't add i2c driver"); | ||
814 | } | 811 | } |
815 | #else | ||
816 | /* Add other interfaces here */ | ||
817 | #endif | 812 | #endif |
818 | 813 | ||
819 | if (ret != 0) | 814 | if (ret != 0) |
@@ -833,6 +828,7 @@ static int uda1380_remove(struct platform_device *pdev) | |||
833 | snd_soc_free_pcms(socdev); | 828 | snd_soc_free_pcms(socdev); |
834 | snd_soc_dapm_free(socdev); | 829 | snd_soc_dapm_free(socdev); |
835 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 830 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
831 | i2c_unregister_device(codec->control_data); | ||
836 | i2c_del_driver(&uda1380_i2c_driver); | 832 | i2c_del_driver(&uda1380_i2c_driver); |
837 | #endif | 833 | #endif |
838 | kfree(codec); | 834 | kfree(codec); |
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index 50c603e2c9f2..c55c17a52a12 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 3d998e6a997e..d8ca2da8d634 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 6 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/spi/spi.h> | ||
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
@@ -27,7 +28,6 @@ | |||
27 | 28 | ||
28 | #include "wm8510.h" | 29 | #include "wm8510.h" |
29 | 30 | ||
30 | #define AUDIO_NAME "wm8510" | ||
31 | #define WM8510_VERSION "0.6" | 31 | #define WM8510_VERSION "0.6" |
32 | 32 | ||
33 | struct snd_soc_codec_device soc_codec_dev_wm8510; | 33 | struct snd_soc_codec_device soc_codec_dev_wm8510; |
@@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | |||
55 | 0x0001, | 55 | 0x0001, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | #define WM8510_POWER1_BIASEN 0x08 | ||
59 | #define WM8510_POWER1_BUFIOEN 0x10 | ||
60 | |||
58 | /* | 61 | /* |
59 | * read wm8510 register cache | 62 | * read wm8510 register cache |
60 | */ | 63 | */ |
@@ -199,7 +202,7 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), | |||
199 | }; | 202 | }; |
200 | 203 | ||
201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | 204 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { |
202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | 205 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 1), |
203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | 206 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), |
204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | 207 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), |
205 | }; | 208 | }; |
@@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), | |||
224 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), | 227 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), |
225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), | 228 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), |
226 | 229 | ||
227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, | 230 | SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0, |
228 | &wm8510_micpga_controls[0], | 231 | &wm8510_micpga_controls[0], |
229 | ARRAY_SIZE(wm8510_micpga_controls)), | 232 | ARRAY_SIZE(wm8510_micpga_controls)), |
230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, | 233 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, |
231 | &wm8510_boost_controls[0], | 234 | &wm8510_boost_controls[0], |
232 | ARRAY_SIZE(wm8510_boost_controls)), | 235 | ARRAY_SIZE(wm8510_boost_controls)), |
@@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute) | |||
526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | 529 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, |
527 | enum snd_soc_bias_level level) | 530 | enum snd_soc_bias_level level) |
528 | { | 531 | { |
532 | u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3; | ||
529 | 533 | ||
530 | switch (level) { | 534 | switch (level) { |
531 | case SND_SOC_BIAS_ON: | 535 | case SND_SOC_BIAS_ON: |
532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); | ||
533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); | ||
534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); | ||
535 | break; | ||
536 | case SND_SOC_BIAS_PREPARE: | 536 | case SND_SOC_BIAS_PREPARE: |
537 | power1 |= 0x1; /* VMID 50k */ | ||
538 | wm8510_write(codec, WM8510_POWER1, power1); | ||
539 | break; | ||
540 | |||
537 | case SND_SOC_BIAS_STANDBY: | 541 | case SND_SOC_BIAS_STANDBY: |
542 | power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN; | ||
543 | |||
544 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
545 | /* Initial cap charge at VMID 5k */ | ||
546 | wm8510_write(codec, WM8510_POWER1, power1 | 0x3); | ||
547 | mdelay(100); | ||
548 | } | ||
549 | |||
550 | power1 |= 0x2; /* VMID 500k */ | ||
551 | wm8510_write(codec, WM8510_POWER1, power1); | ||
538 | break; | 552 | break; |
553 | |||
539 | case SND_SOC_BIAS_OFF: | 554 | case SND_SOC_BIAS_OFF: |
540 | /* everything off, dac mute, inactive */ | 555 | wm8510_write(codec, WM8510_POWER1, 0); |
541 | wm8510_write(codec, WM8510_POWER1, 0x0); | 556 | wm8510_write(codec, WM8510_POWER2, 0); |
542 | wm8510_write(codec, WM8510_POWER2, 0x0); | 557 | wm8510_write(codec, WM8510_POWER3, 0); |
543 | wm8510_write(codec, WM8510_POWER3, 0x0); | ||
544 | break; | 558 | break; |
545 | } | 559 | } |
560 | |||
546 | codec->bias_level = level; | 561 | codec->bias_level = level; |
547 | return 0; | 562 | return 0; |
548 | } | 563 | } |
@@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev) | |||
640 | } | 655 | } |
641 | 656 | ||
642 | /* power on device */ | 657 | /* power on device */ |
658 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 659 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
644 | wm8510_add_controls(codec); | 660 | wm8510_add_controls(codec); |
645 | wm8510_add_widgets(codec); | 661 | wm8510_add_widgets(codec); |
@@ -665,90 +681,144 @@ static struct snd_soc_device *wm8510_socdev; | |||
665 | /* | 681 | /* |
666 | * WM8510 2 wire address is 0x1a | 682 | * WM8510 2 wire address is 0x1a |
667 | */ | 683 | */ |
668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | ||
669 | |||
670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
671 | 684 | ||
672 | /* Magic definition of all other variables and things */ | 685 | static int wm8510_i2c_probe(struct i2c_client *i2c, |
673 | I2C_CLIENT_INSMOD; | 686 | const struct i2c_device_id *id) |
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 | { | 687 | { |
683 | struct snd_soc_device *socdev = wm8510_socdev; | 688 | struct snd_soc_device *socdev = wm8510_socdev; |
684 | struct wm8510_setup_data *setup = socdev->codec_data; | ||
685 | struct snd_soc_codec *codec = socdev->codec; | 689 | struct snd_soc_codec *codec = socdev->codec; |
686 | struct i2c_client *i2c; | ||
687 | int ret; | 690 | int ret; |
688 | 691 | ||
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); | 692 | i2c_set_clientdata(i2c, codec); |
700 | codec->control_data = i2c; | 693 | codec->control_data = i2c; |
701 | 694 | ||
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); | 695 | ret = wm8510_init(socdev); |
709 | if (ret < 0) { | 696 | if (ret < 0) |
710 | pr_err("failed to initialise WM8510\n"); | 697 | pr_err("failed to initialise WM8510\n"); |
711 | goto err; | ||
712 | } | ||
713 | return ret; | ||
714 | 698 | ||
715 | err: | ||
716 | kfree(i2c); | ||
717 | return ret; | 699 | return ret; |
718 | } | 700 | } |
719 | 701 | ||
720 | static int wm8510_i2c_detach(struct i2c_client *client) | 702 | static int wm8510_i2c_remove(struct i2c_client *client) |
721 | { | 703 | { |
722 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 704 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
723 | i2c_detach_client(client); | ||
724 | kfree(codec->reg_cache); | 705 | kfree(codec->reg_cache); |
725 | kfree(client); | ||
726 | return 0; | 706 | return 0; |
727 | } | 707 | } |
728 | 708 | ||
729 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | 709 | static const struct i2c_device_id wm8510_i2c_id[] = { |
730 | { | 710 | { "wm8510", 0 }, |
731 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | 711 | { } |
732 | } | 712 | }; |
713 | MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); | ||
733 | 714 | ||
734 | /* corgi i2c codec control layer */ | ||
735 | static struct i2c_driver wm8510_i2c_driver = { | 715 | static struct i2c_driver wm8510_i2c_driver = { |
736 | .driver = { | 716 | .driver = { |
737 | .name = "WM8510 I2C Codec", | 717 | .name = "WM8510 I2C Codec", |
738 | .owner = THIS_MODULE, | 718 | .owner = THIS_MODULE, |
739 | }, | 719 | }, |
740 | .id = I2C_DRIVERID_WM8510, | 720 | .probe = wm8510_i2c_probe, |
741 | .attach_adapter = wm8510_i2c_attach, | 721 | .remove = wm8510_i2c_remove, |
742 | .detach_client = wm8510_i2c_detach, | 722 | .id_table = wm8510_i2c_id, |
743 | .command = NULL, | ||
744 | }; | 723 | }; |
745 | 724 | ||
746 | static struct i2c_client client_template = { | 725 | static int wm8510_add_i2c_device(struct platform_device *pdev, |
747 | .name = "WM8510", | 726 | const struct wm8510_setup_data *setup) |
748 | .driver = &wm8510_i2c_driver, | 727 | { |
749 | }; | 728 | struct i2c_board_info info; |
729 | struct i2c_adapter *adapter; | ||
730 | struct i2c_client *client; | ||
731 | int ret; | ||
732 | |||
733 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
734 | if (ret != 0) { | ||
735 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
740 | info.addr = setup->i2c_address; | ||
741 | strlcpy(info.type, "wm8510", I2C_NAME_SIZE); | ||
742 | |||
743 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
744 | if (!adapter) { | ||
745 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
746 | setup->i2c_bus); | ||
747 | goto err_driver; | ||
748 | } | ||
749 | |||
750 | client = i2c_new_device(adapter, &info); | ||
751 | i2c_put_adapter(adapter); | ||
752 | if (!client) { | ||
753 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
754 | (unsigned int)info.addr); | ||
755 | goto err_driver; | ||
756 | } | ||
757 | |||
758 | return 0; | ||
759 | |||
760 | err_driver: | ||
761 | i2c_del_driver(&wm8510_i2c_driver); | ||
762 | return -ENODEV; | ||
763 | } | ||
750 | #endif | 764 | #endif |
751 | 765 | ||
766 | #if defined(CONFIG_SPI_MASTER) | ||
767 | static int __devinit wm8510_spi_probe(struct spi_device *spi) | ||
768 | { | ||
769 | struct snd_soc_device *socdev = wm8510_socdev; | ||
770 | struct snd_soc_codec *codec = socdev->codec; | ||
771 | int ret; | ||
772 | |||
773 | codec->control_data = spi; | ||
774 | |||
775 | ret = wm8510_init(socdev); | ||
776 | if (ret < 0) | ||
777 | dev_err(&spi->dev, "failed to initialise WM8510\n"); | ||
778 | |||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | static int __devexit wm8510_spi_remove(struct spi_device *spi) | ||
783 | { | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static struct spi_driver wm8510_spi_driver = { | ||
788 | .driver = { | ||
789 | .name = "wm8510", | ||
790 | .bus = &spi_bus_type, | ||
791 | .owner = THIS_MODULE, | ||
792 | }, | ||
793 | .probe = wm8510_spi_probe, | ||
794 | .remove = __devexit_p(wm8510_spi_remove), | ||
795 | }; | ||
796 | |||
797 | static int wm8510_spi_write(struct spi_device *spi, const char *data, int len) | ||
798 | { | ||
799 | struct spi_transfer t; | ||
800 | struct spi_message m; | ||
801 | u8 msg[2]; | ||
802 | |||
803 | if (len <= 0) | ||
804 | return 0; | ||
805 | |||
806 | msg[0] = data[0]; | ||
807 | msg[1] = data[1]; | ||
808 | |||
809 | spi_message_init(&m); | ||
810 | memset(&t, 0, (sizeof t)); | ||
811 | |||
812 | t.tx_buf = &msg[0]; | ||
813 | t.len = len; | ||
814 | |||
815 | spi_message_add_tail(&t, &m); | ||
816 | spi_sync(spi, &m); | ||
817 | |||
818 | return len; | ||
819 | } | ||
820 | #endif /* CONFIG_SPI_MASTER */ | ||
821 | |||
752 | static int wm8510_probe(struct platform_device *pdev) | 822 | static int wm8510_probe(struct platform_device *pdev) |
753 | { | 823 | { |
754 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 824 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -771,14 +841,17 @@ static int wm8510_probe(struct platform_device *pdev) | |||
771 | wm8510_socdev = socdev; | 841 | wm8510_socdev = socdev; |
772 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 842 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
773 | if (setup->i2c_address) { | 843 | if (setup->i2c_address) { |
774 | normal_i2c[0] = setup->i2c_address; | ||
775 | codec->hw_write = (hw_write_t)i2c_master_send; | 844 | codec->hw_write = (hw_write_t)i2c_master_send; |
776 | ret = i2c_add_driver(&wm8510_i2c_driver); | 845 | ret = wm8510_add_i2c_device(pdev, setup); |
846 | } | ||
847 | #endif | ||
848 | #if defined(CONFIG_SPI_MASTER) | ||
849 | if (setup->spi) { | ||
850 | codec->hw_write = (hw_write_t)wm8510_spi_write; | ||
851 | ret = spi_register_driver(&wm8510_spi_driver); | ||
777 | if (ret != 0) | 852 | if (ret != 0) |
778 | printk(KERN_ERR "can't add i2c driver"); | 853 | printk(KERN_ERR "can't add spi driver"); |
779 | } | 854 | } |
780 | #else | ||
781 | /* Add other interfaces here */ | ||
782 | #endif | 855 | #endif |
783 | 856 | ||
784 | if (ret != 0) | 857 | if (ret != 0) |
@@ -798,8 +871,12 @@ static int wm8510_remove(struct platform_device *pdev) | |||
798 | snd_soc_free_pcms(socdev); | 871 | snd_soc_free_pcms(socdev); |
799 | snd_soc_dapm_free(socdev); | 872 | snd_soc_dapm_free(socdev); |
800 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 873 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
874 | i2c_unregister_device(codec->control_data); | ||
801 | i2c_del_driver(&wm8510_i2c_driver); | 875 | i2c_del_driver(&wm8510_i2c_driver); |
802 | #endif | 876 | #endif |
877 | #if defined(CONFIG_SPI_MASTER) | ||
878 | spi_unregister_driver(&wm8510_spi_driver); | ||
879 | #endif | ||
803 | kfree(codec); | 880 | kfree(codec); |
804 | 881 | ||
805 | return 0; | 882 | return 0; |
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h index f5d2e42eb3f4..bdefcf5c69ff 100644 --- a/sound/soc/codecs/wm8510.h +++ b/sound/soc/codecs/wm8510.h | |||
@@ -94,6 +94,8 @@ | |||
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 spi; | ||
98 | int i2c_bus; | ||
97 | unsigned short i2c_address; | 99 | unsigned short i2c_address; |
98 | }; | 100 | }; |
99 | 101 | ||
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c new file mode 100644 index 000000000000..627ebfb4209b --- /dev/null +++ b/sound/soc/codecs/wm8580.c | |||
@@ -0,0 +1,1053 @@ | |||
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/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/pm.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/tlv.h> | ||
33 | #include <sound/initval.h> | ||
34 | #include <asm/div64.h> | ||
35 | |||
36 | #include "wm8580.h" | ||
37 | |||
38 | #define WM8580_VERSION "0.1" | ||
39 | |||
40 | struct pll_state { | ||
41 | unsigned int in; | ||
42 | unsigned int out; | ||
43 | }; | ||
44 | |||
45 | /* codec private data */ | ||
46 | struct wm8580_priv { | ||
47 | struct pll_state a; | ||
48 | struct pll_state b; | ||
49 | }; | ||
50 | |||
51 | /* WM8580 register space */ | ||
52 | #define WM8580_PLLA1 0x00 | ||
53 | #define WM8580_PLLA2 0x01 | ||
54 | #define WM8580_PLLA3 0x02 | ||
55 | #define WM8580_PLLA4 0x03 | ||
56 | #define WM8580_PLLB1 0x04 | ||
57 | #define WM8580_PLLB2 0x05 | ||
58 | #define WM8580_PLLB3 0x06 | ||
59 | #define WM8580_PLLB4 0x07 | ||
60 | #define WM8580_CLKSEL 0x08 | ||
61 | #define WM8580_PAIF1 0x09 | ||
62 | #define WM8580_PAIF2 0x0A | ||
63 | #define WM8580_SAIF1 0x0B | ||
64 | #define WM8580_PAIF3 0x0C | ||
65 | #define WM8580_PAIF4 0x0D | ||
66 | #define WM8580_SAIF2 0x0E | ||
67 | #define WM8580_DAC_CONTROL1 0x0F | ||
68 | #define WM8580_DAC_CONTROL2 0x10 | ||
69 | #define WM8580_DAC_CONTROL3 0x11 | ||
70 | #define WM8580_DAC_CONTROL4 0x12 | ||
71 | #define WM8580_DAC_CONTROL5 0x13 | ||
72 | #define WM8580_DIGITAL_ATTENUATION_DACL1 0x14 | ||
73 | #define WM8580_DIGITAL_ATTENUATION_DACR1 0x15 | ||
74 | #define WM8580_DIGITAL_ATTENUATION_DACL2 0x16 | ||
75 | #define WM8580_DIGITAL_ATTENUATION_DACR2 0x17 | ||
76 | #define WM8580_DIGITAL_ATTENUATION_DACL3 0x18 | ||
77 | #define WM8580_DIGITAL_ATTENUATION_DACR3 0x19 | ||
78 | #define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C | ||
79 | #define WM8580_ADC_CONTROL1 0x1D | ||
80 | #define WM8580_SPDTXCHAN0 0x1E | ||
81 | #define WM8580_SPDTXCHAN1 0x1F | ||
82 | #define WM8580_SPDTXCHAN2 0x20 | ||
83 | #define WM8580_SPDTXCHAN3 0x21 | ||
84 | #define WM8580_SPDTXCHAN4 0x22 | ||
85 | #define WM8580_SPDTXCHAN5 0x23 | ||
86 | #define WM8580_SPDMODE 0x24 | ||
87 | #define WM8580_INTMASK 0x25 | ||
88 | #define WM8580_GPO1 0x26 | ||
89 | #define WM8580_GPO2 0x27 | ||
90 | #define WM8580_GPO3 0x28 | ||
91 | #define WM8580_GPO4 0x29 | ||
92 | #define WM8580_GPO5 0x2A | ||
93 | #define WM8580_INTSTAT 0x2B | ||
94 | #define WM8580_SPDRXCHAN1 0x2C | ||
95 | #define WM8580_SPDRXCHAN2 0x2D | ||
96 | #define WM8580_SPDRXCHAN3 0x2E | ||
97 | #define WM8580_SPDRXCHAN4 0x2F | ||
98 | #define WM8580_SPDRXCHAN5 0x30 | ||
99 | #define WM8580_SPDSTAT 0x31 | ||
100 | #define WM8580_PWRDN1 0x32 | ||
101 | #define WM8580_PWRDN2 0x33 | ||
102 | #define WM8580_READBACK 0x34 | ||
103 | #define WM8580_RESET 0x35 | ||
104 | |||
105 | /* PLLB4 (register 7h) */ | ||
106 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | ||
107 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | ||
108 | #define WM8580_PLLB4_MCLKOUTSRC_PLLB 0x40 | ||
109 | #define WM8580_PLLB4_MCLKOUTSRC_OSC 0x60 | ||
110 | |||
111 | #define WM8580_PLLB4_CLKOUTSRC_MASK 0x180 | ||
112 | #define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080 | ||
113 | #define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100 | ||
114 | #define WM8580_PLLB4_CLKOUTSRC_OSCCLK 0x180 | ||
115 | |||
116 | /* CLKSEL (register 8h) */ | ||
117 | #define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03 | ||
118 | #define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01 | ||
119 | #define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02 | ||
120 | |||
121 | /* AIF control 1 (registers 9h-bh) */ | ||
122 | #define WM8580_AIF_RATE_MASK 0x7 | ||
123 | #define WM8580_AIF_RATE_128 0x0 | ||
124 | #define WM8580_AIF_RATE_192 0x1 | ||
125 | #define WM8580_AIF_RATE_256 0x2 | ||
126 | #define WM8580_AIF_RATE_384 0x3 | ||
127 | #define WM8580_AIF_RATE_512 0x4 | ||
128 | #define WM8580_AIF_RATE_768 0x5 | ||
129 | #define WM8580_AIF_RATE_1152 0x6 | ||
130 | |||
131 | #define WM8580_AIF_BCLKSEL_MASK 0x18 | ||
132 | #define WM8580_AIF_BCLKSEL_64 0x00 | ||
133 | #define WM8580_AIF_BCLKSEL_128 0x08 | ||
134 | #define WM8580_AIF_BCLKSEL_256 0x10 | ||
135 | #define WM8580_AIF_BCLKSEL_SYSCLK 0x18 | ||
136 | |||
137 | #define WM8580_AIF_MS 0x20 | ||
138 | |||
139 | #define WM8580_AIF_CLKSRC_MASK 0xc0 | ||
140 | #define WM8580_AIF_CLKSRC_PLLA 0x40 | ||
141 | #define WM8580_AIF_CLKSRC_PLLB 0x40 | ||
142 | #define WM8580_AIF_CLKSRC_MCLK 0xc0 | ||
143 | |||
144 | /* AIF control 2 (registers ch-eh) */ | ||
145 | #define WM8580_AIF_FMT_MASK 0x03 | ||
146 | #define WM8580_AIF_FMT_RIGHTJ 0x00 | ||
147 | #define WM8580_AIF_FMT_LEFTJ 0x01 | ||
148 | #define WM8580_AIF_FMT_I2S 0x02 | ||
149 | #define WM8580_AIF_FMT_DSP 0x03 | ||
150 | |||
151 | #define WM8580_AIF_LENGTH_MASK 0x0c | ||
152 | #define WM8580_AIF_LENGTH_16 0x00 | ||
153 | #define WM8580_AIF_LENGTH_20 0x04 | ||
154 | #define WM8580_AIF_LENGTH_24 0x08 | ||
155 | #define WM8580_AIF_LENGTH_32 0x0c | ||
156 | |||
157 | #define WM8580_AIF_LRP 0x10 | ||
158 | #define WM8580_AIF_BCP 0x20 | ||
159 | |||
160 | /* Powerdown Register 1 (register 32h) */ | ||
161 | #define WM8580_PWRDN1_PWDN 0x001 | ||
162 | #define WM8580_PWRDN1_ALLDACPD 0x040 | ||
163 | |||
164 | /* Powerdown Register 2 (register 33h) */ | ||
165 | #define WM8580_PWRDN2_OSSCPD 0x001 | ||
166 | #define WM8580_PWRDN2_PLLAPD 0x002 | ||
167 | #define WM8580_PWRDN2_PLLBPD 0x004 | ||
168 | #define WM8580_PWRDN2_SPDIFPD 0x008 | ||
169 | #define WM8580_PWRDN2_SPDIFTXD 0x010 | ||
170 | #define WM8580_PWRDN2_SPDIFRXD 0x020 | ||
171 | |||
172 | #define WM8580_DAC_CONTROL5_MUTEALL 0x10 | ||
173 | |||
174 | /* | ||
175 | * wm8580 register cache | ||
176 | * We can't read the WM8580 register space when we | ||
177 | * are using 2 wire for device control, so we cache them instead. | ||
178 | */ | ||
179 | static const u16 wm8580_reg[] = { | ||
180 | 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ | ||
181 | 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ | ||
182 | 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/ | ||
183 | 0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ | ||
184 | 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ | ||
185 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ | ||
186 | 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/ | ||
187 | 0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/ | ||
188 | 0x0000, 0x0000, 0x0031, 0x000b, /*R35*/ | ||
189 | 0x0039, 0x0000, 0x0010, 0x0032, /*R39*/ | ||
190 | 0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/ | ||
191 | 0x0000, 0x0000, 0x0000, 0x0000, /*R47*/ | ||
192 | 0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/ | ||
193 | 0x0000, 0x0000 /*R53*/ | ||
194 | }; | ||
195 | |||
196 | /* | ||
197 | * read wm8580 register cache | ||
198 | */ | ||
199 | static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, | ||
200 | unsigned int reg) | ||
201 | { | ||
202 | u16 *cache = codec->reg_cache; | ||
203 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | ||
204 | return cache[reg]; | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * write wm8580 register cache | ||
209 | */ | ||
210 | static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec, | ||
211 | unsigned int reg, unsigned int value) | ||
212 | { | ||
213 | u16 *cache = codec->reg_cache; | ||
214 | |||
215 | cache[reg] = value; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * write to the WM8580 register space | ||
220 | */ | ||
221 | static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, | ||
222 | unsigned int value) | ||
223 | { | ||
224 | u8 data[2]; | ||
225 | |||
226 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | ||
227 | |||
228 | /* Registers are 9 bits wide */ | ||
229 | value &= 0x1ff; | ||
230 | |||
231 | switch (reg) { | ||
232 | case WM8580_RESET: | ||
233 | /* Uncached */ | ||
234 | break; | ||
235 | default: | ||
236 | if (value == wm8580_read_reg_cache(codec, reg)) | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* data is | ||
241 | * D15..D9 WM8580 register offset | ||
242 | * D8...D0 register data | ||
243 | */ | ||
244 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
245 | data[1] = value & 0x00ff; | ||
246 | |||
247 | wm8580_write_reg_cache(codec, reg, value); | ||
248 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
249 | return 0; | ||
250 | else | ||
251 | return -EIO; | ||
252 | } | ||
253 | |||
254 | static inline unsigned int wm8580_read(struct snd_soc_codec *codec, | ||
255 | unsigned int reg) | ||
256 | { | ||
257 | switch (reg) { | ||
258 | default: | ||
259 | return wm8580_read_reg_cache(codec, reg); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | ||
264 | |||
265 | static int wm8580_out_vu(struct snd_kcontrol *kcontrol, | ||
266 | struct snd_ctl_elem_value *ucontrol) | ||
267 | { | ||
268 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
269 | int reg = kcontrol->private_value & 0xff; | ||
270 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | ||
271 | int ret; | ||
272 | u16 val; | ||
273 | |||
274 | /* Clear the register cache so we write without VU set */ | ||
275 | wm8580_write_reg_cache(codec, reg, 0); | ||
276 | wm8580_write_reg_cache(codec, reg2, 0); | ||
277 | |||
278 | ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); | ||
279 | if (ret < 0) | ||
280 | return ret; | ||
281 | |||
282 | /* Now write again with the volume update bit set */ | ||
283 | val = wm8580_read_reg_cache(codec, reg); | ||
284 | wm8580_write(codec, reg, val | 0x0100); | ||
285 | |||
286 | val = wm8580_read_reg_cache(codec, reg2); | ||
287 | wm8580_write(codec, reg2, val | 0x0100); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | #define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \ | ||
293 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
294 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
295 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
296 | .tlv.p = (tlv_array), \ | ||
297 | .info = snd_soc_info_volsw_2r, \ | ||
298 | .get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \ | ||
299 | .private_value = (reg_left) | ((shift) << 8) | \ | ||
300 | ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) } | ||
301 | |||
302 | static const struct snd_kcontrol_new wm8580_snd_controls[] = { | ||
303 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume", | ||
304 | WM8580_DIGITAL_ATTENUATION_DACL1, | ||
305 | WM8580_DIGITAL_ATTENUATION_DACR1, | ||
306 | 0, 0xff, 0, dac_tlv), | ||
307 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume", | ||
308 | WM8580_DIGITAL_ATTENUATION_DACL2, | ||
309 | WM8580_DIGITAL_ATTENUATION_DACR2, | ||
310 | 0, 0xff, 0, dac_tlv), | ||
311 | SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume", | ||
312 | WM8580_DIGITAL_ATTENUATION_DACL3, | ||
313 | WM8580_DIGITAL_ATTENUATION_DACR3, | ||
314 | 0, 0xff, 0, dac_tlv), | ||
315 | |||
316 | SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0), | ||
317 | SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0), | ||
318 | SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0), | ||
319 | |||
320 | SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4, 0, 1, 1, 0), | ||
321 | SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4, 2, 3, 1, 0), | ||
322 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), | ||
323 | |||
324 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), | ||
325 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0), | ||
326 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0), | ||
327 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0), | ||
328 | |||
329 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | ||
330 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | ||
331 | }; | ||
332 | |||
333 | /* Add non-DAPM controls */ | ||
334 | static int wm8580_add_controls(struct snd_soc_codec *codec) | ||
335 | { | ||
336 | int err, i; | ||
337 | |||
338 | for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) { | ||
339 | err = snd_ctl_add(codec->card, | ||
340 | snd_soc_cnew(&wm8580_snd_controls[i], | ||
341 | codec, NULL)); | ||
342 | if (err < 0) | ||
343 | return err; | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | ||
348 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), | ||
349 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), | ||
350 | SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1), | ||
351 | |||
352 | SND_SOC_DAPM_OUTPUT("VOUT1L"), | ||
353 | SND_SOC_DAPM_OUTPUT("VOUT1R"), | ||
354 | SND_SOC_DAPM_OUTPUT("VOUT2L"), | ||
355 | SND_SOC_DAPM_OUTPUT("VOUT2R"), | ||
356 | SND_SOC_DAPM_OUTPUT("VOUT3L"), | ||
357 | SND_SOC_DAPM_OUTPUT("VOUT3R"), | ||
358 | |||
359 | SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1), | ||
360 | |||
361 | SND_SOC_DAPM_INPUT("AINL"), | ||
362 | SND_SOC_DAPM_INPUT("AINR"), | ||
363 | }; | ||
364 | |||
365 | static const struct snd_soc_dapm_route audio_map[] = { | ||
366 | { "VOUT1L", NULL, "DAC1" }, | ||
367 | { "VOUT1R", NULL, "DAC1" }, | ||
368 | |||
369 | { "VOUT2L", NULL, "DAC2" }, | ||
370 | { "VOUT2R", NULL, "DAC2" }, | ||
371 | |||
372 | { "VOUT3L", NULL, "DAC3" }, | ||
373 | { "VOUT3R", NULL, "DAC3" }, | ||
374 | |||
375 | { "ADC", NULL, "AINL" }, | ||
376 | { "ADC", NULL, "AINR" }, | ||
377 | }; | ||
378 | |||
379 | static int wm8580_add_widgets(struct snd_soc_codec *codec) | ||
380 | { | ||
381 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets, | ||
382 | ARRAY_SIZE(wm8580_dapm_widgets)); | ||
383 | |||
384 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
385 | |||
386 | snd_soc_dapm_new_widgets(codec); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /* PLL divisors */ | ||
391 | struct _pll_div { | ||
392 | u32 prescale:1; | ||
393 | u32 postscale:1; | ||
394 | u32 freqmode:2; | ||
395 | u32 n:4; | ||
396 | u32 k:24; | ||
397 | }; | ||
398 | |||
399 | /* The size in bits of the pll divide */ | ||
400 | #define FIXED_PLL_SIZE (1 << 22) | ||
401 | |||
402 | /* PLL rate to output rate divisions */ | ||
403 | static struct { | ||
404 | unsigned int div; | ||
405 | unsigned int freqmode; | ||
406 | unsigned int postscale; | ||
407 | } post_table[] = { | ||
408 | { 2, 0, 0 }, | ||
409 | { 4, 0, 1 }, | ||
410 | { 4, 1, 0 }, | ||
411 | { 8, 1, 1 }, | ||
412 | { 8, 2, 0 }, | ||
413 | { 16, 2, 1 }, | ||
414 | { 12, 3, 0 }, | ||
415 | { 24, 3, 1 } | ||
416 | }; | ||
417 | |||
418 | static int pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
419 | unsigned int source) | ||
420 | { | ||
421 | u64 Kpart; | ||
422 | unsigned int K, Ndiv, Nmod; | ||
423 | int i; | ||
424 | |||
425 | pr_debug("wm8580: PLL %dHz->%dHz\n", source, target); | ||
426 | |||
427 | /* Scale the output frequency up; the PLL should run in the | ||
428 | * region of 90-100MHz. | ||
429 | */ | ||
430 | for (i = 0; i < ARRAY_SIZE(post_table); i++) { | ||
431 | if (target * post_table[i].div >= 90000000 && | ||
432 | target * post_table[i].div <= 100000000) { | ||
433 | pll_div->freqmode = post_table[i].freqmode; | ||
434 | pll_div->postscale = post_table[i].postscale; | ||
435 | target *= post_table[i].div; | ||
436 | break; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | if (i == ARRAY_SIZE(post_table)) { | ||
441 | printk(KERN_ERR "wm8580: Unable to scale output frequency " | ||
442 | "%u\n", target); | ||
443 | return -EINVAL; | ||
444 | } | ||
445 | |||
446 | Ndiv = target / source; | ||
447 | |||
448 | if (Ndiv < 5) { | ||
449 | source /= 2; | ||
450 | pll_div->prescale = 1; | ||
451 | Ndiv = target / source; | ||
452 | } else | ||
453 | pll_div->prescale = 0; | ||
454 | |||
455 | if ((Ndiv < 5) || (Ndiv > 13)) { | ||
456 | printk(KERN_ERR | ||
457 | "WM8580 N=%d outside supported range\n", Ndiv); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | pll_div->n = Ndiv; | ||
462 | Nmod = target % source; | ||
463 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
464 | |||
465 | do_div(Kpart, source); | ||
466 | |||
467 | K = Kpart & 0xFFFFFFFF; | ||
468 | |||
469 | pll_div->k = K; | ||
470 | |||
471 | pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n", | ||
472 | pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode, | ||
473 | pll_div->postscale); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
479 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
480 | { | ||
481 | int offset; | ||
482 | struct snd_soc_codec *codec = codec_dai->codec; | ||
483 | struct wm8580_priv *wm8580 = codec->private_data; | ||
484 | struct pll_state *state; | ||
485 | struct _pll_div pll_div; | ||
486 | unsigned int reg; | ||
487 | unsigned int pwr_mask; | ||
488 | int ret; | ||
489 | |||
490 | /* GCC isn't able to work out the ifs below for initialising/using | ||
491 | * pll_div so suppress warnings. | ||
492 | */ | ||
493 | memset(&pll_div, 0, sizeof(pll_div)); | ||
494 | |||
495 | switch (pll_id) { | ||
496 | case WM8580_PLLA: | ||
497 | state = &wm8580->a; | ||
498 | offset = 0; | ||
499 | pwr_mask = WM8580_PWRDN2_PLLAPD; | ||
500 | break; | ||
501 | case WM8580_PLLB: | ||
502 | state = &wm8580->b; | ||
503 | offset = 4; | ||
504 | pwr_mask = WM8580_PWRDN2_PLLBPD; | ||
505 | break; | ||
506 | default: | ||
507 | return -ENODEV; | ||
508 | } | ||
509 | |||
510 | if (freq_in && freq_out) { | ||
511 | ret = pll_factors(&pll_div, freq_out, freq_in); | ||
512 | if (ret != 0) | ||
513 | return ret; | ||
514 | } | ||
515 | |||
516 | state->in = freq_in; | ||
517 | state->out = freq_out; | ||
518 | |||
519 | /* Always disable the PLL - it is not safe to leave it running | ||
520 | * while reprogramming it. | ||
521 | */ | ||
522 | reg = wm8580_read(codec, WM8580_PWRDN2); | ||
523 | wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask); | ||
524 | |||
525 | if (!freq_in || !freq_out) | ||
526 | return 0; | ||
527 | |||
528 | wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); | ||
529 | wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); | ||
530 | wm8580_write(codec, WM8580_PLLA3 + offset, | ||
531 | (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); | ||
532 | |||
533 | reg = wm8580_read(codec, WM8580_PLLA4 + offset); | ||
534 | reg &= ~0x3f; | ||
535 | reg |= pll_div.prescale | pll_div.postscale << 1 | | ||
536 | pll_div.freqmode << 4; | ||
537 | |||
538 | wm8580_write(codec, WM8580_PLLA4 + offset, reg); | ||
539 | |||
540 | /* All done, turn it on */ | ||
541 | reg = wm8580_read(codec, WM8580_PWRDN2); | ||
542 | wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Set PCM DAI bit size and sample rate. | ||
549 | */ | ||
550 | static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, | ||
551 | struct snd_pcm_hw_params *params) | ||
552 | { | ||
553 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
554 | struct snd_soc_dai_link *dai = rtd->dai; | ||
555 | struct snd_soc_device *socdev = rtd->socdev; | ||
556 | struct snd_soc_codec *codec = socdev->codec; | ||
557 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); | ||
558 | |||
559 | paifb &= ~WM8580_AIF_LENGTH_MASK; | ||
560 | /* bit size */ | ||
561 | switch (params_format(params)) { | ||
562 | case SNDRV_PCM_FORMAT_S16_LE: | ||
563 | break; | ||
564 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
565 | paifb |= WM8580_AIF_LENGTH_20; | ||
566 | break; | ||
567 | case SNDRV_PCM_FORMAT_S24_LE: | ||
568 | paifb |= WM8580_AIF_LENGTH_24; | ||
569 | break; | ||
570 | case SNDRV_PCM_FORMAT_S32_LE: | ||
571 | paifb |= WM8580_AIF_LENGTH_24; | ||
572 | break; | ||
573 | default: | ||
574 | return -EINVAL; | ||
575 | } | ||
576 | |||
577 | wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, | ||
582 | unsigned int fmt) | ||
583 | { | ||
584 | struct snd_soc_codec *codec = codec_dai->codec; | ||
585 | unsigned int aifa; | ||
586 | unsigned int aifb; | ||
587 | int can_invert_lrclk; | ||
588 | |||
589 | aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id); | ||
590 | aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id); | ||
591 | |||
592 | aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); | ||
593 | |||
594 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
595 | case SND_SOC_DAIFMT_CBS_CFS: | ||
596 | aifa &= ~WM8580_AIF_MS; | ||
597 | break; | ||
598 | case SND_SOC_DAIFMT_CBM_CFM: | ||
599 | aifa |= WM8580_AIF_MS; | ||
600 | break; | ||
601 | default: | ||
602 | return -EINVAL; | ||
603 | } | ||
604 | |||
605 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
606 | case SND_SOC_DAIFMT_I2S: | ||
607 | can_invert_lrclk = 1; | ||
608 | aifb |= WM8580_AIF_FMT_I2S; | ||
609 | break; | ||
610 | case SND_SOC_DAIFMT_RIGHT_J: | ||
611 | can_invert_lrclk = 1; | ||
612 | aifb |= WM8580_AIF_FMT_RIGHTJ; | ||
613 | break; | ||
614 | case SND_SOC_DAIFMT_LEFT_J: | ||
615 | can_invert_lrclk = 1; | ||
616 | aifb |= WM8580_AIF_FMT_LEFTJ; | ||
617 | break; | ||
618 | case SND_SOC_DAIFMT_DSP_A: | ||
619 | can_invert_lrclk = 0; | ||
620 | aifb |= WM8580_AIF_FMT_DSP; | ||
621 | break; | ||
622 | case SND_SOC_DAIFMT_DSP_B: | ||
623 | can_invert_lrclk = 0; | ||
624 | aifb |= WM8580_AIF_FMT_DSP; | ||
625 | aifb |= WM8580_AIF_LRP; | ||
626 | break; | ||
627 | default: | ||
628 | return -EINVAL; | ||
629 | } | ||
630 | |||
631 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
632 | case SND_SOC_DAIFMT_NB_NF: | ||
633 | break; | ||
634 | |||
635 | case SND_SOC_DAIFMT_IB_IF: | ||
636 | if (!can_invert_lrclk) | ||
637 | return -EINVAL; | ||
638 | aifb |= WM8580_AIF_BCP; | ||
639 | aifb |= WM8580_AIF_LRP; | ||
640 | break; | ||
641 | |||
642 | case SND_SOC_DAIFMT_IB_NF: | ||
643 | aifb |= WM8580_AIF_BCP; | ||
644 | break; | ||
645 | |||
646 | case SND_SOC_DAIFMT_NB_IF: | ||
647 | if (!can_invert_lrclk) | ||
648 | return -EINVAL; | ||
649 | aifb |= WM8580_AIF_LRP; | ||
650 | break; | ||
651 | |||
652 | default: | ||
653 | return -EINVAL; | ||
654 | } | ||
655 | |||
656 | wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); | ||
657 | wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
663 | int div_id, int div) | ||
664 | { | ||
665 | struct snd_soc_codec *codec = codec_dai->codec; | ||
666 | unsigned int reg; | ||
667 | |||
668 | switch (div_id) { | ||
669 | case WM8580_MCLK: | ||
670 | reg = wm8580_read(codec, WM8580_PLLB4); | ||
671 | reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; | ||
672 | |||
673 | switch (div) { | ||
674 | case WM8580_CLKSRC_MCLK: | ||
675 | /* Input */ | ||
676 | break; | ||
677 | |||
678 | case WM8580_CLKSRC_PLLA: | ||
679 | reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA; | ||
680 | break; | ||
681 | case WM8580_CLKSRC_PLLB: | ||
682 | reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB; | ||
683 | break; | ||
684 | |||
685 | case WM8580_CLKSRC_OSC: | ||
686 | reg |= WM8580_PLLB4_MCLKOUTSRC_OSC; | ||
687 | break; | ||
688 | |||
689 | default: | ||
690 | return -EINVAL; | ||
691 | } | ||
692 | wm8580_write(codec, WM8580_PLLB4, reg); | ||
693 | break; | ||
694 | |||
695 | case WM8580_DAC_CLKSEL: | ||
696 | reg = wm8580_read(codec, WM8580_CLKSEL); | ||
697 | reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; | ||
698 | |||
699 | switch (div) { | ||
700 | case WM8580_CLKSRC_MCLK: | ||
701 | break; | ||
702 | |||
703 | case WM8580_CLKSRC_PLLA: | ||
704 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA; | ||
705 | break; | ||
706 | |||
707 | case WM8580_CLKSRC_PLLB: | ||
708 | reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB; | ||
709 | break; | ||
710 | |||
711 | default: | ||
712 | return -EINVAL; | ||
713 | } | ||
714 | wm8580_write(codec, WM8580_CLKSEL, reg); | ||
715 | break; | ||
716 | |||
717 | case WM8580_CLKOUTSRC: | ||
718 | reg = wm8580_read(codec, WM8580_PLLB4); | ||
719 | reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; | ||
720 | |||
721 | switch (div) { | ||
722 | case WM8580_CLKSRC_NONE: | ||
723 | break; | ||
724 | |||
725 | case WM8580_CLKSRC_PLLA: | ||
726 | reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK; | ||
727 | break; | ||
728 | |||
729 | case WM8580_CLKSRC_PLLB: | ||
730 | reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK; | ||
731 | break; | ||
732 | |||
733 | case WM8580_CLKSRC_OSC: | ||
734 | reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK; | ||
735 | break; | ||
736 | |||
737 | default: | ||
738 | return -EINVAL; | ||
739 | } | ||
740 | wm8580_write(codec, WM8580_PLLB4, reg); | ||
741 | break; | ||
742 | |||
743 | default: | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
751 | { | ||
752 | struct snd_soc_codec *codec = codec_dai->codec; | ||
753 | unsigned int reg; | ||
754 | |||
755 | reg = wm8580_read(codec, WM8580_DAC_CONTROL5); | ||
756 | |||
757 | if (mute) | ||
758 | reg |= WM8580_DAC_CONTROL5_MUTEALL; | ||
759 | else | ||
760 | reg &= ~WM8580_DAC_CONTROL5_MUTEALL; | ||
761 | |||
762 | wm8580_write(codec, WM8580_DAC_CONTROL5, reg); | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | static int wm8580_set_bias_level(struct snd_soc_codec *codec, | ||
768 | enum snd_soc_bias_level level) | ||
769 | { | ||
770 | u16 reg; | ||
771 | switch (level) { | ||
772 | case SND_SOC_BIAS_ON: | ||
773 | case SND_SOC_BIAS_PREPARE: | ||
774 | case SND_SOC_BIAS_STANDBY: | ||
775 | break; | ||
776 | case SND_SOC_BIAS_OFF: | ||
777 | reg = wm8580_read(codec, WM8580_PWRDN1); | ||
778 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | ||
779 | break; | ||
780 | } | ||
781 | codec->bias_level = level; | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
786 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
787 | |||
788 | struct snd_soc_dai wm8580_dai[] = { | ||
789 | { | ||
790 | .name = "WM8580 PAIFRX", | ||
791 | .id = 0, | ||
792 | .playback = { | ||
793 | .stream_name = "Playback", | ||
794 | .channels_min = 1, | ||
795 | .channels_max = 6, | ||
796 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
797 | .formats = WM8580_FORMATS, | ||
798 | }, | ||
799 | .ops = { | ||
800 | .hw_params = wm8580_paif_hw_params, | ||
801 | }, | ||
802 | .dai_ops = { | ||
803 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
804 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
805 | .set_pll = wm8580_set_dai_pll, | ||
806 | .digital_mute = wm8580_digital_mute, | ||
807 | }, | ||
808 | }, | ||
809 | { | ||
810 | .name = "WM8580 PAIFTX", | ||
811 | .id = 1, | ||
812 | .capture = { | ||
813 | .stream_name = "Capture", | ||
814 | .channels_min = 2, | ||
815 | .channels_max = 2, | ||
816 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
817 | .formats = WM8580_FORMATS, | ||
818 | }, | ||
819 | .ops = { | ||
820 | .hw_params = wm8580_paif_hw_params, | ||
821 | }, | ||
822 | .dai_ops = { | ||
823 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
824 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
825 | .set_pll = wm8580_set_dai_pll, | ||
826 | }, | ||
827 | }, | ||
828 | }; | ||
829 | EXPORT_SYMBOL_GPL(wm8580_dai); | ||
830 | |||
831 | /* | ||
832 | * initialise the WM8580 driver | ||
833 | * register the mixer and dsp interfaces with the kernel | ||
834 | */ | ||
835 | static int wm8580_init(struct snd_soc_device *socdev) | ||
836 | { | ||
837 | struct snd_soc_codec *codec = socdev->codec; | ||
838 | int ret = 0; | ||
839 | |||
840 | codec->name = "WM8580"; | ||
841 | codec->owner = THIS_MODULE; | ||
842 | codec->read = wm8580_read_reg_cache; | ||
843 | codec->write = wm8580_write; | ||
844 | codec->set_bias_level = wm8580_set_bias_level; | ||
845 | codec->dai = wm8580_dai; | ||
846 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
847 | codec->reg_cache_size = ARRAY_SIZE(wm8580_reg); | ||
848 | codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg), | ||
849 | GFP_KERNEL); | ||
850 | |||
851 | if (codec->reg_cache == NULL) | ||
852 | return -ENOMEM; | ||
853 | |||
854 | /* Get the codec into a known state */ | ||
855 | wm8580_write(codec, WM8580_RESET, 0); | ||
856 | |||
857 | /* Power up and get individual control of the DACs */ | ||
858 | wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) & | ||
859 | ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD)); | ||
860 | |||
861 | /* Make VMID high impedence */ | ||
862 | wm8580_write(codec, WM8580_ADC_CONTROL1, | ||
863 | wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100); | ||
864 | |||
865 | /* register pcms */ | ||
866 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, | ||
867 | SNDRV_DEFAULT_STR1); | ||
868 | if (ret < 0) { | ||
869 | printk(KERN_ERR "wm8580: failed to create pcms\n"); | ||
870 | goto pcm_err; | ||
871 | } | ||
872 | |||
873 | wm8580_add_controls(codec); | ||
874 | wm8580_add_widgets(codec); | ||
875 | |||
876 | ret = snd_soc_register_card(socdev); | ||
877 | if (ret < 0) { | ||
878 | printk(KERN_ERR "wm8580: failed to register card\n"); | ||
879 | goto card_err; | ||
880 | } | ||
881 | return ret; | ||
882 | |||
883 | card_err: | ||
884 | snd_soc_free_pcms(socdev); | ||
885 | snd_soc_dapm_free(socdev); | ||
886 | pcm_err: | ||
887 | kfree(codec->reg_cache); | ||
888 | return ret; | ||
889 | } | ||
890 | |||
891 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
892 | around */ | ||
893 | static struct snd_soc_device *wm8580_socdev; | ||
894 | |||
895 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
896 | |||
897 | /* | ||
898 | * WM8580 2 wire address is determined by GPIO5 | ||
899 | * state during powerup. | ||
900 | * low = 0x1a | ||
901 | * high = 0x1b | ||
902 | */ | ||
903 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
904 | |||
905 | /* Magic definition of all other variables and things */ | ||
906 | I2C_CLIENT_INSMOD; | ||
907 | |||
908 | static struct i2c_driver wm8580_i2c_driver; | ||
909 | static struct i2c_client client_template; | ||
910 | |||
911 | static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
912 | { | ||
913 | struct snd_soc_device *socdev = wm8580_socdev; | ||
914 | struct wm8580_setup_data *setup = socdev->codec_data; | ||
915 | struct snd_soc_codec *codec = socdev->codec; | ||
916 | struct i2c_client *i2c; | ||
917 | int ret; | ||
918 | |||
919 | if (addr != setup->i2c_address) | ||
920 | return -ENODEV; | ||
921 | |||
922 | client_template.adapter = adap; | ||
923 | client_template.addr = addr; | ||
924 | |||
925 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
926 | if (i2c == NULL) { | ||
927 | kfree(codec); | ||
928 | return -ENOMEM; | ||
929 | } | ||
930 | i2c_set_clientdata(i2c, codec); | ||
931 | codec->control_data = i2c; | ||
932 | |||
933 | ret = i2c_attach_client(i2c); | ||
934 | if (ret < 0) { | ||
935 | dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); | ||
936 | goto err; | ||
937 | } | ||
938 | |||
939 | ret = wm8580_init(socdev); | ||
940 | if (ret < 0) { | ||
941 | dev_err(&i2c->dev, "failed to initialise WM8580\n"); | ||
942 | goto err; | ||
943 | } | ||
944 | |||
945 | return ret; | ||
946 | |||
947 | err: | ||
948 | kfree(codec); | ||
949 | kfree(i2c); | ||
950 | return ret; | ||
951 | } | ||
952 | |||
953 | static int wm8580_i2c_detach(struct i2c_client *client) | ||
954 | { | ||
955 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
956 | i2c_detach_client(client); | ||
957 | kfree(codec->reg_cache); | ||
958 | kfree(client); | ||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static int wm8580_i2c_attach(struct i2c_adapter *adap) | ||
963 | { | ||
964 | return i2c_probe(adap, &addr_data, wm8580_codec_probe); | ||
965 | } | ||
966 | |||
967 | /* corgi i2c codec control layer */ | ||
968 | static struct i2c_driver wm8580_i2c_driver = { | ||
969 | .driver = { | ||
970 | .name = "WM8580 I2C Codec", | ||
971 | .owner = THIS_MODULE, | ||
972 | }, | ||
973 | .attach_adapter = wm8580_i2c_attach, | ||
974 | .detach_client = wm8580_i2c_detach, | ||
975 | .command = NULL, | ||
976 | }; | ||
977 | |||
978 | static struct i2c_client client_template = { | ||
979 | .name = "WM8580", | ||
980 | .driver = &wm8580_i2c_driver, | ||
981 | }; | ||
982 | #endif | ||
983 | |||
984 | static int wm8580_probe(struct platform_device *pdev) | ||
985 | { | ||
986 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
987 | struct wm8580_setup_data *setup; | ||
988 | struct snd_soc_codec *codec; | ||
989 | struct wm8580_priv *wm8580; | ||
990 | int ret = 0; | ||
991 | |||
992 | pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION); | ||
993 | |||
994 | setup = socdev->codec_data; | ||
995 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
996 | if (codec == NULL) | ||
997 | return -ENOMEM; | ||
998 | |||
999 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
1000 | if (wm8580 == NULL) { | ||
1001 | kfree(codec); | ||
1002 | return -ENOMEM; | ||
1003 | } | ||
1004 | |||
1005 | codec->private_data = wm8580; | ||
1006 | socdev->codec = codec; | ||
1007 | mutex_init(&codec->mutex); | ||
1008 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1009 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1010 | wm8580_socdev = socdev; | ||
1011 | |||
1012 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1013 | if (setup->i2c_address) { | ||
1014 | normal_i2c[0] = setup->i2c_address; | ||
1015 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1016 | ret = i2c_add_driver(&wm8580_i2c_driver); | ||
1017 | if (ret != 0) | ||
1018 | printk(KERN_ERR "can't add i2c driver"); | ||
1019 | } | ||
1020 | #else | ||
1021 | /* Add other interfaces here */ | ||
1022 | #endif | ||
1023 | return ret; | ||
1024 | } | ||
1025 | |||
1026 | /* power down chip */ | ||
1027 | static int wm8580_remove(struct platform_device *pdev) | ||
1028 | { | ||
1029 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1030 | struct snd_soc_codec *codec = socdev->codec; | ||
1031 | |||
1032 | if (codec->control_data) | ||
1033 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1034 | snd_soc_free_pcms(socdev); | ||
1035 | snd_soc_dapm_free(socdev); | ||
1036 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1037 | i2c_del_driver(&wm8580_i2c_driver); | ||
1038 | #endif | ||
1039 | kfree(codec->private_data); | ||
1040 | kfree(codec); | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
1046 | .probe = wm8580_probe, | ||
1047 | .remove = wm8580_remove, | ||
1048 | }; | ||
1049 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
1050 | |||
1051 | MODULE_DESCRIPTION("ASoC WM8580 driver"); | ||
1052 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
1053 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h new file mode 100644 index 000000000000..589ddaba21d7 --- /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 9402fcaf04fa..7f8a7e36b33e 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> |
@@ -28,7 +29,6 @@ | |||
28 | 29 | ||
29 | #include "wm8731.h" | 30 | #include "wm8731.h" |
30 | 31 | ||
31 | #define AUDIO_NAME "wm8731" | ||
32 | #define WM8731_VERSION "0.13" | 32 | #define WM8731_VERSION "0.13" |
33 | 33 | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
@@ -570,88 +570,144 @@ static struct snd_soc_device *wm8731_socdev; | |||
570 | * low = 0x1a | 570 | * low = 0x1a |
571 | * high = 0x1b | 571 | * high = 0x1b |
572 | */ | 572 | */ |
573 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
574 | 573 | ||
575 | /* Magic definition of all other variables and things */ | 574 | static int wm8731_i2c_probe(struct i2c_client *i2c, |
576 | I2C_CLIENT_INSMOD; | 575 | 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 | { | 576 | { |
586 | struct snd_soc_device *socdev = wm8731_socdev; | 577 | struct snd_soc_device *socdev = wm8731_socdev; |
587 | struct wm8731_setup_data *setup = socdev->codec_data; | ||
588 | struct snd_soc_codec *codec = socdev->codec; | 578 | struct snd_soc_codec *codec = socdev->codec; |
589 | struct i2c_client *i2c; | ||
590 | int ret; | 579 | int ret; |
591 | 580 | ||
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); | 581 | i2c_set_clientdata(i2c, codec); |
603 | codec->control_data = i2c; | 582 | codec->control_data = i2c; |
604 | 583 | ||
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); | 584 | ret = wm8731_init(socdev); |
612 | if (ret < 0) { | 585 | if (ret < 0) |
613 | pr_err("failed to initialise WM8731\n"); | 586 | pr_err("failed to initialise WM8731\n"); |
614 | goto err; | ||
615 | } | ||
616 | return ret; | ||
617 | 587 | ||
618 | err: | ||
619 | kfree(i2c); | ||
620 | return ret; | 588 | return ret; |
621 | } | 589 | } |
622 | 590 | ||
623 | static int wm8731_i2c_detach(struct i2c_client *client) | 591 | static int wm8731_i2c_remove(struct i2c_client *client) |
624 | { | 592 | { |
625 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 593 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
626 | i2c_detach_client(client); | ||
627 | kfree(codec->reg_cache); | 594 | kfree(codec->reg_cache); |
628 | kfree(client); | ||
629 | return 0; | 595 | return 0; |
630 | } | 596 | } |
631 | 597 | ||
632 | static int wm8731_i2c_attach(struct i2c_adapter *adap) | 598 | static const struct i2c_device_id wm8731_i2c_id[] = { |
633 | { | 599 | { "wm8731", 0 }, |
634 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); | 600 | { } |
635 | } | 601 | }; |
602 | MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); | ||
636 | 603 | ||
637 | /* corgi i2c codec control layer */ | ||
638 | static struct i2c_driver wm8731_i2c_driver = { | 604 | static struct i2c_driver wm8731_i2c_driver = { |
639 | .driver = { | 605 | .driver = { |
640 | .name = "WM8731 I2C Codec", | 606 | .name = "WM8731 I2C Codec", |
641 | .owner = THIS_MODULE, | 607 | .owner = THIS_MODULE, |
642 | }, | 608 | }, |
643 | .id = I2C_DRIVERID_WM8731, | 609 | .probe = wm8731_i2c_probe, |
644 | .attach_adapter = wm8731_i2c_attach, | 610 | .remove = wm8731_i2c_remove, |
645 | .detach_client = wm8731_i2c_detach, | 611 | .id_table = wm8731_i2c_id, |
646 | .command = NULL, | ||
647 | }; | 612 | }; |
648 | 613 | ||
649 | static struct i2c_client client_template = { | 614 | static int wm8731_add_i2c_device(struct platform_device *pdev, |
650 | .name = "WM8731", | 615 | const struct wm8731_setup_data *setup) |
651 | .driver = &wm8731_i2c_driver, | 616 | { |
652 | }; | 617 | struct i2c_board_info info; |
618 | struct i2c_adapter *adapter; | ||
619 | struct i2c_client *client; | ||
620 | int ret; | ||
621 | |||
622 | ret = i2c_add_driver(&wm8731_i2c_driver); | ||
623 | if (ret != 0) { | ||
624 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
625 | return ret; | ||
626 | } | ||
627 | |||
628 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
629 | info.addr = setup->i2c_address; | ||
630 | strlcpy(info.type, "wm8731", I2C_NAME_SIZE); | ||
631 | |||
632 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
633 | if (!adapter) { | ||
634 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
635 | setup->i2c_bus); | ||
636 | goto err_driver; | ||
637 | } | ||
638 | |||
639 | client = i2c_new_device(adapter, &info); | ||
640 | i2c_put_adapter(adapter); | ||
641 | if (!client) { | ||
642 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
643 | (unsigned int)info.addr); | ||
644 | goto err_driver; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | |||
649 | err_driver: | ||
650 | i2c_del_driver(&wm8731_i2c_driver); | ||
651 | return -ENODEV; | ||
652 | } | ||
653 | #endif | 653 | #endif |
654 | 654 | ||
655 | #if defined(CONFIG_SPI_MASTER) | ||
656 | static int __devinit wm8731_spi_probe(struct spi_device *spi) | ||
657 | { | ||
658 | struct snd_soc_device *socdev = wm8731_socdev; | ||
659 | struct snd_soc_codec *codec = socdev->codec; | ||
660 | int ret; | ||
661 | |||
662 | codec->control_data = spi; | ||
663 | |||
664 | ret = wm8731_init(socdev); | ||
665 | if (ret < 0) | ||
666 | dev_err(&spi->dev, "failed to initialise WM8731\n"); | ||
667 | |||
668 | return ret; | ||
669 | } | ||
670 | |||
671 | static int __devexit wm8731_spi_remove(struct spi_device *spi) | ||
672 | { | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static struct spi_driver wm8731_spi_driver = { | ||
677 | .driver = { | ||
678 | .name = "wm8731", | ||
679 | .bus = &spi_bus_type, | ||
680 | .owner = THIS_MODULE, | ||
681 | }, | ||
682 | .probe = wm8731_spi_probe, | ||
683 | .remove = __devexit_p(wm8731_spi_remove), | ||
684 | }; | ||
685 | |||
686 | static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) | ||
687 | { | ||
688 | struct spi_transfer t; | ||
689 | struct spi_message m; | ||
690 | u8 msg[2]; | ||
691 | |||
692 | if (len <= 0) | ||
693 | return 0; | ||
694 | |||
695 | msg[0] = data[0]; | ||
696 | msg[1] = data[1]; | ||
697 | |||
698 | spi_message_init(&m); | ||
699 | memset(&t, 0, (sizeof t)); | ||
700 | |||
701 | t.tx_buf = &msg[0]; | ||
702 | t.len = len; | ||
703 | |||
704 | spi_message_add_tail(&t, &m); | ||
705 | spi_sync(spi, &m); | ||
706 | |||
707 | return len; | ||
708 | } | ||
709 | #endif /* CONFIG_SPI_MASTER */ | ||
710 | |||
655 | static int wm8731_probe(struct platform_device *pdev) | 711 | static int wm8731_probe(struct platform_device *pdev) |
656 | { | 712 | { |
657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 713 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -680,16 +736,21 @@ static int wm8731_probe(struct platform_device *pdev) | |||
680 | INIT_LIST_HEAD(&codec->dapm_paths); | 736 | INIT_LIST_HEAD(&codec->dapm_paths); |
681 | 737 | ||
682 | wm8731_socdev = socdev; | 738 | wm8731_socdev = socdev; |
739 | ret = -ENODEV; | ||
740 | |||
683 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 741 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
684 | if (setup->i2c_address) { | 742 | if (setup->i2c_address) { |
685 | normal_i2c[0] = setup->i2c_address; | ||
686 | codec->hw_write = (hw_write_t)i2c_master_send; | 743 | codec->hw_write = (hw_write_t)i2c_master_send; |
687 | ret = i2c_add_driver(&wm8731_i2c_driver); | 744 | ret = wm8731_add_i2c_device(pdev, setup); |
745 | } | ||
746 | #endif | ||
747 | #if defined(CONFIG_SPI_MASTER) | ||
748 | if (setup->spi) { | ||
749 | codec->hw_write = (hw_write_t)wm8731_spi_write; | ||
750 | ret = spi_register_driver(&wm8731_spi_driver); | ||
688 | if (ret != 0) | 751 | if (ret != 0) |
689 | printk(KERN_ERR "can't add i2c driver"); | 752 | printk(KERN_ERR "can't add spi driver"); |
690 | } | 753 | } |
691 | #else | ||
692 | /* Add other interfaces here */ | ||
693 | #endif | 754 | #endif |
694 | 755 | ||
695 | if (ret != 0) { | 756 | if (ret != 0) { |
@@ -711,8 +772,12 @@ static int wm8731_remove(struct platform_device *pdev) | |||
711 | snd_soc_free_pcms(socdev); | 772 | snd_soc_free_pcms(socdev); |
712 | snd_soc_dapm_free(socdev); | 773 | snd_soc_dapm_free(socdev); |
713 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 774 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
775 | i2c_unregister_device(codec->control_data); | ||
714 | i2c_del_driver(&wm8731_i2c_driver); | 776 | i2c_del_driver(&wm8731_i2c_driver); |
715 | #endif | 777 | #endif |
778 | #if defined(CONFIG_SPI_MASTER) | ||
779 | spi_unregister_driver(&wm8731_spi_driver); | ||
780 | #endif | ||
716 | kfree(codec->private_data); | 781 | kfree(codec->private_data); |
717 | kfree(codec); | 782 | kfree(codec); |
718 | 783 | ||
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 99f2e3c60e33..95190e9c0c14 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 dd1f55404b29..9b7296ee5b08 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> |
@@ -28,7 +29,6 @@ | |||
28 | 29 | ||
29 | #include "wm8750.h" | 30 | #include "wm8750.h" |
30 | 31 | ||
31 | #define AUDIO_NAME "WM8750" | ||
32 | #define WM8750_VERSION "0.12" | 32 | #define WM8750_VERSION "0.12" |
33 | 33 | ||
34 | /* codec private data */ | 34 | /* codec private data */ |
@@ -841,88 +841,147 @@ static struct snd_soc_device *wm8750_socdev; | |||
841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
842 | 842 | ||
843 | /* | 843 | /* |
844 | * WM8731 2 wire address is determined by GPIO5 | 844 | * WM8750 2 wire address is determined by GPIO5 |
845 | * state during powerup. | 845 | * state during powerup. |
846 | * low = 0x1a | 846 | * low = 0x1a |
847 | * high = 0x1b | 847 | * high = 0x1b |
848 | */ | 848 | */ |
849 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
850 | 849 | ||
851 | /* Magic definition of all other variables and things */ | 850 | static int wm8750_i2c_probe(struct i2c_client *i2c, |
852 | I2C_CLIENT_INSMOD; | 851 | 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 | { | 852 | { |
859 | struct snd_soc_device *socdev = wm8750_socdev; | 853 | struct snd_soc_device *socdev = wm8750_socdev; |
860 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
861 | struct snd_soc_codec *codec = socdev->codec; | 854 | struct snd_soc_codec *codec = socdev->codec; |
862 | struct i2c_client *i2c; | ||
863 | int ret; | 855 | int ret; |
864 | 856 | ||
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); | 857 | i2c_set_clientdata(i2c, codec); |
876 | codec->control_data = i2c; | 858 | codec->control_data = i2c; |
877 | 859 | ||
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); | 860 | ret = wm8750_init(socdev); |
885 | if (ret < 0) { | 861 | if (ret < 0) |
886 | pr_err("failed to initialise WM8750\n"); | 862 | pr_err("failed to initialise WM8750\n"); |
887 | goto err; | ||
888 | } | ||
889 | return ret; | ||
890 | 863 | ||
891 | err: | ||
892 | kfree(i2c); | ||
893 | return ret; | 864 | return ret; |
894 | } | 865 | } |
895 | 866 | ||
896 | static int wm8750_i2c_detach(struct i2c_client *client) | 867 | static int wm8750_i2c_remove(struct i2c_client *client) |
897 | { | 868 | { |
898 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 869 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
899 | i2c_detach_client(client); | ||
900 | kfree(codec->reg_cache); | 870 | kfree(codec->reg_cache); |
901 | kfree(client); | ||
902 | return 0; | 871 | return 0; |
903 | } | 872 | } |
904 | 873 | ||
905 | static int wm8750_i2c_attach(struct i2c_adapter *adap) | 874 | static const struct i2c_device_id wm8750_i2c_id[] = { |
906 | { | 875 | { "wm8750", 0 }, |
907 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); | 876 | { } |
908 | } | 877 | }; |
878 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | ||
909 | 879 | ||
910 | /* corgi i2c codec control layer */ | ||
911 | static struct i2c_driver wm8750_i2c_driver = { | 880 | static struct i2c_driver wm8750_i2c_driver = { |
912 | .driver = { | 881 | .driver = { |
913 | .name = "WM8750 I2C Codec", | 882 | .name = "WM8750 I2C Codec", |
914 | .owner = THIS_MODULE, | 883 | .owner = THIS_MODULE, |
915 | }, | 884 | }, |
916 | .id = I2C_DRIVERID_WM8750, | 885 | .probe = wm8750_i2c_probe, |
917 | .attach_adapter = wm8750_i2c_attach, | 886 | .remove = wm8750_i2c_remove, |
918 | .detach_client = wm8750_i2c_detach, | 887 | .id_table = wm8750_i2c_id, |
919 | .command = NULL, | ||
920 | }; | 888 | }; |
921 | 889 | ||
922 | static struct i2c_client client_template = { | 890 | static int wm8750_add_i2c_device(struct platform_device *pdev, |
923 | .name = "WM8750", | 891 | const struct wm8750_setup_data *setup) |
924 | .driver = &wm8750_i2c_driver, | 892 | { |
893 | struct i2c_board_info info; | ||
894 | struct i2c_adapter *adapter; | ||
895 | struct i2c_client *client; | ||
896 | int ret; | ||
897 | |||
898 | ret = i2c_add_driver(&wm8750_i2c_driver); | ||
899 | if (ret != 0) { | ||
900 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
905 | info.addr = setup->i2c_address; | ||
906 | strlcpy(info.type, "wm8750", I2C_NAME_SIZE); | ||
907 | |||
908 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
909 | if (!adapter) { | ||
910 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
911 | setup->i2c_bus); | ||
912 | goto err_driver; | ||
913 | } | ||
914 | |||
915 | client = i2c_new_device(adapter, &info); | ||
916 | i2c_put_adapter(adapter); | ||
917 | if (!client) { | ||
918 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
919 | (unsigned int)info.addr); | ||
920 | goto err_driver; | ||
921 | } | ||
922 | |||
923 | return 0; | ||
924 | |||
925 | err_driver: | ||
926 | i2c_del_driver(&wm8750_i2c_driver); | ||
927 | return -ENODEV; | ||
928 | } | ||
929 | #endif | ||
930 | |||
931 | #if defined(CONFIG_SPI_MASTER) | ||
932 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | ||
933 | { | ||
934 | struct snd_soc_device *socdev = wm8750_socdev; | ||
935 | struct snd_soc_codec *codec = socdev->codec; | ||
936 | int ret; | ||
937 | |||
938 | codec->control_data = spi; | ||
939 | |||
940 | ret = wm8750_init(socdev); | ||
941 | if (ret < 0) | ||
942 | dev_err(&spi->dev, "failed to initialise WM8750\n"); | ||
943 | |||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | static int __devexit wm8750_spi_remove(struct spi_device *spi) | ||
948 | { | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static struct spi_driver wm8750_spi_driver = { | ||
953 | .driver = { | ||
954 | .name = "wm8750", | ||
955 | .bus = &spi_bus_type, | ||
956 | .owner = THIS_MODULE, | ||
957 | }, | ||
958 | .probe = wm8750_spi_probe, | ||
959 | .remove = __devexit_p(wm8750_spi_remove), | ||
925 | }; | 960 | }; |
961 | |||
962 | static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) | ||
963 | { | ||
964 | struct spi_transfer t; | ||
965 | struct spi_message m; | ||
966 | u8 msg[2]; | ||
967 | |||
968 | if (len <= 0) | ||
969 | return 0; | ||
970 | |||
971 | msg[0] = data[0]; | ||
972 | msg[1] = data[1]; | ||
973 | |||
974 | spi_message_init(&m); | ||
975 | memset(&t, 0, (sizeof t)); | ||
976 | |||
977 | t.tx_buf = &msg[0]; | ||
978 | t.len = len; | ||
979 | |||
980 | spi_message_add_tail(&t, &m); | ||
981 | spi_sync(spi, &m); | ||
982 | |||
983 | return len; | ||
984 | } | ||
926 | #endif | 985 | #endif |
927 | 986 | ||
928 | static int wm8750_probe(struct platform_device *pdev) | 987 | static int wm8750_probe(struct platform_device *pdev) |
@@ -931,7 +990,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
931 | struct wm8750_setup_data *setup = socdev->codec_data; | 990 | struct wm8750_setup_data *setup = socdev->codec_data; |
932 | struct snd_soc_codec *codec; | 991 | struct snd_soc_codec *codec; |
933 | struct wm8750_priv *wm8750; | 992 | struct wm8750_priv *wm8750; |
934 | int ret = 0; | 993 | int ret; |
935 | 994 | ||
936 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); | 995 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
937 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 996 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -952,16 +1011,21 @@ static int wm8750_probe(struct platform_device *pdev) | |||
952 | wm8750_socdev = socdev; | 1011 | wm8750_socdev = socdev; |
953 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | 1012 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); |
954 | 1013 | ||
1014 | ret = -ENODEV; | ||
1015 | |||
955 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1016 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
956 | if (setup->i2c_address) { | 1017 | if (setup->i2c_address) { |
957 | normal_i2c[0] = setup->i2c_address; | ||
958 | codec->hw_write = (hw_write_t)i2c_master_send; | 1018 | codec->hw_write = (hw_write_t)i2c_master_send; |
959 | ret = i2c_add_driver(&wm8750_i2c_driver); | 1019 | ret = wm8750_add_i2c_device(pdev, setup); |
1020 | } | ||
1021 | #endif | ||
1022 | #if defined(CONFIG_SPI_MASTER) | ||
1023 | if (setup->spi) { | ||
1024 | codec->hw_write = (hw_write_t)wm8750_spi_write; | ||
1025 | ret = spi_register_driver(&wm8750_spi_driver); | ||
960 | if (ret != 0) | 1026 | if (ret != 0) |
961 | printk(KERN_ERR "can't add i2c driver"); | 1027 | printk(KERN_ERR "can't add spi driver"); |
962 | } | 1028 | } |
963 | #else | ||
964 | /* Add other interfaces here */ | ||
965 | #endif | 1029 | #endif |
966 | 1030 | ||
967 | if (ret != 0) { | 1031 | if (ret != 0) { |
@@ -1002,8 +1066,12 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1002 | snd_soc_free_pcms(socdev); | 1066 | snd_soc_free_pcms(socdev); |
1003 | snd_soc_dapm_free(socdev); | 1067 | snd_soc_dapm_free(socdev); |
1004 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1068 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1069 | i2c_unregister_device(codec->control_data); | ||
1005 | i2c_del_driver(&wm8750_i2c_driver); | 1070 | i2c_del_driver(&wm8750_i2c_driver); |
1006 | #endif | 1071 | #endif |
1072 | #if defined(CONFIG_SPI_MASTER) | ||
1073 | spi_unregister_driver(&wm8750_spi_driver); | ||
1074 | #endif | ||
1007 | kfree(codec->private_data); | 1075 | kfree(codec->private_data); |
1008 | kfree(codec); | 1076 | kfree(codec); |
1009 | 1077 | ||
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index 8ef30e628b21..1dc100e19cfe 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 5761164fe16d..d426eaa22185 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm8753.c -- WM8753 ALSA Soc Audio driver | 2 | * wm8753.c -- WM8753 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * 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 | 8 | * under the terms of the GNU General Public License as published by the |
@@ -40,6 +39,7 @@ | |||
40 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
41 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
42 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/spi/spi.h> | ||
43 | #include <sound/core.h> | 43 | #include <sound/core.h> |
44 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
45 | #include <sound/pcm_params.h> | 45 | #include <sound/pcm_params.h> |
@@ -51,7 +51,6 @@ | |||
51 | 51 | ||
52 | #include "wm8753.h" | 52 | #include "wm8753.h" |
53 | 53 | ||
54 | #define AUDIO_NAME "wm8753" | ||
55 | #define WM8753_VERSION "0.16" | 54 | #define WM8753_VERSION "0.16" |
56 | 55 | ||
57 | static int caps_charge = 2000; | 56 | static int caps_charge = 2000; |
@@ -583,7 +582,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 582 | ||
584 | /* out 4 */ | 583 | /* out 4 */ |
585 | {"Out4 Mux", "VREF", "VREF"}, | 584 | {"Out4 Mux", "VREF", "VREF"}, |
586 | {"Out4 Mux", "Capture ST", "Capture ST Mixer"}, | 585 | {"Out4 Mux", "Capture ST", "Playback Mixer"}, |
587 | {"Out4 Mux", "LOUT2", "LOUT2"}, | 586 | {"Out4 Mux", "LOUT2", "LOUT2"}, |
588 | {"Out 4", NULL, "Out4 Mux"}, | 587 | {"Out 4", NULL, "Out4 Mux"}, |
589 | {"OUT4", NULL, "Out 4"}, | 588 | {"OUT4", NULL, "Out 4"}, |
@@ -607,7 +606,7 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
607 | /* Capture Right Mux */ | 606 | /* Capture Right Mux */ |
608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, | 607 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, |
609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, | 608 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, |
610 | {"Capture Right Mux", "Sidetone", "Capture ST Mixer"}, | 609 | {"Capture Right Mux", "Sidetone", "Playback Mixer"}, |
611 | 610 | ||
612 | /* Mono Capture mixer-mux */ | 611 | /* Mono Capture mixer-mux */ |
613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, | 612 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, |
@@ -1637,86 +1636,145 @@ static struct snd_soc_device *wm8753_socdev; | |||
1637 | * low = 0x1a | 1636 | * low = 0x1a |
1638 | * high = 0x1b | 1637 | * high = 0x1b |
1639 | */ | 1638 | */ |
1640 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1641 | 1639 | ||
1642 | /* Magic definition of all other variables and things */ | 1640 | static int wm8753_i2c_probe(struct i2c_client *i2c, |
1643 | I2C_CLIENT_INSMOD; | 1641 | 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 | { | 1642 | { |
1650 | struct snd_soc_device *socdev = wm8753_socdev; | 1643 | struct snd_soc_device *socdev = wm8753_socdev; |
1651 | struct wm8753_setup_data *setup = socdev->codec_data; | ||
1652 | struct snd_soc_codec *codec = socdev->codec; | 1644 | struct snd_soc_codec *codec = socdev->codec; |
1653 | struct i2c_client *i2c; | ||
1654 | int ret; | 1645 | int ret; |
1655 | 1646 | ||
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); | 1647 | i2c_set_clientdata(i2c, codec); |
1667 | codec->control_data = i2c; | 1648 | codec->control_data = i2c; |
1668 | 1649 | ||
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); | 1650 | ret = wm8753_init(socdev); |
1676 | if (ret < 0) { | 1651 | if (ret < 0) |
1677 | pr_err("failed to initialise WM8753\n"); | 1652 | pr_err("failed to initialise WM8753\n"); |
1678 | goto err; | ||
1679 | } | ||
1680 | |||
1681 | return ret; | ||
1682 | 1653 | ||
1683 | err: | ||
1684 | kfree(i2c); | ||
1685 | return ret; | 1654 | return ret; |
1686 | } | 1655 | } |
1687 | 1656 | ||
1688 | static int wm8753_i2c_detach(struct i2c_client *client) | 1657 | static int wm8753_i2c_remove(struct i2c_client *client) |
1689 | { | 1658 | { |
1690 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1659 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1691 | i2c_detach_client(client); | ||
1692 | kfree(codec->reg_cache); | 1660 | kfree(codec->reg_cache); |
1693 | kfree(client); | ||
1694 | return 0; | 1661 | return 0; |
1695 | } | 1662 | } |
1696 | 1663 | ||
1697 | static int wm8753_i2c_attach(struct i2c_adapter *adap) | 1664 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1698 | { | 1665 | { "wm8753", 0 }, |
1699 | return i2c_probe(adap, &addr_data, wm8753_codec_probe); | 1666 | { } |
1700 | } | 1667 | }; |
1668 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1701 | 1669 | ||
1702 | /* corgi i2c codec control layer */ | ||
1703 | static struct i2c_driver wm8753_i2c_driver = { | 1670 | static struct i2c_driver wm8753_i2c_driver = { |
1704 | .driver = { | 1671 | .driver = { |
1705 | .name = "WM8753 I2C Codec", | 1672 | .name = "WM8753 I2C Codec", |
1706 | .owner = THIS_MODULE, | 1673 | .owner = THIS_MODULE, |
1707 | }, | 1674 | }, |
1708 | .id = I2C_DRIVERID_WM8753, | 1675 | .probe = wm8753_i2c_probe, |
1709 | .attach_adapter = wm8753_i2c_attach, | 1676 | .remove = wm8753_i2c_remove, |
1710 | .detach_client = wm8753_i2c_detach, | 1677 | .id_table = wm8753_i2c_id, |
1711 | .command = NULL, | ||
1712 | }; | 1678 | }; |
1713 | 1679 | ||
1714 | static struct i2c_client client_template = { | 1680 | static int wm8753_add_i2c_device(struct platform_device *pdev, |
1715 | .name = "WM8753", | 1681 | const struct wm8753_setup_data *setup) |
1716 | .driver = &wm8753_i2c_driver, | 1682 | { |
1683 | struct i2c_board_info info; | ||
1684 | struct i2c_adapter *adapter; | ||
1685 | struct i2c_client *client; | ||
1686 | int ret; | ||
1687 | |||
1688 | ret = i2c_add_driver(&wm8753_i2c_driver); | ||
1689 | if (ret != 0) { | ||
1690 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1691 | return ret; | ||
1692 | } | ||
1693 | |||
1694 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1695 | info.addr = setup->i2c_address; | ||
1696 | strlcpy(info.type, "wm8753", I2C_NAME_SIZE); | ||
1697 | |||
1698 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1699 | if (!adapter) { | ||
1700 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1701 | setup->i2c_bus); | ||
1702 | goto err_driver; | ||
1703 | } | ||
1704 | |||
1705 | client = i2c_new_device(adapter, &info); | ||
1706 | i2c_put_adapter(adapter); | ||
1707 | if (!client) { | ||
1708 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1709 | (unsigned int)info.addr); | ||
1710 | goto err_driver; | ||
1711 | } | ||
1712 | |||
1713 | return 0; | ||
1714 | |||
1715 | err_driver: | ||
1716 | i2c_del_driver(&wm8753_i2c_driver); | ||
1717 | return -ENODEV; | ||
1718 | } | ||
1719 | #endif | ||
1720 | |||
1721 | #if defined(CONFIG_SPI_MASTER) | ||
1722 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | ||
1723 | { | ||
1724 | struct snd_soc_device *socdev = wm8753_socdev; | ||
1725 | struct snd_soc_codec *codec = socdev->codec; | ||
1726 | int ret; | ||
1727 | |||
1728 | codec->control_data = spi; | ||
1729 | |||
1730 | ret = wm8753_init(socdev); | ||
1731 | if (ret < 0) | ||
1732 | dev_err(&spi->dev, "failed to initialise WM8753\n"); | ||
1733 | |||
1734 | return ret; | ||
1735 | } | ||
1736 | |||
1737 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | ||
1738 | { | ||
1739 | return 0; | ||
1740 | } | ||
1741 | |||
1742 | static struct spi_driver wm8753_spi_driver = { | ||
1743 | .driver = { | ||
1744 | .name = "wm8753", | ||
1745 | .bus = &spi_bus_type, | ||
1746 | .owner = THIS_MODULE, | ||
1747 | }, | ||
1748 | .probe = wm8753_spi_probe, | ||
1749 | .remove = __devexit_p(wm8753_spi_remove), | ||
1717 | }; | 1750 | }; |
1751 | |||
1752 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | ||
1753 | { | ||
1754 | struct spi_transfer t; | ||
1755 | struct spi_message m; | ||
1756 | u8 msg[2]; | ||
1757 | |||
1758 | if (len <= 0) | ||
1759 | return 0; | ||
1760 | |||
1761 | msg[0] = data[0]; | ||
1762 | msg[1] = data[1]; | ||
1763 | |||
1764 | spi_message_init(&m); | ||
1765 | memset(&t, 0, (sizeof t)); | ||
1766 | |||
1767 | t.tx_buf = &msg[0]; | ||
1768 | t.len = len; | ||
1769 | |||
1770 | spi_message_add_tail(&t, &m); | ||
1771 | spi_sync(spi, &m); | ||
1772 | |||
1773 | return len; | ||
1774 | } | ||
1718 | #endif | 1775 | #endif |
1719 | 1776 | ||
1777 | |||
1720 | static int wm8753_probe(struct platform_device *pdev) | 1778 | static int wm8753_probe(struct platform_device *pdev) |
1721 | { | 1779 | { |
1722 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1780 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -1748,14 +1806,17 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1748 | 1806 | ||
1749 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1750 | if (setup->i2c_address) { | 1808 | if (setup->i2c_address) { |
1751 | normal_i2c[0] = setup->i2c_address; | ||
1752 | codec->hw_write = (hw_write_t)i2c_master_send; | 1809 | codec->hw_write = (hw_write_t)i2c_master_send; |
1753 | ret = i2c_add_driver(&wm8753_i2c_driver); | 1810 | ret = wm8753_add_i2c_device(pdev, setup); |
1811 | } | ||
1812 | #endif | ||
1813 | #if defined(CONFIG_SPI_MASTER) | ||
1814 | if (setup->spi) { | ||
1815 | codec->hw_write = (hw_write_t)wm8753_spi_write; | ||
1816 | ret = spi_register_driver(&wm8753_spi_driver); | ||
1754 | if (ret != 0) | 1817 | if (ret != 0) |
1755 | printk(KERN_ERR "can't add i2c driver"); | 1818 | printk(KERN_ERR "can't add spi driver"); |
1756 | } | 1819 | } |
1757 | #else | ||
1758 | /* Add other interfaces here */ | ||
1759 | #endif | 1820 | #endif |
1760 | 1821 | ||
1761 | if (ret != 0) { | 1822 | if (ret != 0) { |
@@ -1796,8 +1857,12 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1796 | snd_soc_free_pcms(socdev); | 1857 | snd_soc_free_pcms(socdev); |
1797 | snd_soc_dapm_free(socdev); | 1858 | snd_soc_dapm_free(socdev); |
1798 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1859 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1860 | i2c_unregister_device(codec->control_data); | ||
1799 | i2c_del_driver(&wm8753_i2c_driver); | 1861 | i2c_del_driver(&wm8753_i2c_driver); |
1800 | #endif | 1862 | #endif |
1863 | #if defined(CONFIG_SPI_MASTER) | ||
1864 | spi_unregister_driver(&wm8753_spi_driver); | ||
1865 | #endif | ||
1801 | kfree(codec->private_data); | 1866 | kfree(codec->private_data); |
1802 | kfree(codec); | 1867 | kfree(codec); |
1803 | 1868 | ||
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 44f5f1ff0cc7..f55704ce931b 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm8753.h -- audio driver for WM8753 | 2 | * wm8753.h -- audio driver for WM8753 |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * 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 | 8 | * under the terms of the GNU General Public License as published by the |
@@ -79,6 +78,8 @@ | |||
79 | #define WM8753_ADCTL2 0x3f | 78 | #define WM8753_ADCTL2 0x3f |
80 | 79 | ||
81 | struct wm8753_setup_data { | 80 | struct wm8753_setup_data { |
81 | int spi; | ||
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 000000000000..3b326c9b5586 --- /dev/null +++ b/sound/soc/codecs/wm8900.c | |||
@@ -0,0 +1,1541 @@ | |||
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/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/pm.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include <sound/tlv.h> | ||
34 | |||
35 | #include "wm8900.h" | ||
36 | |||
37 | /* WM8900 register space */ | ||
38 | #define WM8900_REG_RESET 0x0 | ||
39 | #define WM8900_REG_ID 0x0 | ||
40 | #define WM8900_REG_POWER1 0x1 | ||
41 | #define WM8900_REG_POWER2 0x2 | ||
42 | #define WM8900_REG_POWER3 0x3 | ||
43 | #define WM8900_REG_AUDIO1 0x4 | ||
44 | #define WM8900_REG_AUDIO2 0x5 | ||
45 | #define WM8900_REG_CLOCKING1 0x6 | ||
46 | #define WM8900_REG_CLOCKING2 0x7 | ||
47 | #define WM8900_REG_AUDIO3 0x8 | ||
48 | #define WM8900_REG_AUDIO4 0x9 | ||
49 | #define WM8900_REG_DACCTRL 0xa | ||
50 | #define WM8900_REG_LDAC_DV 0xb | ||
51 | #define WM8900_REG_RDAC_DV 0xc | ||
52 | #define WM8900_REG_SIDETONE 0xd | ||
53 | #define WM8900_REG_ADCCTRL 0xe | ||
54 | #define WM8900_REG_LADC_DV 0xf | ||
55 | #define WM8900_REG_RADC_DV 0x10 | ||
56 | #define WM8900_REG_GPIO 0x12 | ||
57 | #define WM8900_REG_INCTL 0x15 | ||
58 | #define WM8900_REG_LINVOL 0x16 | ||
59 | #define WM8900_REG_RINVOL 0x17 | ||
60 | #define WM8900_REG_INBOOSTMIX1 0x18 | ||
61 | #define WM8900_REG_INBOOSTMIX2 0x19 | ||
62 | #define WM8900_REG_ADCPATH 0x1a | ||
63 | #define WM8900_REG_AUXBOOST 0x1b | ||
64 | #define WM8900_REG_ADDCTL 0x1e | ||
65 | #define WM8900_REG_FLLCTL1 0x24 | ||
66 | #define WM8900_REG_FLLCTL2 0x25 | ||
67 | #define WM8900_REG_FLLCTL3 0x26 | ||
68 | #define WM8900_REG_FLLCTL4 0x27 | ||
69 | #define WM8900_REG_FLLCTL5 0x28 | ||
70 | #define WM8900_REG_FLLCTL6 0x29 | ||
71 | #define WM8900_REG_LOUTMIXCTL1 0x2c | ||
72 | #define WM8900_REG_ROUTMIXCTL1 0x2d | ||
73 | #define WM8900_REG_BYPASS1 0x2e | ||
74 | #define WM8900_REG_BYPASS2 0x2f | ||
75 | #define WM8900_REG_AUXOUT_CTL 0x30 | ||
76 | #define WM8900_REG_LOUT1CTL 0x33 | ||
77 | #define WM8900_REG_ROUT1CTL 0x34 | ||
78 | #define WM8900_REG_LOUT2CTL 0x35 | ||
79 | #define WM8900_REG_ROUT2CTL 0x36 | ||
80 | #define WM8900_REG_HPCTL1 0x3a | ||
81 | #define WM8900_REG_OUTBIASCTL 0x73 | ||
82 | |||
83 | #define WM8900_MAXREG 0x80 | ||
84 | |||
85 | #define WM8900_REG_ADDCTL_OUT1_DIS 0x80 | ||
86 | #define WM8900_REG_ADDCTL_OUT2_DIS 0x40 | ||
87 | #define WM8900_REG_ADDCTL_VMID_DIS 0x20 | ||
88 | #define WM8900_REG_ADDCTL_BIAS_SRC 0x10 | ||
89 | #define WM8900_REG_ADDCTL_VMID_SOFTST 0x04 | ||
90 | #define WM8900_REG_ADDCTL_TEMP_SD 0x02 | ||
91 | |||
92 | #define WM8900_REG_GPIO_TEMP_ENA 0x2 | ||
93 | |||
94 | #define WM8900_REG_POWER1_STARTUP_BIAS_ENA 0x0100 | ||
95 | #define WM8900_REG_POWER1_BIAS_ENA 0x0008 | ||
96 | #define WM8900_REG_POWER1_VMID_BUF_ENA 0x0004 | ||
97 | #define WM8900_REG_POWER1_FLL_ENA 0x0040 | ||
98 | |||
99 | #define WM8900_REG_POWER2_SYSCLK_ENA 0x8000 | ||
100 | #define WM8900_REG_POWER2_ADCL_ENA 0x0002 | ||
101 | #define WM8900_REG_POWER2_ADCR_ENA 0x0001 | ||
102 | |||
103 | #define WM8900_REG_POWER3_DACL_ENA 0x0002 | ||
104 | #define WM8900_REG_POWER3_DACR_ENA 0x0001 | ||
105 | |||
106 | #define WM8900_REG_AUDIO1_AIF_FMT_MASK 0x0018 | ||
107 | #define WM8900_REG_AUDIO1_LRCLK_INV 0x0080 | ||
108 | #define WM8900_REG_AUDIO1_BCLK_INV 0x0100 | ||
109 | |||
110 | #define WM8900_REG_CLOCKING1_BCLK_DIR 0x1 | ||
111 | #define WM8900_REG_CLOCKING1_MCLK_SRC 0x100 | ||
112 | #define WM8900_REG_CLOCKING1_BCLK_MASK (~0x01e) | ||
113 | #define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000) | ||
114 | |||
115 | #define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0 | ||
116 | #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c | ||
117 | |||
118 | #define WM8900_REG_DACCTRL_MUTE 0x004 | ||
119 | #define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400 | ||
120 | |||
121 | #define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800 | ||
122 | |||
123 | #define WM8900_REG_AUDIO4_DACLRC_DIR 0x0800 | ||
124 | |||
125 | #define WM8900_REG_FLLCTL1_OSC_ENA 0x100 | ||
126 | |||
127 | #define WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF 0x100 | ||
128 | |||
129 | #define WM8900_REG_HPCTL1_HP_IPSTAGE_ENA 0x80 | ||
130 | #define WM8900_REG_HPCTL1_HP_OPSTAGE_ENA 0x40 | ||
131 | #define WM8900_REG_HPCTL1_HP_CLAMP_IP 0x20 | ||
132 | #define WM8900_REG_HPCTL1_HP_CLAMP_OP 0x10 | ||
133 | #define WM8900_REG_HPCTL1_HP_SHORT 0x08 | ||
134 | #define WM8900_REG_HPCTL1_HP_SHORT2 0x04 | ||
135 | |||
136 | #define WM8900_LRC_MASK 0xfc00 | ||
137 | |||
138 | struct snd_soc_codec_device soc_codec_dev_wm8900; | ||
139 | |||
140 | struct wm8900_priv { | ||
141 | u32 fll_in; /* FLL input frequency */ | ||
142 | u32 fll_out; /* FLL output frequency */ | ||
143 | }; | ||
144 | |||
145 | /* | ||
146 | * wm8900 register cache. We can't read the entire register space and we | ||
147 | * have slow control buses so we cache the registers. | ||
148 | */ | ||
149 | static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { | ||
150 | 0x8900, 0x0000, | ||
151 | 0xc000, 0x0000, | ||
152 | 0x4050, 0x4000, | ||
153 | 0x0008, 0x0000, | ||
154 | 0x0040, 0x0040, | ||
155 | 0x1004, 0x00c0, | ||
156 | 0x00c0, 0x0000, | ||
157 | 0x0100, 0x00c0, | ||
158 | 0x00c0, 0x0000, | ||
159 | 0xb001, 0x0000, | ||
160 | 0x0000, 0x0044, | ||
161 | 0x004c, 0x004c, | ||
162 | 0x0044, 0x0044, | ||
163 | 0x0000, 0x0044, | ||
164 | 0x0000, 0x0000, | ||
165 | 0x0002, 0x0000, | ||
166 | 0x0000, 0x0000, | ||
167 | 0x0000, 0x0000, | ||
168 | 0x0008, 0x0000, | ||
169 | 0x0000, 0x0008, | ||
170 | 0x0097, 0x0100, | ||
171 | 0x0000, 0x0000, | ||
172 | 0x0050, 0x0050, | ||
173 | 0x0055, 0x0055, | ||
174 | 0x0055, 0x0000, | ||
175 | 0x0000, 0x0079, | ||
176 | 0x0079, 0x0079, | ||
177 | 0x0079, 0x0000, | ||
178 | /* Remaining registers all zero */ | ||
179 | }; | ||
180 | |||
181 | /* | ||
182 | * read wm8900 register cache | ||
183 | */ | ||
184 | static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec, | ||
185 | unsigned int reg) | ||
186 | { | ||
187 | u16 *cache = codec->reg_cache; | ||
188 | |||
189 | BUG_ON(reg >= WM8900_MAXREG); | ||
190 | |||
191 | if (reg == WM8900_REG_ID) | ||
192 | return 0; | ||
193 | |||
194 | return cache[reg]; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * write wm8900 register cache | ||
199 | */ | ||
200 | static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec, | ||
201 | u16 reg, unsigned int value) | ||
202 | { | ||
203 | u16 *cache = codec->reg_cache; | ||
204 | |||
205 | BUG_ON(reg >= WM8900_MAXREG); | ||
206 | |||
207 | cache[reg] = value; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * write to the WM8900 register space | ||
212 | */ | ||
213 | static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg, | ||
214 | unsigned int value) | ||
215 | { | ||
216 | u8 data[3]; | ||
217 | |||
218 | if (value == wm8900_read_reg_cache(codec, reg)) | ||
219 | return 0; | ||
220 | |||
221 | /* data is | ||
222 | * D15..D9 WM8900 register offset | ||
223 | * D8...D0 register data | ||
224 | */ | ||
225 | data[0] = reg; | ||
226 | data[1] = value >> 8; | ||
227 | data[2] = value & 0x00ff; | ||
228 | |||
229 | wm8900_write_reg_cache(codec, reg, value); | ||
230 | if (codec->hw_write(codec->control_data, data, 3) == 3) | ||
231 | return 0; | ||
232 | else | ||
233 | return -EIO; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Read from the wm8900. | ||
238 | */ | ||
239 | static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg) | ||
240 | { | ||
241 | struct i2c_msg xfer[2]; | ||
242 | u16 data; | ||
243 | int ret; | ||
244 | struct i2c_client *client = codec->control_data; | ||
245 | |||
246 | BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1); | ||
247 | |||
248 | /* Write register */ | ||
249 | xfer[0].addr = client->addr; | ||
250 | xfer[0].flags = 0; | ||
251 | xfer[0].len = 1; | ||
252 | xfer[0].buf = ® | ||
253 | |||
254 | /* Read data */ | ||
255 | xfer[1].addr = client->addr; | ||
256 | xfer[1].flags = I2C_M_RD; | ||
257 | xfer[1].len = 2; | ||
258 | xfer[1].buf = (u8 *)&data; | ||
259 | |||
260 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
261 | if (ret != 2) { | ||
262 | printk(KERN_CRIT "i2c_transfer returned %d\n", ret); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | return (data >> 8) | ((data & 0xff) << 8); | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Read from the WM8900 register space. Most registers can't be read | ||
271 | * and are therefore supplied from cache. | ||
272 | */ | ||
273 | static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg) | ||
274 | { | ||
275 | switch (reg) { | ||
276 | case WM8900_REG_ID: | ||
277 | return wm8900_chip_read(codec, reg); | ||
278 | default: | ||
279 | return wm8900_read_reg_cache(codec, reg); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static void wm8900_reset(struct snd_soc_codec *codec) | ||
284 | { | ||
285 | wm8900_write(codec, WM8900_REG_RESET, 0); | ||
286 | |||
287 | memcpy(codec->reg_cache, wm8900_reg_defaults, | ||
288 | sizeof(codec->reg_cache)); | ||
289 | } | ||
290 | |||
291 | static int wm8900_hp_event(struct snd_soc_dapm_widget *w, | ||
292 | struct snd_kcontrol *kcontrol, int event) | ||
293 | { | ||
294 | struct snd_soc_codec *codec = w->codec; | ||
295 | u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1); | ||
296 | |||
297 | switch (event) { | ||
298 | case SND_SOC_DAPM_PRE_PMU: | ||
299 | /* Clamp headphone outputs */ | ||
300 | hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | | ||
301 | WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
302 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
303 | break; | ||
304 | |||
305 | case SND_SOC_DAPM_POST_PMU: | ||
306 | /* Enable the input stage */ | ||
307 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP; | ||
308 | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | | ||
309 | WM8900_REG_HPCTL1_HP_SHORT2 | | ||
310 | WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; | ||
311 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
312 | |||
313 | msleep(400); | ||
314 | |||
315 | /* Enable the output stage */ | ||
316 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
317 | hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; | ||
318 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
319 | |||
320 | /* Remove the shorts */ | ||
321 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; | ||
322 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
323 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; | ||
324 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
325 | break; | ||
326 | |||
327 | case SND_SOC_DAPM_PRE_PMD: | ||
328 | /* Short the output */ | ||
329 | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; | ||
330 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
331 | |||
332 | /* Disable the output stage */ | ||
333 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; | ||
334 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
335 | |||
336 | /* Clamp the outputs and power down input */ | ||
337 | hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | | ||
338 | WM8900_REG_HPCTL1_HP_CLAMP_OP; | ||
339 | hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; | ||
340 | wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); | ||
341 | break; | ||
342 | |||
343 | case SND_SOC_DAPM_POST_PMD: | ||
344 | /* Disable everything */ | ||
345 | wm8900_write(codec, WM8900_REG_HPCTL1, 0); | ||
346 | break; | ||
347 | |||
348 | default: | ||
349 | BUG(); | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 100, 0); | ||
356 | |||
357 | static const DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 0); | ||
358 | |||
359 | static const DECLARE_TLV_DB_SCALE(in_boost_tlv, -1200, 600, 0); | ||
360 | |||
361 | static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1200, 100, 0); | ||
362 | |||
363 | static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0); | ||
364 | |||
365 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); | ||
366 | |||
367 | static const DECLARE_TLV_DB_SCALE(adc_svol_tlv, -3600, 300, 0); | ||
368 | |||
369 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); | ||
370 | |||
371 | static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; | ||
372 | |||
373 | static const struct soc_enum mic_bias_level = | ||
374 | SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); | ||
375 | |||
376 | static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; | ||
377 | |||
378 | static const struct soc_enum dac_mute_rate = | ||
379 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); | ||
380 | |||
381 | static const char *dac_deemphasis_txt[] = { | ||
382 | "Disabled", "32kHz", "44.1kHz", "48kHz" | ||
383 | }; | ||
384 | |||
385 | static const struct soc_enum dac_deemphasis = | ||
386 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); | ||
387 | |||
388 | static const char *adc_hpf_cut_txt[] = { | ||
389 | "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" | ||
390 | }; | ||
391 | |||
392 | static const struct soc_enum adc_hpf_cut = | ||
393 | SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); | ||
394 | |||
395 | static const char *lr_txt[] = { | ||
396 | "Left", "Right" | ||
397 | }; | ||
398 | |||
399 | static const struct soc_enum aifl_src = | ||
400 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); | ||
401 | |||
402 | static const struct soc_enum aifr_src = | ||
403 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); | ||
404 | |||
405 | static const struct soc_enum dacl_src = | ||
406 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); | ||
407 | |||
408 | static const struct soc_enum dacr_src = | ||
409 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); | ||
410 | |||
411 | static const char *sidetone_txt[] = { | ||
412 | "Disabled", "Left ADC", "Right ADC" | ||
413 | }; | ||
414 | |||
415 | static const struct soc_enum dacl_sidetone = | ||
416 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); | ||
417 | |||
418 | static const struct soc_enum dacr_sidetone = | ||
419 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); | ||
420 | |||
421 | static const struct snd_kcontrol_new wm8900_snd_controls[] = { | ||
422 | SOC_ENUM("Mic Bias Level", mic_bias_level), | ||
423 | |||
424 | SOC_SINGLE_TLV("Left Input PGA Volume", WM8900_REG_LINVOL, 0, 31, 0, | ||
425 | in_pga_tlv), | ||
426 | SOC_SINGLE("Left Input PGA Switch", WM8900_REG_LINVOL, 6, 1, 1), | ||
427 | SOC_SINGLE("Left Input PGA ZC Switch", WM8900_REG_LINVOL, 7, 1, 0), | ||
428 | |||
429 | SOC_SINGLE_TLV("Right Input PGA Volume", WM8900_REG_RINVOL, 0, 31, 0, | ||
430 | in_pga_tlv), | ||
431 | SOC_SINGLE("Right Input PGA Switch", WM8900_REG_RINVOL, 6, 1, 1), | ||
432 | SOC_SINGLE("Right Input PGA ZC Switch", WM8900_REG_RINVOL, 7, 1, 0), | ||
433 | |||
434 | SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1), | ||
435 | SOC_ENUM("DAC Mute Rate", dac_mute_rate), | ||
436 | SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0), | ||
437 | SOC_ENUM("DAC Deemphasis", dac_deemphasis), | ||
438 | SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0), | ||
439 | SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL, | ||
440 | 12, 1, 0), | ||
441 | |||
442 | SOC_SINGLE("ADC HPF Switch", WM8900_REG_ADCCTRL, 8, 1, 0), | ||
443 | SOC_ENUM("ADC HPF Cut-Off", adc_hpf_cut), | ||
444 | SOC_DOUBLE("ADC Invert Switch", WM8900_REG_ADCCTRL, 1, 0, 1, 0), | ||
445 | SOC_SINGLE_TLV("Left ADC Sidetone Volume", WM8900_REG_SIDETONE, 9, 12, 0, | ||
446 | adc_svol_tlv), | ||
447 | SOC_SINGLE_TLV("Right ADC Sidetone Volume", WM8900_REG_SIDETONE, 5, 12, 0, | ||
448 | adc_svol_tlv), | ||
449 | SOC_ENUM("Left Digital Audio Source", aifl_src), | ||
450 | SOC_ENUM("Right Digital Audio Source", aifr_src), | ||
451 | |||
452 | SOC_SINGLE_TLV("DAC Input Boost Volume", WM8900_REG_AUDIO2, 10, 4, 0, | ||
453 | dac_boost_tlv), | ||
454 | SOC_ENUM("Left DAC Source", dacl_src), | ||
455 | SOC_ENUM("Right DAC Source", dacr_src), | ||
456 | SOC_ENUM("Left DAC Sidetone", dacl_sidetone), | ||
457 | SOC_ENUM("Right DAC Sidetone", dacr_sidetone), | ||
458 | SOC_DOUBLE("DAC Invert Switch", WM8900_REG_DACCTRL, 1, 0, 1, 0), | ||
459 | |||
460 | SOC_DOUBLE_R_TLV("Digital Playback Volume", | ||
461 | WM8900_REG_LDAC_DV, WM8900_REG_RDAC_DV, | ||
462 | 1, 96, 0, dac_tlv), | ||
463 | SOC_DOUBLE_R_TLV("Digital Capture Volume", | ||
464 | WM8900_REG_LADC_DV, WM8900_REG_RADC_DV, 1, 119, 0, adc_tlv), | ||
465 | |||
466 | SOC_SINGLE_TLV("LINPUT3 Bypass Volume", WM8900_REG_LOUTMIXCTL1, 4, 7, 0, | ||
467 | out_mix_tlv), | ||
468 | SOC_SINGLE_TLV("RINPUT3 Bypass Volume", WM8900_REG_ROUTMIXCTL1, 4, 7, 0, | ||
469 | out_mix_tlv), | ||
470 | SOC_SINGLE_TLV("Left AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 4, 7, 0, | ||
471 | out_mix_tlv), | ||
472 | SOC_SINGLE_TLV("Right AUX Bypass Volume", WM8900_REG_AUXOUT_CTL, 0, 7, 0, | ||
473 | out_mix_tlv), | ||
474 | |||
475 | SOC_SINGLE_TLV("LeftIn to RightOut Mixer Volume", WM8900_REG_BYPASS1, 0, 7, 0, | ||
476 | out_mix_tlv), | ||
477 | SOC_SINGLE_TLV("LeftIn to LeftOut Mixer Volume", WM8900_REG_BYPASS1, 4, 7, 0, | ||
478 | out_mix_tlv), | ||
479 | SOC_SINGLE_TLV("RightIn to LeftOut Mixer Volume", WM8900_REG_BYPASS2, 0, 7, 0, | ||
480 | out_mix_tlv), | ||
481 | SOC_SINGLE_TLV("RightIn to RightOut Mixer Volume", WM8900_REG_BYPASS2, 4, 7, 0, | ||
482 | out_mix_tlv), | ||
483 | |||
484 | SOC_SINGLE_TLV("IN2L Boost Volume", WM8900_REG_INBOOSTMIX1, 0, 3, 0, | ||
485 | in_boost_tlv), | ||
486 | SOC_SINGLE_TLV("IN3L Boost Volume", WM8900_REG_INBOOSTMIX1, 4, 3, 0, | ||
487 | in_boost_tlv), | ||
488 | SOC_SINGLE_TLV("IN2R Boost Volume", WM8900_REG_INBOOSTMIX2, 0, 3, 0, | ||
489 | in_boost_tlv), | ||
490 | SOC_SINGLE_TLV("IN3R Boost Volume", WM8900_REG_INBOOSTMIX2, 4, 3, 0, | ||
491 | in_boost_tlv), | ||
492 | SOC_SINGLE_TLV("Left AUX Boost Volume", WM8900_REG_AUXBOOST, 4, 3, 0, | ||
493 | in_boost_tlv), | ||
494 | SOC_SINGLE_TLV("Right AUX Boost Volume", WM8900_REG_AUXBOOST, 0, 3, 0, | ||
495 | in_boost_tlv), | ||
496 | |||
497 | SOC_DOUBLE_R_TLV("LINEOUT1 Volume", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
498 | 0, 63, 0, out_pga_tlv), | ||
499 | SOC_DOUBLE_R("LINEOUT1 Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
500 | 6, 1, 1), | ||
501 | SOC_DOUBLE_R("LINEOUT1 ZC Switch", WM8900_REG_LOUT1CTL, WM8900_REG_ROUT1CTL, | ||
502 | 7, 1, 0), | ||
503 | |||
504 | SOC_DOUBLE_R_TLV("LINEOUT2 Volume", | ||
505 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, | ||
506 | 0, 63, 0, out_pga_tlv), | ||
507 | SOC_DOUBLE_R("LINEOUT2 Switch", | ||
508 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 6, 1, 1), | ||
509 | SOC_DOUBLE_R("LINEOUT2 ZC Switch", | ||
510 | WM8900_REG_LOUT2CTL, WM8900_REG_ROUT2CTL, 7, 1, 0), | ||
511 | SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, | ||
512 | 0, 1, 1), | ||
513 | |||
514 | }; | ||
515 | |||
516 | /* add non dapm controls */ | ||
517 | static int wm8900_add_controls(struct snd_soc_codec *codec) | ||
518 | { | ||
519 | int err, i; | ||
520 | |||
521 | for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) { | ||
522 | err = snd_ctl_add(codec->card, | ||
523 | snd_soc_cnew(&wm8900_snd_controls[i], | ||
524 | codec, NULL)); | ||
525 | if (err < 0) | ||
526 | return err; | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = | ||
533 | SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); | ||
534 | |||
535 | static const struct snd_kcontrol_new wm8900_dapm_routput2_control = | ||
536 | SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0); | ||
537 | |||
538 | static const struct snd_kcontrol_new wm8900_loutmix_controls[] = { | ||
539 | SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0), | ||
540 | SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0), | ||
541 | SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 7, 1, 0), | ||
542 | SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 3, 1, 0), | ||
543 | SOC_DAPM_SINGLE("DACL Switch", WM8900_REG_LOUTMIXCTL1, 8, 1, 0), | ||
544 | }; | ||
545 | |||
546 | static const struct snd_kcontrol_new wm8900_routmix_controls[] = { | ||
547 | SOC_DAPM_SINGLE("RINPUT3 Bypass Switch", WM8900_REG_ROUTMIXCTL1, 7, 1, 0), | ||
548 | SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 3, 1, 0), | ||
549 | SOC_DAPM_SINGLE("Left Input Mixer Switch", WM8900_REG_BYPASS1, 3, 1, 0), | ||
550 | SOC_DAPM_SINGLE("Right Input Mixer Switch", WM8900_REG_BYPASS2, 7, 1, 0), | ||
551 | SOC_DAPM_SINGLE("DACR Switch", WM8900_REG_ROUTMIXCTL1, 8, 1, 0), | ||
552 | }; | ||
553 | |||
554 | static const struct snd_kcontrol_new wm8900_linmix_controls[] = { | ||
555 | SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INBOOSTMIX1, 2, 1, 1), | ||
556 | SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INBOOSTMIX1, 6, 1, 1), | ||
557 | SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 6, 1, 1), | ||
558 | SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 6, 1, 0), | ||
559 | }; | ||
560 | |||
561 | static const struct snd_kcontrol_new wm8900_rinmix_controls[] = { | ||
562 | SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INBOOSTMIX2, 2, 1, 1), | ||
563 | SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INBOOSTMIX2, 6, 1, 1), | ||
564 | SOC_DAPM_SINGLE("AUX Switch", WM8900_REG_AUXBOOST, 2, 1, 1), | ||
565 | SOC_DAPM_SINGLE("Input PGA Switch", WM8900_REG_ADCPATH, 2, 1, 0), | ||
566 | }; | ||
567 | |||
568 | static const struct snd_kcontrol_new wm8900_linpga_controls[] = { | ||
569 | SOC_DAPM_SINGLE("LINPUT1 Switch", WM8900_REG_INCTL, 6, 1, 0), | ||
570 | SOC_DAPM_SINGLE("LINPUT2 Switch", WM8900_REG_INCTL, 5, 1, 0), | ||
571 | SOC_DAPM_SINGLE("LINPUT3 Switch", WM8900_REG_INCTL, 4, 1, 0), | ||
572 | }; | ||
573 | |||
574 | static const struct snd_kcontrol_new wm8900_rinpga_controls[] = { | ||
575 | SOC_DAPM_SINGLE("RINPUT1 Switch", WM8900_REG_INCTL, 2, 1, 0), | ||
576 | SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0), | ||
577 | SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), | ||
578 | }; | ||
579 | |||
580 | static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" }; | ||
581 | |||
582 | static const struct soc_enum wm8900_lineout2_lp_mux = | ||
583 | SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux); | ||
584 | |||
585 | static const struct snd_kcontrol_new wm8900_lineout2_lp = | ||
586 | SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); | ||
587 | |||
588 | static const struct snd_soc_dapm_widget wm8900_dapm_widgets[] = { | ||
589 | |||
590 | /* Externally visible pins */ | ||
591 | SND_SOC_DAPM_OUTPUT("LINEOUT1L"), | ||
592 | SND_SOC_DAPM_OUTPUT("LINEOUT1R"), | ||
593 | SND_SOC_DAPM_OUTPUT("LINEOUT2L"), | ||
594 | SND_SOC_DAPM_OUTPUT("LINEOUT2R"), | ||
595 | SND_SOC_DAPM_OUTPUT("HP_L"), | ||
596 | SND_SOC_DAPM_OUTPUT("HP_R"), | ||
597 | |||
598 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
599 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
600 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
601 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
602 | SND_SOC_DAPM_INPUT("RINPUT3"), | ||
603 | SND_SOC_DAPM_INPUT("LINPUT3"), | ||
604 | SND_SOC_DAPM_INPUT("AUX"), | ||
605 | |||
606 | SND_SOC_DAPM_VMID("VMID"), | ||
607 | |||
608 | /* Input */ | ||
609 | SND_SOC_DAPM_MIXER("Left Input PGA", WM8900_REG_POWER2, 3, 0, | ||
610 | wm8900_linpga_controls, | ||
611 | ARRAY_SIZE(wm8900_linpga_controls)), | ||
612 | SND_SOC_DAPM_MIXER("Right Input PGA", WM8900_REG_POWER2, 2, 0, | ||
613 | wm8900_rinpga_controls, | ||
614 | ARRAY_SIZE(wm8900_rinpga_controls)), | ||
615 | |||
616 | SND_SOC_DAPM_MIXER("Left Input Mixer", WM8900_REG_POWER2, 5, 0, | ||
617 | wm8900_linmix_controls, | ||
618 | ARRAY_SIZE(wm8900_linmix_controls)), | ||
619 | SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0, | ||
620 | wm8900_rinmix_controls, | ||
621 | ARRAY_SIZE(wm8900_rinmix_controls)), | ||
622 | |||
623 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0), | ||
624 | |||
625 | SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0), | ||
626 | SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0), | ||
627 | |||
628 | /* Output */ | ||
629 | SND_SOC_DAPM_DAC("DACL", "Left HiFi Playback", WM8900_REG_POWER3, 1, 0), | ||
630 | SND_SOC_DAPM_DAC("DACR", "Right HiFi Playback", WM8900_REG_POWER3, 0, 0), | ||
631 | |||
632 | SND_SOC_DAPM_PGA_E("Headphone Amplifier", WM8900_REG_POWER3, 7, 0, NULL, 0, | ||
633 | wm8900_hp_event, | ||
634 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
635 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | ||
636 | |||
637 | SND_SOC_DAPM_PGA("LINEOUT1L PGA", WM8900_REG_POWER2, 8, 0, NULL, 0), | ||
638 | SND_SOC_DAPM_PGA("LINEOUT1R PGA", WM8900_REG_POWER2, 7, 0, NULL, 0), | ||
639 | |||
640 | SND_SOC_DAPM_MUX("LINEOUT2 LP", SND_SOC_NOPM, 0, 0, &wm8900_lineout2_lp), | ||
641 | SND_SOC_DAPM_PGA("LINEOUT2L PGA", WM8900_REG_POWER3, 6, 0, NULL, 0), | ||
642 | SND_SOC_DAPM_PGA("LINEOUT2R PGA", WM8900_REG_POWER3, 5, 0, NULL, 0), | ||
643 | |||
644 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8900_REG_POWER3, 3, 0, | ||
645 | wm8900_loutmix_controls, | ||
646 | ARRAY_SIZE(wm8900_loutmix_controls)), | ||
647 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0, | ||
648 | wm8900_routmix_controls, | ||
649 | ARRAY_SIZE(wm8900_routmix_controls)), | ||
650 | }; | ||
651 | |||
652 | /* Target, Path, Source */ | ||
653 | static const struct snd_soc_dapm_route audio_map[] = { | ||
654 | /* Inputs */ | ||
655 | {"Left Input PGA", "LINPUT1 Switch", "LINPUT1"}, | ||
656 | {"Left Input PGA", "LINPUT2 Switch", "LINPUT2"}, | ||
657 | {"Left Input PGA", "LINPUT3 Switch", "LINPUT3"}, | ||
658 | |||
659 | {"Right Input PGA", "RINPUT1 Switch", "RINPUT1"}, | ||
660 | {"Right Input PGA", "RINPUT2 Switch", "RINPUT2"}, | ||
661 | {"Right Input PGA", "RINPUT3 Switch", "RINPUT3"}, | ||
662 | |||
663 | {"Left Input Mixer", "LINPUT2 Switch", "LINPUT2"}, | ||
664 | {"Left Input Mixer", "LINPUT3 Switch", "LINPUT3"}, | ||
665 | {"Left Input Mixer", "AUX Switch", "AUX"}, | ||
666 | {"Left Input Mixer", "Input PGA Switch", "Left Input PGA"}, | ||
667 | |||
668 | {"Right Input Mixer", "RINPUT2 Switch", "RINPUT2"}, | ||
669 | {"Right Input Mixer", "RINPUT3 Switch", "RINPUT3"}, | ||
670 | {"Right Input Mixer", "AUX Switch", "AUX"}, | ||
671 | {"Right Input Mixer", "Input PGA Switch", "Right Input PGA"}, | ||
672 | |||
673 | {"ADCL", NULL, "Left Input Mixer"}, | ||
674 | {"ADCR", NULL, "Right Input Mixer"}, | ||
675 | |||
676 | /* Outputs */ | ||
677 | {"LINEOUT1L", NULL, "LINEOUT1L PGA"}, | ||
678 | {"LINEOUT1L PGA", NULL, "Left Output Mixer"}, | ||
679 | {"LINEOUT1R", NULL, "LINEOUT1R PGA"}, | ||
680 | {"LINEOUT1R PGA", NULL, "Right Output Mixer"}, | ||
681 | |||
682 | {"LINEOUT2L PGA", NULL, "Left Output Mixer"}, | ||
683 | {"LINEOUT2 LP", "Disabled", "LINEOUT2L PGA"}, | ||
684 | {"LINEOUT2 LP", "Enabled", "Left Output Mixer"}, | ||
685 | {"LINEOUT2L", NULL, "LINEOUT2 LP"}, | ||
686 | |||
687 | {"LINEOUT2R PGA", NULL, "Right Output Mixer"}, | ||
688 | {"LINEOUT2 LP", "Disabled", "LINEOUT2R PGA"}, | ||
689 | {"LINEOUT2 LP", "Enabled", "Right Output Mixer"}, | ||
690 | {"LINEOUT2R", NULL, "LINEOUT2 LP"}, | ||
691 | |||
692 | {"Left Output Mixer", "LINPUT3 Bypass Switch", "LINPUT3"}, | ||
693 | {"Left Output Mixer", "AUX Bypass Switch", "AUX"}, | ||
694 | {"Left Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, | ||
695 | {"Left Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, | ||
696 | {"Left Output Mixer", "DACL Switch", "DACL"}, | ||
697 | |||
698 | {"Right Output Mixer", "RINPUT3 Bypass Switch", "RINPUT3"}, | ||
699 | {"Right Output Mixer", "AUX Bypass Switch", "AUX"}, | ||
700 | {"Right Output Mixer", "Left Input Mixer Switch", "Left Input Mixer"}, | ||
701 | {"Right Output Mixer", "Right Input Mixer Switch", "Right Input Mixer"}, | ||
702 | {"Right Output Mixer", "DACR Switch", "DACR"}, | ||
703 | |||
704 | /* Note that the headphone output stage needs to be connected | ||
705 | * externally to LINEOUT2 via DC blocking capacitors. Other | ||
706 | * configurations are not supported. | ||
707 | * | ||
708 | * Note also that left and right headphone paths are treated as a | ||
709 | * mono path. | ||
710 | */ | ||
711 | {"Headphone Amplifier", NULL, "LINEOUT2 LP"}, | ||
712 | {"Headphone Amplifier", NULL, "LINEOUT2 LP"}, | ||
713 | {"HP_L", NULL, "Headphone Amplifier"}, | ||
714 | {"HP_R", NULL, "Headphone Amplifier"}, | ||
715 | }; | ||
716 | |||
717 | static int wm8900_add_widgets(struct snd_soc_codec *codec) | ||
718 | { | ||
719 | snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets, | ||
720 | ARRAY_SIZE(wm8900_dapm_widgets)); | ||
721 | |||
722 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
723 | |||
724 | snd_soc_dapm_new_widgets(codec); | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int wm8900_hw_params(struct snd_pcm_substream *substream, | ||
730 | struct snd_pcm_hw_params *params) | ||
731 | { | ||
732 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
733 | struct snd_soc_device *socdev = rtd->socdev; | ||
734 | struct snd_soc_codec *codec = socdev->codec; | ||
735 | u16 reg; | ||
736 | |||
737 | reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; | ||
738 | |||
739 | switch (params_format(params)) { | ||
740 | case SNDRV_PCM_FORMAT_S16_LE: | ||
741 | break; | ||
742 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
743 | reg |= 0x20; | ||
744 | break; | ||
745 | case SNDRV_PCM_FORMAT_S24_LE: | ||
746 | reg |= 0x40; | ||
747 | break; | ||
748 | case SNDRV_PCM_FORMAT_S32_LE: | ||
749 | reg |= 0x60; | ||
750 | break; | ||
751 | default: | ||
752 | return -EINVAL; | ||
753 | } | ||
754 | |||
755 | wm8900_write(codec, WM8900_REG_AUDIO1, reg); | ||
756 | |||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | /* FLL divisors */ | ||
761 | struct _fll_div { | ||
762 | u16 fll_ratio; | ||
763 | u16 fllclk_div; | ||
764 | u16 fll_slow_lock_ref; | ||
765 | u16 n; | ||
766 | u16 k; | ||
767 | }; | ||
768 | |||
769 | /* The size in bits of the FLL divide multiplied by 10 | ||
770 | * to allow rounding later */ | ||
771 | #define FIXED_FLL_SIZE ((1 << 16) * 10) | ||
772 | |||
773 | static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, | ||
774 | unsigned int Fout) | ||
775 | { | ||
776 | u64 Kpart; | ||
777 | unsigned int K, Ndiv, Nmod, target; | ||
778 | unsigned int div; | ||
779 | |||
780 | BUG_ON(!Fout); | ||
781 | |||
782 | /* The FLL must run at 90-100MHz which is then scaled down to | ||
783 | * the output value by FLLCLK_DIV. */ | ||
784 | target = Fout; | ||
785 | div = 1; | ||
786 | while (target < 90000000) { | ||
787 | div *= 2; | ||
788 | target *= 2; | ||
789 | } | ||
790 | |||
791 | if (target > 100000000) | ||
792 | printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d" | ||
793 | " Fout=%d\n", target, Fref, Fout); | ||
794 | if (div > 32) { | ||
795 | printk(KERN_ERR "wm8900: Invalid FLL division rate %u, " | ||
796 | "Fref=%d, Fout=%d, target=%d\n", | ||
797 | div, Fref, Fout, target); | ||
798 | return -EINVAL; | ||
799 | } | ||
800 | |||
801 | fll_div->fllclk_div = div >> 2; | ||
802 | |||
803 | if (Fref < 48000) | ||
804 | fll_div->fll_slow_lock_ref = 1; | ||
805 | else | ||
806 | fll_div->fll_slow_lock_ref = 0; | ||
807 | |||
808 | Ndiv = target / Fref; | ||
809 | |||
810 | if (Fref < 1000000) | ||
811 | fll_div->fll_ratio = 8; | ||
812 | else | ||
813 | fll_div->fll_ratio = 1; | ||
814 | |||
815 | fll_div->n = Ndiv / fll_div->fll_ratio; | ||
816 | Nmod = (target / fll_div->fll_ratio) % Fref; | ||
817 | |||
818 | /* Calculate fractional part - scale up so we can round. */ | ||
819 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
820 | |||
821 | do_div(Kpart, Fref); | ||
822 | |||
823 | K = Kpart & 0xFFFFFFFF; | ||
824 | |||
825 | if ((K % 10) >= 5) | ||
826 | K += 5; | ||
827 | |||
828 | /* Move down to proper range now rounding is done */ | ||
829 | fll_div->k = K / 10; | ||
830 | |||
831 | BUG_ON(target != Fout * (fll_div->fllclk_div << 2)); | ||
832 | BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n); | ||
833 | |||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | static int wm8900_set_fll(struct snd_soc_codec *codec, | ||
838 | int fll_id, unsigned int freq_in, unsigned int freq_out) | ||
839 | { | ||
840 | struct wm8900_priv *wm8900 = codec->private_data; | ||
841 | struct _fll_div fll_div; | ||
842 | unsigned int reg; | ||
843 | |||
844 | if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out) | ||
845 | return 0; | ||
846 | |||
847 | /* The digital side should be disabled during any change. */ | ||
848 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
849 | wm8900_write(codec, WM8900_REG_POWER1, | ||
850 | reg & (~WM8900_REG_POWER1_FLL_ENA)); | ||
851 | |||
852 | /* Disable the FLL? */ | ||
853 | if (!freq_in || !freq_out) { | ||
854 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
855 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
856 | reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); | ||
857 | |||
858 | reg = wm8900_read(codec, WM8900_REG_FLLCTL1); | ||
859 | wm8900_write(codec, WM8900_REG_FLLCTL1, | ||
860 | reg & (~WM8900_REG_FLLCTL1_OSC_ENA)); | ||
861 | |||
862 | wm8900->fll_in = freq_in; | ||
863 | wm8900->fll_out = freq_out; | ||
864 | |||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | if (fll_factors(&fll_div, freq_in, freq_out) != 0) | ||
869 | goto reenable; | ||
870 | |||
871 | wm8900->fll_in = freq_in; | ||
872 | wm8900->fll_out = freq_out; | ||
873 | |||
874 | /* The osclilator *MUST* be enabled before we enable the | ||
875 | * digital circuit. */ | ||
876 | wm8900_write(codec, WM8900_REG_FLLCTL1, | ||
877 | fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA); | ||
878 | |||
879 | wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); | ||
880 | wm8900_write(codec, WM8900_REG_FLLCTL5, | ||
881 | (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f)); | ||
882 | |||
883 | if (fll_div.k) { | ||
884 | wm8900_write(codec, WM8900_REG_FLLCTL2, | ||
885 | (fll_div.k >> 8) | 0x100); | ||
886 | wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); | ||
887 | } else | ||
888 | wm8900_write(codec, WM8900_REG_FLLCTL2, 0); | ||
889 | |||
890 | if (fll_div.fll_slow_lock_ref) | ||
891 | wm8900_write(codec, WM8900_REG_FLLCTL6, | ||
892 | WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF); | ||
893 | else | ||
894 | wm8900_write(codec, WM8900_REG_FLLCTL6, 0); | ||
895 | |||
896 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
897 | wm8900_write(codec, WM8900_REG_POWER1, | ||
898 | reg | WM8900_REG_POWER1_FLL_ENA); | ||
899 | |||
900 | reenable: | ||
901 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
902 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
903 | reg | WM8900_REG_CLOCKING1_MCLK_SRC); | ||
904 | |||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
909 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
910 | { | ||
911 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); | ||
912 | } | ||
913 | |||
914 | static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
915 | int div_id, int div) | ||
916 | { | ||
917 | struct snd_soc_codec *codec = codec_dai->codec; | ||
918 | unsigned int reg; | ||
919 | |||
920 | switch (div_id) { | ||
921 | case WM8900_BCLK_DIV: | ||
922 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
923 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
924 | div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK)); | ||
925 | break; | ||
926 | case WM8900_OPCLK_DIV: | ||
927 | reg = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
928 | wm8900_write(codec, WM8900_REG_CLOCKING1, | ||
929 | div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK)); | ||
930 | break; | ||
931 | case WM8900_DAC_LRCLK: | ||
932 | reg = wm8900_read(codec, WM8900_REG_AUDIO4); | ||
933 | wm8900_write(codec, WM8900_REG_AUDIO4, | ||
934 | div | (reg & WM8900_LRC_MASK)); | ||
935 | break; | ||
936 | case WM8900_ADC_LRCLK: | ||
937 | reg = wm8900_read(codec, WM8900_REG_AUDIO3); | ||
938 | wm8900_write(codec, WM8900_REG_AUDIO3, | ||
939 | div | (reg & WM8900_LRC_MASK)); | ||
940 | break; | ||
941 | case WM8900_DAC_CLKDIV: | ||
942 | reg = wm8900_read(codec, WM8900_REG_CLOCKING2); | ||
943 | wm8900_write(codec, WM8900_REG_CLOCKING2, | ||
944 | div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV)); | ||
945 | break; | ||
946 | case WM8900_ADC_CLKDIV: | ||
947 | reg = wm8900_read(codec, WM8900_REG_CLOCKING2); | ||
948 | wm8900_write(codec, WM8900_REG_CLOCKING2, | ||
949 | div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV)); | ||
950 | break; | ||
951 | case WM8900_LRCLK_MODE: | ||
952 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
953 | wm8900_write(codec, WM8900_REG_DACCTRL, | ||
954 | div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE)); | ||
955 | break; | ||
956 | default: | ||
957 | return -EINVAL; | ||
958 | } | ||
959 | |||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | |||
964 | static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
965 | unsigned int fmt) | ||
966 | { | ||
967 | struct snd_soc_codec *codec = codec_dai->codec; | ||
968 | unsigned int clocking1, aif1, aif3, aif4; | ||
969 | |||
970 | clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1); | ||
971 | aif1 = wm8900_read(codec, WM8900_REG_AUDIO1); | ||
972 | aif3 = wm8900_read(codec, WM8900_REG_AUDIO3); | ||
973 | aif4 = wm8900_read(codec, WM8900_REG_AUDIO4); | ||
974 | |||
975 | /* set master/slave audio interface */ | ||
976 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
977 | case SND_SOC_DAIFMT_CBS_CFS: | ||
978 | clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; | ||
979 | aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
980 | aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; | ||
981 | break; | ||
982 | case SND_SOC_DAIFMT_CBS_CFM: | ||
983 | clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; | ||
984 | aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
985 | aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; | ||
986 | break; | ||
987 | case SND_SOC_DAIFMT_CBM_CFM: | ||
988 | clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; | ||
989 | aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
990 | aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; | ||
991 | break; | ||
992 | case SND_SOC_DAIFMT_CBM_CFS: | ||
993 | clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; | ||
994 | aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; | ||
995 | aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; | ||
996 | break; | ||
997 | default: | ||
998 | return -EINVAL; | ||
999 | } | ||
1000 | |||
1001 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1002 | case SND_SOC_DAIFMT_DSP_A: | ||
1003 | aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1004 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1005 | break; | ||
1006 | case SND_SOC_DAIFMT_DSP_B: | ||
1007 | aif1 |= WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1008 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1009 | break; | ||
1010 | case SND_SOC_DAIFMT_I2S: | ||
1011 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1012 | aif1 |= 0x10; | ||
1013 | break; | ||
1014 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1015 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1016 | break; | ||
1017 | case SND_SOC_DAIFMT_LEFT_J: | ||
1018 | aif1 &= ~WM8900_REG_AUDIO1_AIF_FMT_MASK; | ||
1019 | aif1 |= 0x8; | ||
1020 | break; | ||
1021 | default: | ||
1022 | return -EINVAL; | ||
1023 | } | ||
1024 | |||
1025 | /* Clock inversion */ | ||
1026 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1027 | case SND_SOC_DAIFMT_DSP_A: | ||
1028 | case SND_SOC_DAIFMT_DSP_B: | ||
1029 | /* frame inversion not valid for DSP modes */ | ||
1030 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1031 | case SND_SOC_DAIFMT_NB_NF: | ||
1032 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1033 | break; | ||
1034 | case SND_SOC_DAIFMT_IB_NF: | ||
1035 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1036 | break; | ||
1037 | default: | ||
1038 | return -EINVAL; | ||
1039 | } | ||
1040 | break; | ||
1041 | case SND_SOC_DAIFMT_I2S: | ||
1042 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1043 | case SND_SOC_DAIFMT_LEFT_J: | ||
1044 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1045 | case SND_SOC_DAIFMT_NB_NF: | ||
1046 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1047 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1048 | break; | ||
1049 | case SND_SOC_DAIFMT_IB_IF: | ||
1050 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1051 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1052 | break; | ||
1053 | case SND_SOC_DAIFMT_IB_NF: | ||
1054 | aif1 |= WM8900_REG_AUDIO1_BCLK_INV; | ||
1055 | aif1 &= ~WM8900_REG_AUDIO1_LRCLK_INV; | ||
1056 | break; | ||
1057 | case SND_SOC_DAIFMT_NB_IF: | ||
1058 | aif1 &= ~WM8900_REG_AUDIO1_BCLK_INV; | ||
1059 | aif1 |= WM8900_REG_AUDIO1_LRCLK_INV; | ||
1060 | break; | ||
1061 | default: | ||
1062 | return -EINVAL; | ||
1063 | } | ||
1064 | break; | ||
1065 | default: | ||
1066 | return -EINVAL; | ||
1067 | } | ||
1068 | |||
1069 | wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1); | ||
1070 | wm8900_write(codec, WM8900_REG_AUDIO1, aif1); | ||
1071 | wm8900_write(codec, WM8900_REG_AUDIO3, aif3); | ||
1072 | wm8900_write(codec, WM8900_REG_AUDIO4, aif4); | ||
1073 | |||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
1078 | { | ||
1079 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1080 | u16 reg; | ||
1081 | |||
1082 | reg = wm8900_read(codec, WM8900_REG_DACCTRL); | ||
1083 | |||
1084 | if (mute) | ||
1085 | reg |= WM8900_REG_DACCTRL_MUTE; | ||
1086 | else | ||
1087 | reg &= ~WM8900_REG_DACCTRL_MUTE; | ||
1088 | |||
1089 | wm8900_write(codec, WM8900_REG_DACCTRL, reg); | ||
1090 | |||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
1094 | #define WM8900_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
1095 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
1096 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
1097 | |||
1098 | #define WM8900_PCM_FORMATS \ | ||
1099 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | ||
1100 | SNDRV_PCM_FORMAT_S24_LE) | ||
1101 | |||
1102 | struct snd_soc_dai wm8900_dai = { | ||
1103 | .name = "WM8900 HiFi", | ||
1104 | .playback = { | ||
1105 | .stream_name = "HiFi Playback", | ||
1106 | .channels_min = 1, | ||
1107 | .channels_max = 2, | ||
1108 | .rates = WM8900_RATES, | ||
1109 | .formats = WM8900_PCM_FORMATS, | ||
1110 | }, | ||
1111 | .capture = { | ||
1112 | .stream_name = "HiFi Capture", | ||
1113 | .channels_min = 1, | ||
1114 | .channels_max = 2, | ||
1115 | .rates = WM8900_RATES, | ||
1116 | .formats = WM8900_PCM_FORMATS, | ||
1117 | }, | ||
1118 | .ops = { | ||
1119 | .hw_params = wm8900_hw_params, | ||
1120 | }, | ||
1121 | .dai_ops = { | ||
1122 | .set_clkdiv = wm8900_set_dai_clkdiv, | ||
1123 | .set_pll = wm8900_set_dai_pll, | ||
1124 | .set_fmt = wm8900_set_dai_fmt, | ||
1125 | .digital_mute = wm8900_digital_mute, | ||
1126 | }, | ||
1127 | }; | ||
1128 | EXPORT_SYMBOL_GPL(wm8900_dai); | ||
1129 | |||
1130 | static int wm8900_set_bias_level(struct snd_soc_codec *codec, | ||
1131 | enum snd_soc_bias_level level) | ||
1132 | { | ||
1133 | u16 reg; | ||
1134 | |||
1135 | switch (level) { | ||
1136 | case SND_SOC_BIAS_ON: | ||
1137 | /* Enable thermal shutdown */ | ||
1138 | reg = wm8900_read(codec, WM8900_REG_GPIO); | ||
1139 | wm8900_write(codec, WM8900_REG_GPIO, | ||
1140 | reg | WM8900_REG_GPIO_TEMP_ENA); | ||
1141 | reg = wm8900_read(codec, WM8900_REG_ADDCTL); | ||
1142 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1143 | reg | WM8900_REG_ADDCTL_TEMP_SD); | ||
1144 | break; | ||
1145 | |||
1146 | case SND_SOC_BIAS_PREPARE: | ||
1147 | break; | ||
1148 | |||
1149 | case SND_SOC_BIAS_STANDBY: | ||
1150 | /* Charge capacitors if initial power up */ | ||
1151 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1152 | /* STARTUP_BIAS_ENA on */ | ||
1153 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1154 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1155 | |||
1156 | /* Startup bias mode */ | ||
1157 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1158 | WM8900_REG_ADDCTL_BIAS_SRC | | ||
1159 | WM8900_REG_ADDCTL_VMID_SOFTST); | ||
1160 | |||
1161 | /* VMID 2x50k */ | ||
1162 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1163 | WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1); | ||
1164 | |||
1165 | /* Allow capacitors to charge */ | ||
1166 | schedule_timeout_interruptible(msecs_to_jiffies(400)); | ||
1167 | |||
1168 | /* Enable bias */ | ||
1169 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1170 | WM8900_REG_POWER1_STARTUP_BIAS_ENA | | ||
1171 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1172 | |||
1173 | wm8900_write(codec, WM8900_REG_ADDCTL, 0); | ||
1174 | |||
1175 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1176 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1177 | } | ||
1178 | |||
1179 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
1180 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1181 | (reg & WM8900_REG_POWER1_FLL_ENA) | | ||
1182 | WM8900_REG_POWER1_BIAS_ENA | 0x1); | ||
1183 | wm8900_write(codec, WM8900_REG_POWER2, | ||
1184 | WM8900_REG_POWER2_SYSCLK_ENA); | ||
1185 | wm8900_write(codec, WM8900_REG_POWER3, 0); | ||
1186 | break; | ||
1187 | |||
1188 | case SND_SOC_BIAS_OFF: | ||
1189 | /* Startup bias enable */ | ||
1190 | reg = wm8900_read(codec, WM8900_REG_POWER1); | ||
1191 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1192 | reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1193 | wm8900_write(codec, WM8900_REG_ADDCTL, | ||
1194 | WM8900_REG_ADDCTL_BIAS_SRC | | ||
1195 | WM8900_REG_ADDCTL_VMID_SOFTST); | ||
1196 | |||
1197 | /* Discharge caps */ | ||
1198 | wm8900_write(codec, WM8900_REG_POWER1, | ||
1199 | WM8900_REG_POWER1_STARTUP_BIAS_ENA); | ||
1200 | schedule_timeout_interruptible(msecs_to_jiffies(500)); | ||
1201 | |||
1202 | /* Remove clamp */ | ||
1203 | wm8900_write(codec, WM8900_REG_HPCTL1, 0); | ||
1204 | |||
1205 | /* Power down */ | ||
1206 | wm8900_write(codec, WM8900_REG_ADDCTL, 0); | ||
1207 | wm8900_write(codec, WM8900_REG_POWER1, 0); | ||
1208 | wm8900_write(codec, WM8900_REG_POWER2, 0); | ||
1209 | wm8900_write(codec, WM8900_REG_POWER3, 0); | ||
1210 | |||
1211 | /* Need to let things settle before stopping the clock | ||
1212 | * to ensure that restart works, see "Stopping the | ||
1213 | * master clock" in the datasheet. */ | ||
1214 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | ||
1215 | wm8900_write(codec, WM8900_REG_POWER2, | ||
1216 | WM8900_REG_POWER2_SYSCLK_ENA); | ||
1217 | break; | ||
1218 | } | ||
1219 | codec->bias_level = level; | ||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | static int wm8900_suspend(struct platform_device *pdev, pm_message_t state) | ||
1224 | { | ||
1225 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1226 | struct snd_soc_codec *codec = socdev->codec; | ||
1227 | struct wm8900_priv *wm8900 = codec->private_data; | ||
1228 | int fll_out = wm8900->fll_out; | ||
1229 | int fll_in = wm8900->fll_in; | ||
1230 | int ret; | ||
1231 | |||
1232 | /* Stop the FLL in an orderly fashion */ | ||
1233 | ret = wm8900_set_fll(codec, 0, 0, 0); | ||
1234 | if (ret != 0) { | ||
1235 | dev_err(&pdev->dev, "Failed to stop FLL\n"); | ||
1236 | return ret; | ||
1237 | } | ||
1238 | |||
1239 | wm8900->fll_out = fll_out; | ||
1240 | wm8900->fll_in = fll_in; | ||
1241 | |||
1242 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1243 | |||
1244 | return 0; | ||
1245 | } | ||
1246 | |||
1247 | static int wm8900_resume(struct platform_device *pdev) | ||
1248 | { | ||
1249 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1250 | struct snd_soc_codec *codec = socdev->codec; | ||
1251 | struct wm8900_priv *wm8900 = codec->private_data; | ||
1252 | u16 *cache; | ||
1253 | int i, ret; | ||
1254 | |||
1255 | cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults), | ||
1256 | GFP_KERNEL); | ||
1257 | |||
1258 | wm8900_reset(codec); | ||
1259 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1260 | |||
1261 | /* Restart the FLL? */ | ||
1262 | if (wm8900->fll_out) { | ||
1263 | int fll_out = wm8900->fll_out; | ||
1264 | int fll_in = wm8900->fll_in; | ||
1265 | |||
1266 | wm8900->fll_in = 0; | ||
1267 | wm8900->fll_out = 0; | ||
1268 | |||
1269 | ret = wm8900_set_fll(codec, 0, fll_in, fll_out); | ||
1270 | if (ret != 0) { | ||
1271 | dev_err(&pdev->dev, "Failed to restart FLL\n"); | ||
1272 | return ret; | ||
1273 | } | ||
1274 | } | ||
1275 | |||
1276 | if (cache) { | ||
1277 | for (i = 0; i < WM8900_MAXREG; i++) | ||
1278 | wm8900_write(codec, i, cache[i]); | ||
1279 | kfree(cache); | ||
1280 | } else | ||
1281 | dev_err(&pdev->dev, "Unable to allocate register cache\n"); | ||
1282 | |||
1283 | return 0; | ||
1284 | } | ||
1285 | |||
1286 | /* | ||
1287 | * initialise the WM8900 driver | ||
1288 | * register the mixer and dsp interfaces with the kernel | ||
1289 | */ | ||
1290 | static int wm8900_init(struct snd_soc_device *socdev) | ||
1291 | { | ||
1292 | struct snd_soc_codec *codec = socdev->codec; | ||
1293 | int ret = 0; | ||
1294 | unsigned int reg; | ||
1295 | struct i2c_client *i2c_client = socdev->codec->control_data; | ||
1296 | |||
1297 | codec->name = "WM8900"; | ||
1298 | codec->owner = THIS_MODULE; | ||
1299 | codec->read = wm8900_read; | ||
1300 | codec->write = wm8900_write; | ||
1301 | codec->dai = &wm8900_dai; | ||
1302 | codec->num_dai = 1; | ||
1303 | codec->reg_cache_size = WM8900_MAXREG; | ||
1304 | codec->reg_cache = kmemdup(wm8900_reg_defaults, | ||
1305 | sizeof(wm8900_reg_defaults), GFP_KERNEL); | ||
1306 | |||
1307 | if (codec->reg_cache == NULL) | ||
1308 | return -ENOMEM; | ||
1309 | |||
1310 | reg = wm8900_read(codec, WM8900_REG_ID); | ||
1311 | if (reg != 0x8900) { | ||
1312 | dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", | ||
1313 | reg); | ||
1314 | return -ENODEV; | ||
1315 | } | ||
1316 | |||
1317 | codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); | ||
1318 | if (codec->private_data == NULL) { | ||
1319 | ret = -ENOMEM; | ||
1320 | goto priv_err; | ||
1321 | } | ||
1322 | |||
1323 | /* Read back from the chip */ | ||
1324 | reg = wm8900_chip_read(codec, WM8900_REG_POWER1); | ||
1325 | reg = (reg >> 12) & 0xf; | ||
1326 | dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); | ||
1327 | |||
1328 | wm8900_reset(codec); | ||
1329 | |||
1330 | /* Latch the volume update bits */ | ||
1331 | wm8900_write(codec, WM8900_REG_LINVOL, | ||
1332 | wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); | ||
1333 | wm8900_write(codec, WM8900_REG_RINVOL, | ||
1334 | wm8900_read(codec, WM8900_REG_RINVOL) | 0x100); | ||
1335 | wm8900_write(codec, WM8900_REG_LOUT1CTL, | ||
1336 | wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100); | ||
1337 | wm8900_write(codec, WM8900_REG_ROUT1CTL, | ||
1338 | wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100); | ||
1339 | wm8900_write(codec, WM8900_REG_LOUT2CTL, | ||
1340 | wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100); | ||
1341 | wm8900_write(codec, WM8900_REG_ROUT2CTL, | ||
1342 | wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100); | ||
1343 | wm8900_write(codec, WM8900_REG_LDAC_DV, | ||
1344 | wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100); | ||
1345 | wm8900_write(codec, WM8900_REG_RDAC_DV, | ||
1346 | wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100); | ||
1347 | wm8900_write(codec, WM8900_REG_LADC_DV, | ||
1348 | wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100); | ||
1349 | wm8900_write(codec, WM8900_REG_RADC_DV, | ||
1350 | wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100); | ||
1351 | |||
1352 | /* Set the DAC and mixer output bias */ | ||
1353 | wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); | ||
1354 | |||
1355 | /* Register pcms */ | ||
1356 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1357 | if (ret < 0) { | ||
1358 | dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); | ||
1359 | goto pcm_err; | ||
1360 | } | ||
1361 | |||
1362 | /* Turn the chip on */ | ||
1363 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1364 | wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1365 | |||
1366 | wm8900_add_controls(codec); | ||
1367 | wm8900_add_widgets(codec); | ||
1368 | |||
1369 | ret = snd_soc_register_card(socdev); | ||
1370 | if (ret < 0) { | ||
1371 | dev_err(&i2c_client->dev, "Failed to register card\n"); | ||
1372 | goto card_err; | ||
1373 | } | ||
1374 | return ret; | ||
1375 | |||
1376 | card_err: | ||
1377 | snd_soc_free_pcms(socdev); | ||
1378 | snd_soc_dapm_free(socdev); | ||
1379 | pcm_err: | ||
1380 | kfree(codec->reg_cache); | ||
1381 | priv_err: | ||
1382 | kfree(codec->private_data); | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | static struct snd_soc_device *wm8900_socdev; | ||
1387 | |||
1388 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1389 | |||
1390 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1391 | |||
1392 | /* Magic definition of all other variables and things */ | ||
1393 | I2C_CLIENT_INSMOD; | ||
1394 | |||
1395 | static struct i2c_driver wm8900_i2c_driver; | ||
1396 | static struct i2c_client client_template; | ||
1397 | |||
1398 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
1399 | around */ | ||
1400 | static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1401 | { | ||
1402 | struct snd_soc_device *socdev = wm8900_socdev; | ||
1403 | struct wm8900_setup_data *setup = socdev->codec_data; | ||
1404 | struct snd_soc_codec *codec = socdev->codec; | ||
1405 | struct i2c_client *i2c; | ||
1406 | int ret; | ||
1407 | |||
1408 | if (addr != setup->i2c_address) | ||
1409 | return -ENODEV; | ||
1410 | |||
1411 | dev_err(&adap->dev, "Probe on %x\n", addr); | ||
1412 | |||
1413 | client_template.adapter = adap; | ||
1414 | client_template.addr = addr; | ||
1415 | |||
1416 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1417 | if (i2c == NULL) { | ||
1418 | kfree(codec); | ||
1419 | return -ENOMEM; | ||
1420 | } | ||
1421 | i2c_set_clientdata(i2c, codec); | ||
1422 | codec->control_data = i2c; | ||
1423 | |||
1424 | ret = i2c_attach_client(i2c); | ||
1425 | if (ret < 0) { | ||
1426 | dev_err(&adap->dev, | ||
1427 | "failed to attach codec at addr %x\n", addr); | ||
1428 | goto err; | ||
1429 | } | ||
1430 | |||
1431 | ret = wm8900_init(socdev); | ||
1432 | if (ret < 0) { | ||
1433 | dev_err(&adap->dev, "failed to initialise WM8900\n"); | ||
1434 | goto err; | ||
1435 | } | ||
1436 | return ret; | ||
1437 | |||
1438 | err: | ||
1439 | kfree(codec); | ||
1440 | kfree(i2c); | ||
1441 | return ret; | ||
1442 | } | ||
1443 | |||
1444 | static int wm8900_i2c_detach(struct i2c_client *client) | ||
1445 | { | ||
1446 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1447 | i2c_detach_client(client); | ||
1448 | kfree(codec->reg_cache); | ||
1449 | kfree(client); | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | static int wm8900_i2c_attach(struct i2c_adapter *adap) | ||
1454 | { | ||
1455 | return i2c_probe(adap, &addr_data, wm8900_codec_probe); | ||
1456 | } | ||
1457 | |||
1458 | /* corgi i2c codec control layer */ | ||
1459 | static struct i2c_driver wm8900_i2c_driver = { | ||
1460 | .driver = { | ||
1461 | .name = "WM8900 I2C codec", | ||
1462 | .owner = THIS_MODULE, | ||
1463 | }, | ||
1464 | .attach_adapter = wm8900_i2c_attach, | ||
1465 | .detach_client = wm8900_i2c_detach, | ||
1466 | .command = NULL, | ||
1467 | }; | ||
1468 | |||
1469 | static struct i2c_client client_template = { | ||
1470 | .name = "WM8900", | ||
1471 | .driver = &wm8900_i2c_driver, | ||
1472 | }; | ||
1473 | #endif | ||
1474 | |||
1475 | static int wm8900_probe(struct platform_device *pdev) | ||
1476 | { | ||
1477 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1478 | struct wm8900_setup_data *setup; | ||
1479 | struct snd_soc_codec *codec; | ||
1480 | int ret = 0; | ||
1481 | |||
1482 | dev_info(&pdev->dev, "WM8900 Audio Codec\n"); | ||
1483 | |||
1484 | setup = socdev->codec_data; | ||
1485 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1486 | if (codec == NULL) | ||
1487 | return -ENOMEM; | ||
1488 | |||
1489 | mutex_init(&codec->mutex); | ||
1490 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1491 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1492 | |||
1493 | socdev->codec = codec; | ||
1494 | |||
1495 | codec->set_bias_level = wm8900_set_bias_level; | ||
1496 | |||
1497 | wm8900_socdev = socdev; | ||
1498 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1499 | if (setup->i2c_address) { | ||
1500 | normal_i2c[0] = setup->i2c_address; | ||
1501 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1502 | ret = i2c_add_driver(&wm8900_i2c_driver); | ||
1503 | if (ret != 0) | ||
1504 | printk(KERN_ERR "can't add i2c driver"); | ||
1505 | } | ||
1506 | #else | ||
1507 | #error Non-I2C interfaces not yet supported | ||
1508 | #endif | ||
1509 | return ret; | ||
1510 | } | ||
1511 | |||
1512 | /* power down chip */ | ||
1513 | static int wm8900_remove(struct platform_device *pdev) | ||
1514 | { | ||
1515 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1516 | struct snd_soc_codec *codec = socdev->codec; | ||
1517 | |||
1518 | if (codec->control_data) | ||
1519 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1520 | |||
1521 | snd_soc_free_pcms(socdev); | ||
1522 | snd_soc_dapm_free(socdev); | ||
1523 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1524 | i2c_del_driver(&wm8900_i2c_driver); | ||
1525 | #endif | ||
1526 | kfree(codec); | ||
1527 | |||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | struct snd_soc_codec_device soc_codec_dev_wm8900 = { | ||
1532 | .probe = wm8900_probe, | ||
1533 | .remove = wm8900_remove, | ||
1534 | .suspend = wm8900_suspend, | ||
1535 | .resume = wm8900_resume, | ||
1536 | }; | ||
1537 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); | ||
1538 | |||
1539 | MODULE_DESCRIPTION("ASoC WM8900 driver"); | ||
1540 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); | ||
1541 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h new file mode 100644 index 000000000000..ba450d99e902 --- /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 000000000000..ce40d7877605 --- /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, 1), | ||
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, 1), | ||
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 000000000000..cec622f2f660 --- /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 000000000000..f41a578ddd4f --- /dev/null +++ b/sound/soc/codecs/wm8971.c | |||
@@ -0,0 +1,941 @@ | |||
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 WM8971_VERSION "0.9" | ||
33 | |||
34 | #define WM8971_REG_COUNT 43 | ||
35 | |||
36 | static struct workqueue_struct *wm8971_workq = NULL; | ||
37 | |||
38 | /* codec private data */ | ||
39 | struct wm8971_priv { | ||
40 | unsigned int sysclk; | ||
41 | }; | ||
42 | |||
43 | /* | ||
44 | * wm8971 register cache | ||
45 | * We can't read the WM8971 register space when we | ||
46 | * are using 2 wire for device control, so we cache them instead. | ||
47 | */ | ||
48 | static const u16 wm8971_reg[] = { | ||
49 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ | ||
50 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ | ||
51 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ | ||
52 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ | ||
53 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ | ||
54 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ | ||
55 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ | ||
56 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ | ||
57 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ | ||
58 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ | ||
59 | 0x0079, 0x0079, 0x0079, /* 40 */ | ||
60 | }; | ||
61 | |||
62 | static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec, | ||
63 | unsigned int reg) | ||
64 | { | ||
65 | u16 *cache = codec->reg_cache; | ||
66 | if (reg < WM8971_REG_COUNT) | ||
67 | return cache[reg]; | ||
68 | |||
69 | return -1; | ||
70 | } | ||
71 | |||
72 | static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec, | ||
73 | unsigned int reg, unsigned int value) | ||
74 | { | ||
75 | u16 *cache = codec->reg_cache; | ||
76 | if (reg < WM8971_REG_COUNT) | ||
77 | cache[reg] = value; | ||
78 | } | ||
79 | |||
80 | static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg, | ||
81 | unsigned int value) | ||
82 | { | ||
83 | u8 data[2]; | ||
84 | |||
85 | /* data is | ||
86 | * D15..D9 WM8753 register offset | ||
87 | * D8...D0 register data | ||
88 | */ | ||
89 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
90 | data[1] = value & 0x00ff; | ||
91 | |||
92 | wm8971_write_reg_cache (codec, reg, value); | ||
93 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
94 | return 0; | ||
95 | else | ||
96 | return -EIO; | ||
97 | } | ||
98 | |||
99 | #define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0) | ||
100 | |||
101 | /* WM8971 Controls */ | ||
102 | static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; | ||
103 | static const char *wm8971_bass_filter[] = { "130Hz @ 48kHz", | ||
104 | "200Hz @ 48kHz" }; | ||
105 | static const char *wm8971_treble[] = { "8kHz", "4kHz" }; | ||
106 | static const char *wm8971_alc_func[] = { "Off", "Right", "Left", "Stereo" }; | ||
107 | static const char *wm8971_ng_type[] = { "Constant PGA Gain", | ||
108 | "Mute ADC Output" }; | ||
109 | static const char *wm8971_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | ||
110 | static const char *wm8971_mono_mux[] = {"Stereo", "Mono (Left)", | ||
111 | "Mono (Right)", "Digital Mono"}; | ||
112 | static const char *wm8971_dac_phase[] = { "Non Inverted", "Inverted" }; | ||
113 | static const char *wm8971_lline_mux[] = {"Line", "NC", "NC", "PGA", | ||
114 | "Differential"}; | ||
115 | static const char *wm8971_rline_mux[] = {"Line", "Mic", "NC", "PGA", | ||
116 | "Differential"}; | ||
117 | static const char *wm8971_lpga_sel[] = {"Line", "NC", "NC", "Differential"}; | ||
118 | static const char *wm8971_rpga_sel[] = {"Line", "Mic", "NC", "Differential"}; | ||
119 | static const char *wm8971_adcpol[] = {"Normal", "L Invert", "R Invert", | ||
120 | "L + R Invert"}; | ||
121 | |||
122 | static const struct soc_enum wm8971_enum[] = { | ||
123 | SOC_ENUM_SINGLE(WM8971_BASS, 7, 2, wm8971_bass), /* 0 */ | ||
124 | SOC_ENUM_SINGLE(WM8971_BASS, 6, 2, wm8971_bass_filter), | ||
125 | SOC_ENUM_SINGLE(WM8971_TREBLE, 6, 2, wm8971_treble), | ||
126 | SOC_ENUM_SINGLE(WM8971_ALC1, 7, 4, wm8971_alc_func), | ||
127 | SOC_ENUM_SINGLE(WM8971_NGATE, 1, 2, wm8971_ng_type), /* 4 */ | ||
128 | SOC_ENUM_SINGLE(WM8971_ADCDAC, 1, 4, wm8971_deemp), | ||
129 | SOC_ENUM_SINGLE(WM8971_ADCTL1, 4, 4, wm8971_mono_mux), | ||
130 | SOC_ENUM_SINGLE(WM8971_ADCTL1, 1, 2, wm8971_dac_phase), | ||
131 | SOC_ENUM_SINGLE(WM8971_LOUTM1, 0, 5, wm8971_lline_mux), /* 8 */ | ||
132 | SOC_ENUM_SINGLE(WM8971_ROUTM1, 0, 5, wm8971_rline_mux), | ||
133 | SOC_ENUM_SINGLE(WM8971_LADCIN, 6, 4, wm8971_lpga_sel), | ||
134 | SOC_ENUM_SINGLE(WM8971_RADCIN, 6, 4, wm8971_rpga_sel), | ||
135 | SOC_ENUM_SINGLE(WM8971_ADCDAC, 5, 4, wm8971_adcpol), /* 12 */ | ||
136 | SOC_ENUM_SINGLE(WM8971_ADCIN, 6, 4, wm8971_mono_mux), | ||
137 | }; | ||
138 | |||
139 | static const struct snd_kcontrol_new wm8971_snd_controls[] = { | ||
140 | SOC_DOUBLE_R("Capture Volume", WM8971_LINVOL, WM8971_RINVOL, 0, 63, 0), | ||
141 | SOC_DOUBLE_R("Capture ZC Switch", WM8971_LINVOL, WM8971_RINVOL, | ||
142 | 6, 1, 0), | ||
143 | SOC_DOUBLE_R("Capture Switch", WM8971_LINVOL, WM8971_RINVOL, 7, 1, 1), | ||
144 | |||
145 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8971_LOUT1V, | ||
146 | WM8971_ROUT1V, 7, 1, 0), | ||
147 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8971_LOUT2V, | ||
148 | WM8971_ROUT2V, 7, 1, 0), | ||
149 | SOC_SINGLE("Mono Playback ZC Switch", WM8971_MOUTV, 7, 1, 0), | ||
150 | |||
151 | SOC_DOUBLE_R("PCM Volume", WM8971_LDAC, WM8971_RDAC, 0, 255, 0), | ||
152 | |||
153 | SOC_DOUBLE_R("Bypass Left Playback Volume", WM8971_LOUTM1, | ||
154 | WM8971_LOUTM2, 4, 7, 1), | ||
155 | SOC_DOUBLE_R("Bypass Right Playback Volume", WM8971_ROUTM1, | ||
156 | WM8971_ROUTM2, 4, 7, 1), | ||
157 | SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8971_MOUTM1, | ||
158 | WM8971_MOUTM2, 4, 7, 1), | ||
159 | |||
160 | SOC_DOUBLE_R("Headphone Playback Volume", WM8971_LOUT1V, | ||
161 | WM8971_ROUT1V, 0, 127, 0), | ||
162 | SOC_DOUBLE_R("Speaker Playback Volume", WM8971_LOUT2V, | ||
163 | WM8971_ROUT2V, 0, 127, 0), | ||
164 | |||
165 | SOC_ENUM("Bass Boost", wm8971_enum[0]), | ||
166 | SOC_ENUM("Bass Filter", wm8971_enum[1]), | ||
167 | SOC_SINGLE("Bass Volume", WM8971_BASS, 0, 7, 1), | ||
168 | |||
169 | SOC_SINGLE("Treble Volume", WM8971_TREBLE, 0, 7, 0), | ||
170 | SOC_ENUM("Treble Cut-off", wm8971_enum[2]), | ||
171 | |||
172 | SOC_SINGLE("Capture Filter Switch", WM8971_ADCDAC, 0, 1, 1), | ||
173 | |||
174 | SOC_SINGLE("ALC Target Volume", WM8971_ALC1, 0, 7, 0), | ||
175 | SOC_SINGLE("ALC Max Volume", WM8971_ALC1, 4, 7, 0), | ||
176 | |||
177 | SOC_SINGLE("ALC Capture Target Volume", WM8971_ALC1, 0, 7, 0), | ||
178 | SOC_SINGLE("ALC Capture Max Volume", WM8971_ALC1, 4, 7, 0), | ||
179 | SOC_ENUM("ALC Capture Function", wm8971_enum[3]), | ||
180 | SOC_SINGLE("ALC Capture ZC Switch", WM8971_ALC2, 7, 1, 0), | ||
181 | SOC_SINGLE("ALC Capture Hold Time", WM8971_ALC2, 0, 15, 0), | ||
182 | SOC_SINGLE("ALC Capture Decay Time", WM8971_ALC3, 4, 15, 0), | ||
183 | SOC_SINGLE("ALC Capture Attack Time", WM8971_ALC3, 0, 15, 0), | ||
184 | SOC_SINGLE("ALC Capture NG Threshold", WM8971_NGATE, 3, 31, 0), | ||
185 | SOC_ENUM("ALC Capture NG Type", wm8971_enum[4]), | ||
186 | SOC_SINGLE("ALC Capture NG Switch", WM8971_NGATE, 0, 1, 0), | ||
187 | |||
188 | SOC_SINGLE("Capture 6dB Attenuate", WM8971_ADCDAC, 8, 1, 0), | ||
189 | SOC_SINGLE("Playback 6dB Attenuate", WM8971_ADCDAC, 7, 1, 0), | ||
190 | |||
191 | SOC_ENUM("Playback De-emphasis", wm8971_enum[5]), | ||
192 | SOC_ENUM("Playback Function", wm8971_enum[6]), | ||
193 | SOC_ENUM("Playback Phase", wm8971_enum[7]), | ||
194 | |||
195 | SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0), | ||
196 | }; | ||
197 | |||
198 | /* add non-DAPM controls */ | ||
199 | static int wm8971_add_controls(struct snd_soc_codec *codec) | ||
200 | { | ||
201 | int err, i; | ||
202 | |||
203 | for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) { | ||
204 | err = snd_ctl_add(codec->card, | ||
205 | snd_soc_cnew(&wm8971_snd_controls[i], | ||
206 | codec, NULL)); | ||
207 | if (err < 0) | ||
208 | return err; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * DAPM Controls | ||
215 | */ | ||
216 | |||
217 | /* Left Mixer */ | ||
218 | static const struct snd_kcontrol_new wm8971_left_mixer_controls[] = { | ||
219 | SOC_DAPM_SINGLE("Playback Switch", WM8971_LOUTM1, 8, 1, 0), | ||
220 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_LOUTM1, 7, 1, 0), | ||
221 | SOC_DAPM_SINGLE("Right Playback Switch", WM8971_LOUTM2, 8, 1, 0), | ||
222 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_LOUTM2, 7, 1, 0), | ||
223 | }; | ||
224 | |||
225 | /* Right Mixer */ | ||
226 | static const struct snd_kcontrol_new wm8971_right_mixer_controls[] = { | ||
227 | SOC_DAPM_SINGLE("Left Playback Switch", WM8971_ROUTM1, 8, 1, 0), | ||
228 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_ROUTM1, 7, 1, 0), | ||
229 | SOC_DAPM_SINGLE("Playback Switch", WM8971_ROUTM2, 8, 1, 0), | ||
230 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_ROUTM2, 7, 1, 0), | ||
231 | }; | ||
232 | |||
233 | /* Mono Mixer */ | ||
234 | static const struct snd_kcontrol_new wm8971_mono_mixer_controls[] = { | ||
235 | SOC_DAPM_SINGLE("Left Playback Switch", WM8971_MOUTM1, 8, 1, 0), | ||
236 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8971_MOUTM1, 7, 1, 0), | ||
237 | SOC_DAPM_SINGLE("Right Playback Switch", WM8971_MOUTM2, 8, 1, 0), | ||
238 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8971_MOUTM2, 7, 1, 0), | ||
239 | }; | ||
240 | |||
241 | /* Left Line Mux */ | ||
242 | static const struct snd_kcontrol_new wm8971_left_line_controls = | ||
243 | SOC_DAPM_ENUM("Route", wm8971_enum[8]); | ||
244 | |||
245 | /* Right Line Mux */ | ||
246 | static const struct snd_kcontrol_new wm8971_right_line_controls = | ||
247 | SOC_DAPM_ENUM("Route", wm8971_enum[9]); | ||
248 | |||
249 | /* Left PGA Mux */ | ||
250 | static const struct snd_kcontrol_new wm8971_left_pga_controls = | ||
251 | SOC_DAPM_ENUM("Route", wm8971_enum[10]); | ||
252 | |||
253 | /* Right PGA Mux */ | ||
254 | static const struct snd_kcontrol_new wm8971_right_pga_controls = | ||
255 | SOC_DAPM_ENUM("Route", wm8971_enum[11]); | ||
256 | |||
257 | /* Mono ADC Mux */ | ||
258 | static const struct snd_kcontrol_new wm8971_monomux_controls = | ||
259 | SOC_DAPM_ENUM("Route", wm8971_enum[13]); | ||
260 | |||
261 | static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = { | ||
262 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | ||
263 | &wm8971_left_mixer_controls[0], | ||
264 | ARRAY_SIZE(wm8971_left_mixer_controls)), | ||
265 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | ||
266 | &wm8971_right_mixer_controls[0], | ||
267 | ARRAY_SIZE(wm8971_right_mixer_controls)), | ||
268 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8971_PWR2, 2, 0, | ||
269 | &wm8971_mono_mixer_controls[0], | ||
270 | ARRAY_SIZE(wm8971_mono_mixer_controls)), | ||
271 | |||
272 | SND_SOC_DAPM_PGA("Right Out 2", WM8971_PWR2, 3, 0, NULL, 0), | ||
273 | SND_SOC_DAPM_PGA("Left Out 2", WM8971_PWR2, 4, 0, NULL, 0), | ||
274 | SND_SOC_DAPM_PGA("Right Out 1", WM8971_PWR2, 5, 0, NULL, 0), | ||
275 | SND_SOC_DAPM_PGA("Left Out 1", WM8971_PWR2, 6, 0, NULL, 0), | ||
276 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8971_PWR2, 7, 0), | ||
277 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0), | ||
278 | SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0), | ||
279 | |||
280 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0), | ||
281 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0), | ||
282 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0), | ||
283 | |||
284 | SND_SOC_DAPM_MUX("Left PGA Mux", WM8971_PWR1, 5, 0, | ||
285 | &wm8971_left_pga_controls), | ||
286 | SND_SOC_DAPM_MUX("Right PGA Mux", WM8971_PWR1, 4, 0, | ||
287 | &wm8971_right_pga_controls), | ||
288 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | ||
289 | &wm8971_left_line_controls), | ||
290 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | ||
291 | &wm8971_right_line_controls), | ||
292 | |||
293 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | ||
294 | &wm8971_monomux_controls), | ||
295 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | ||
296 | &wm8971_monomux_controls), | ||
297 | |||
298 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
299 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
300 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
301 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
302 | SND_SOC_DAPM_OUTPUT("MONO"), | ||
303 | |||
304 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
305 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
306 | SND_SOC_DAPM_INPUT("MIC"), | ||
307 | }; | ||
308 | |||
309 | static const struct snd_soc_dapm_route audio_map[] = { | ||
310 | /* left mixer */ | ||
311 | {"Left Mixer", "Playback Switch", "Left DAC"}, | ||
312 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
313 | {"Left Mixer", "Right Playback Switch", "Right DAC"}, | ||
314 | {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
315 | |||
316 | /* right mixer */ | ||
317 | {"Right Mixer", "Left Playback Switch", "Left DAC"}, | ||
318 | {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
319 | {"Right Mixer", "Playback Switch", "Right DAC"}, | ||
320 | {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
321 | |||
322 | /* left out 1 */ | ||
323 | {"Left Out 1", NULL, "Left Mixer"}, | ||
324 | {"LOUT1", NULL, "Left Out 1"}, | ||
325 | |||
326 | /* left out 2 */ | ||
327 | {"Left Out 2", NULL, "Left Mixer"}, | ||
328 | {"LOUT2", NULL, "Left Out 2"}, | ||
329 | |||
330 | /* right out 1 */ | ||
331 | {"Right Out 1", NULL, "Right Mixer"}, | ||
332 | {"ROUT1", NULL, "Right Out 1"}, | ||
333 | |||
334 | /* right out 2 */ | ||
335 | {"Right Out 2", NULL, "Right Mixer"}, | ||
336 | {"ROUT2", NULL, "Right Out 2"}, | ||
337 | |||
338 | /* mono mixer */ | ||
339 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, | ||
340 | {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, | ||
341 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, | ||
342 | {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, | ||
343 | |||
344 | /* mono out */ | ||
345 | {"Mono Out", NULL, "Mono Mixer"}, | ||
346 | {"MONO1", NULL, "Mono Out"}, | ||
347 | |||
348 | /* Left Line Mux */ | ||
349 | {"Left Line Mux", "Line", "LINPUT1"}, | ||
350 | {"Left Line Mux", "PGA", "Left PGA Mux"}, | ||
351 | {"Left Line Mux", "Differential", "Differential Mux"}, | ||
352 | |||
353 | /* Right Line Mux */ | ||
354 | {"Right Line Mux", "Line", "RINPUT1"}, | ||
355 | {"Right Line Mux", "Mic", "MIC"}, | ||
356 | {"Right Line Mux", "PGA", "Right PGA Mux"}, | ||
357 | {"Right Line Mux", "Differential", "Differential Mux"}, | ||
358 | |||
359 | /* Left PGA Mux */ | ||
360 | {"Left PGA Mux", "Line", "LINPUT1"}, | ||
361 | {"Left PGA Mux", "Differential", "Differential Mux"}, | ||
362 | |||
363 | /* Right PGA Mux */ | ||
364 | {"Right PGA Mux", "Line", "RINPUT1"}, | ||
365 | {"Right PGA Mux", "Differential", "Differential Mux"}, | ||
366 | |||
367 | /* Differential Mux */ | ||
368 | {"Differential Mux", "Line", "LINPUT1"}, | ||
369 | {"Differential Mux", "Line", "RINPUT1"}, | ||
370 | |||
371 | /* Left ADC Mux */ | ||
372 | {"Left ADC Mux", "Stereo", "Left PGA Mux"}, | ||
373 | {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, | ||
374 | {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, | ||
375 | |||
376 | /* Right ADC Mux */ | ||
377 | {"Right ADC Mux", "Stereo", "Right PGA Mux"}, | ||
378 | {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, | ||
379 | {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, | ||
380 | |||
381 | /* ADC */ | ||
382 | {"Left ADC", NULL, "Left ADC Mux"}, | ||
383 | {"Right ADC", NULL, "Right ADC Mux"}, | ||
384 | }; | ||
385 | |||
386 | static int wm8971_add_widgets(struct snd_soc_codec *codec) | ||
387 | { | ||
388 | snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets, | ||
389 | ARRAY_SIZE(wm8971_dapm_widgets)); | ||
390 | |||
391 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
392 | |||
393 | snd_soc_dapm_new_widgets(codec); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | struct _coeff_div { | ||
399 | u32 mclk; | ||
400 | u32 rate; | ||
401 | u16 fs; | ||
402 | u8 sr:5; | ||
403 | u8 usb:1; | ||
404 | }; | ||
405 | |||
406 | /* codec hifi mclk clock divider coefficients */ | ||
407 | static const struct _coeff_div coeff_div[] = { | ||
408 | /* 8k */ | ||
409 | {12288000, 8000, 1536, 0x6, 0x0}, | ||
410 | {11289600, 8000, 1408, 0x16, 0x0}, | ||
411 | {18432000, 8000, 2304, 0x7, 0x0}, | ||
412 | {16934400, 8000, 2112, 0x17, 0x0}, | ||
413 | {12000000, 8000, 1500, 0x6, 0x1}, | ||
414 | |||
415 | /* 11.025k */ | ||
416 | {11289600, 11025, 1024, 0x18, 0x0}, | ||
417 | {16934400, 11025, 1536, 0x19, 0x0}, | ||
418 | {12000000, 11025, 1088, 0x19, 0x1}, | ||
419 | |||
420 | /* 16k */ | ||
421 | {12288000, 16000, 768, 0xa, 0x0}, | ||
422 | {18432000, 16000, 1152, 0xb, 0x0}, | ||
423 | {12000000, 16000, 750, 0xa, 0x1}, | ||
424 | |||
425 | /* 22.05k */ | ||
426 | {11289600, 22050, 512, 0x1a, 0x0}, | ||
427 | {16934400, 22050, 768, 0x1b, 0x0}, | ||
428 | {12000000, 22050, 544, 0x1b, 0x1}, | ||
429 | |||
430 | /* 32k */ | ||
431 | {12288000, 32000, 384, 0xc, 0x0}, | ||
432 | {18432000, 32000, 576, 0xd, 0x0}, | ||
433 | {12000000, 32000, 375, 0xa, 0x1}, | ||
434 | |||
435 | /* 44.1k */ | ||
436 | {11289600, 44100, 256, 0x10, 0x0}, | ||
437 | {16934400, 44100, 384, 0x11, 0x0}, | ||
438 | {12000000, 44100, 272, 0x11, 0x1}, | ||
439 | |||
440 | /* 48k */ | ||
441 | {12288000, 48000, 256, 0x0, 0x0}, | ||
442 | {18432000, 48000, 384, 0x1, 0x0}, | ||
443 | {12000000, 48000, 250, 0x0, 0x1}, | ||
444 | |||
445 | /* 88.2k */ | ||
446 | {11289600, 88200, 128, 0x1e, 0x0}, | ||
447 | {16934400, 88200, 192, 0x1f, 0x0}, | ||
448 | {12000000, 88200, 136, 0x1f, 0x1}, | ||
449 | |||
450 | /* 96k */ | ||
451 | {12288000, 96000, 128, 0xe, 0x0}, | ||
452 | {18432000, 96000, 192, 0xf, 0x0}, | ||
453 | {12000000, 96000, 125, 0xe, 0x1}, | ||
454 | }; | ||
455 | |||
456 | static int get_coeff(int mclk, int rate) | ||
457 | { | ||
458 | int i; | ||
459 | |||
460 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
461 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
462 | return i; | ||
463 | } | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | |||
467 | static int wm8971_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
468 | int clk_id, unsigned int freq, int dir) | ||
469 | { | ||
470 | struct snd_soc_codec *codec = codec_dai->codec; | ||
471 | struct wm8971_priv *wm8971 = codec->private_data; | ||
472 | |||
473 | switch (freq) { | ||
474 | case 11289600: | ||
475 | case 12000000: | ||
476 | case 12288000: | ||
477 | case 16934400: | ||
478 | case 18432000: | ||
479 | wm8971->sysclk = freq; | ||
480 | return 0; | ||
481 | } | ||
482 | return -EINVAL; | ||
483 | } | ||
484 | |||
485 | static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
486 | unsigned int fmt) | ||
487 | { | ||
488 | struct snd_soc_codec *codec = codec_dai->codec; | ||
489 | u16 iface = 0; | ||
490 | |||
491 | /* set master/slave audio interface */ | ||
492 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
493 | case SND_SOC_DAIFMT_CBM_CFM: | ||
494 | iface = 0x0040; | ||
495 | break; | ||
496 | case SND_SOC_DAIFMT_CBS_CFS: | ||
497 | break; | ||
498 | default: | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | |||
502 | /* interface format */ | ||
503 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
504 | case SND_SOC_DAIFMT_I2S: | ||
505 | iface |= 0x0002; | ||
506 | break; | ||
507 | case SND_SOC_DAIFMT_RIGHT_J: | ||
508 | break; | ||
509 | case SND_SOC_DAIFMT_LEFT_J: | ||
510 | iface |= 0x0001; | ||
511 | break; | ||
512 | case SND_SOC_DAIFMT_DSP_A: | ||
513 | iface |= 0x0003; | ||
514 | break; | ||
515 | case SND_SOC_DAIFMT_DSP_B: | ||
516 | iface |= 0x0013; | ||
517 | break; | ||
518 | default: | ||
519 | return -EINVAL; | ||
520 | } | ||
521 | |||
522 | /* clock inversion */ | ||
523 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
524 | case SND_SOC_DAIFMT_NB_NF: | ||
525 | break; | ||
526 | case SND_SOC_DAIFMT_IB_IF: | ||
527 | iface |= 0x0090; | ||
528 | break; | ||
529 | case SND_SOC_DAIFMT_IB_NF: | ||
530 | iface |= 0x0080; | ||
531 | break; | ||
532 | case SND_SOC_DAIFMT_NB_IF: | ||
533 | iface |= 0x0010; | ||
534 | break; | ||
535 | default: | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | wm8971_write(codec, WM8971_IFACE, iface); | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, | ||
544 | struct snd_pcm_hw_params *params) | ||
545 | { | ||
546 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
547 | struct snd_soc_device *socdev = rtd->socdev; | ||
548 | struct snd_soc_codec *codec = socdev->codec; | ||
549 | struct wm8971_priv *wm8971 = codec->private_data; | ||
550 | u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; | ||
551 | u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; | ||
552 | int coeff = get_coeff(wm8971->sysclk, params_rate(params)); | ||
553 | |||
554 | /* bit size */ | ||
555 | switch (params_format(params)) { | ||
556 | case SNDRV_PCM_FORMAT_S16_LE: | ||
557 | break; | ||
558 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
559 | iface |= 0x0004; | ||
560 | break; | ||
561 | case SNDRV_PCM_FORMAT_S24_LE: | ||
562 | iface |= 0x0008; | ||
563 | break; | ||
564 | case SNDRV_PCM_FORMAT_S32_LE: | ||
565 | iface |= 0x000c; | ||
566 | break; | ||
567 | } | ||
568 | |||
569 | /* set iface & srate */ | ||
570 | wm8971_write(codec, WM8971_IFACE, iface); | ||
571 | if (coeff >= 0) | ||
572 | wm8971_write(codec, WM8971_SRATE, srate | | ||
573 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int wm8971_mute(struct snd_soc_dai *dai, int mute) | ||
579 | { | ||
580 | struct snd_soc_codec *codec = dai->codec; | ||
581 | u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7; | ||
582 | |||
583 | if (mute) | ||
584 | wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8); | ||
585 | else | ||
586 | wm8971_write(codec, WM8971_ADCDAC, mute_reg); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int wm8971_set_bias_level(struct snd_soc_codec *codec, | ||
591 | enum snd_soc_bias_level level) | ||
592 | { | ||
593 | u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
594 | |||
595 | switch (level) { | ||
596 | case SND_SOC_BIAS_ON: | ||
597 | /* set vmid to 50k and unmute dac */ | ||
598 | wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); | ||
599 | break; | ||
600 | case SND_SOC_BIAS_PREPARE: | ||
601 | break; | ||
602 | case SND_SOC_BIAS_STANDBY: | ||
603 | /* mute dac and set vmid to 500k, enable VREF */ | ||
604 | wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140); | ||
605 | break; | ||
606 | case SND_SOC_BIAS_OFF: | ||
607 | wm8971_write(codec, WM8971_PWR1, 0x0001); | ||
608 | break; | ||
609 | } | ||
610 | codec->bias_level = level; | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | #define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
615 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
616 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
617 | |||
618 | #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
619 | SNDRV_PCM_FMTBIT_S24_LE) | ||
620 | |||
621 | struct snd_soc_dai wm8971_dai = { | ||
622 | .name = "WM8971", | ||
623 | .playback = { | ||
624 | .stream_name = "Playback", | ||
625 | .channels_min = 1, | ||
626 | .channels_max = 2, | ||
627 | .rates = WM8971_RATES, | ||
628 | .formats = WM8971_FORMATS,}, | ||
629 | .capture = { | ||
630 | .stream_name = "Capture", | ||
631 | .channels_min = 1, | ||
632 | .channels_max = 2, | ||
633 | .rates = WM8971_RATES, | ||
634 | .formats = WM8971_FORMATS,}, | ||
635 | .ops = { | ||
636 | .hw_params = wm8971_pcm_hw_params, | ||
637 | }, | ||
638 | .dai_ops = { | ||
639 | .digital_mute = wm8971_mute, | ||
640 | .set_fmt = wm8971_set_dai_fmt, | ||
641 | .set_sysclk = wm8971_set_dai_sysclk, | ||
642 | }, | ||
643 | }; | ||
644 | EXPORT_SYMBOL_GPL(wm8971_dai); | ||
645 | |||
646 | static void wm8971_work(struct work_struct *work) | ||
647 | { | ||
648 | struct snd_soc_codec *codec = | ||
649 | container_of(work, struct snd_soc_codec, delayed_work.work); | ||
650 | wm8971_set_bias_level(codec, codec->bias_level); | ||
651 | } | ||
652 | |||
653 | static int wm8971_suspend(struct platform_device *pdev, pm_message_t state) | ||
654 | { | ||
655 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
656 | struct snd_soc_codec *codec = socdev->codec; | ||
657 | |||
658 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int wm8971_resume(struct platform_device *pdev) | ||
663 | { | ||
664 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
665 | struct snd_soc_codec *codec = socdev->codec; | ||
666 | int i; | ||
667 | u8 data[2]; | ||
668 | u16 *cache = codec->reg_cache; | ||
669 | u16 reg; | ||
670 | |||
671 | /* Sync reg_cache with the hardware */ | ||
672 | for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) { | ||
673 | if (i + 1 == WM8971_RESET) | ||
674 | continue; | ||
675 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
676 | data[1] = cache[i] & 0x00ff; | ||
677 | codec->hw_write(codec->control_data, data, 2); | ||
678 | } | ||
679 | |||
680 | wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
681 | |||
682 | /* charge wm8971 caps */ | ||
683 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | ||
684 | reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
685 | wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); | ||
686 | codec->bias_level = SND_SOC_BIAS_ON; | ||
687 | queue_delayed_work(wm8971_workq, &codec->delayed_work, | ||
688 | msecs_to_jiffies(1000)); | ||
689 | } | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int wm8971_init(struct snd_soc_device *socdev) | ||
695 | { | ||
696 | struct snd_soc_codec *codec = socdev->codec; | ||
697 | int reg, ret = 0; | ||
698 | |||
699 | codec->name = "WM8971"; | ||
700 | codec->owner = THIS_MODULE; | ||
701 | codec->read = wm8971_read_reg_cache; | ||
702 | codec->write = wm8971_write; | ||
703 | codec->set_bias_level = wm8971_set_bias_level; | ||
704 | codec->dai = &wm8971_dai; | ||
705 | codec->reg_cache_size = ARRAY_SIZE(wm8971_reg); | ||
706 | codec->num_dai = 1; | ||
707 | codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL); | ||
708 | |||
709 | if (codec->reg_cache == NULL) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | wm8971_reset(codec); | ||
713 | |||
714 | /* register pcms */ | ||
715 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
716 | if (ret < 0) { | ||
717 | printk(KERN_ERR "wm8971: failed to create pcms\n"); | ||
718 | goto pcm_err; | ||
719 | } | ||
720 | |||
721 | /* charge output caps - set vmid to 5k for quick power up */ | ||
722 | reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; | ||
723 | wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); | ||
724 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
725 | queue_delayed_work(wm8971_workq, &codec->delayed_work, | ||
726 | msecs_to_jiffies(1000)); | ||
727 | |||
728 | /* set the update bits */ | ||
729 | reg = wm8971_read_reg_cache(codec, WM8971_LDAC); | ||
730 | wm8971_write(codec, WM8971_LDAC, reg | 0x0100); | ||
731 | reg = wm8971_read_reg_cache(codec, WM8971_RDAC); | ||
732 | wm8971_write(codec, WM8971_RDAC, reg | 0x0100); | ||
733 | |||
734 | reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V); | ||
735 | wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100); | ||
736 | reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V); | ||
737 | wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100); | ||
738 | |||
739 | reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V); | ||
740 | wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100); | ||
741 | reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V); | ||
742 | wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100); | ||
743 | |||
744 | reg = wm8971_read_reg_cache(codec, WM8971_LINVOL); | ||
745 | wm8971_write(codec, WM8971_LINVOL, reg | 0x0100); | ||
746 | reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); | ||
747 | wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); | ||
748 | |||
749 | wm8971_add_controls(codec); | ||
750 | wm8971_add_widgets(codec); | ||
751 | ret = snd_soc_register_card(socdev); | ||
752 | if (ret < 0) { | ||
753 | printk(KERN_ERR "wm8971: failed to register card\n"); | ||
754 | goto card_err; | ||
755 | } | ||
756 | return ret; | ||
757 | |||
758 | card_err: | ||
759 | snd_soc_free_pcms(socdev); | ||
760 | snd_soc_dapm_free(socdev); | ||
761 | pcm_err: | ||
762 | kfree(codec->reg_cache); | ||
763 | return ret; | ||
764 | } | ||
765 | |||
766 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
767 | around */ | ||
768 | static struct snd_soc_device *wm8971_socdev; | ||
769 | |||
770 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
771 | |||
772 | static int wm8971_i2c_probe(struct i2c_client *i2c, | ||
773 | const struct i2c_device_id *id) | ||
774 | { | ||
775 | struct snd_soc_device *socdev = wm8971_socdev; | ||
776 | struct snd_soc_codec *codec = socdev->codec; | ||
777 | int ret; | ||
778 | |||
779 | i2c_set_clientdata(i2c, codec); | ||
780 | |||
781 | codec->control_data = i2c; | ||
782 | |||
783 | ret = wm8971_init(socdev); | ||
784 | if (ret < 0) | ||
785 | pr_err("failed to initialise WM8971\n"); | ||
786 | |||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | static int wm8971_i2c_remove(struct i2c_client *client) | ||
791 | { | ||
792 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
793 | kfree(codec->reg_cache); | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static const struct i2c_device_id wm8971_i2c_id[] = { | ||
798 | { "wm8971", 0 }, | ||
799 | { } | ||
800 | }; | ||
801 | MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id); | ||
802 | |||
803 | static struct i2c_driver wm8971_i2c_driver = { | ||
804 | .driver = { | ||
805 | .name = "WM8971 I2C Codec", | ||
806 | .owner = THIS_MODULE, | ||
807 | }, | ||
808 | .probe = wm8971_i2c_probe, | ||
809 | .remove = wm8971_i2c_remove, | ||
810 | .id_table = wm8971_i2c_id, | ||
811 | }; | ||
812 | |||
813 | static int wm8971_add_i2c_device(struct platform_device *pdev, | ||
814 | const struct wm8971_setup_data *setup) | ||
815 | { | ||
816 | struct i2c_board_info info; | ||
817 | struct i2c_adapter *adapter; | ||
818 | struct i2c_client *client; | ||
819 | int ret; | ||
820 | |||
821 | ret = i2c_add_driver(&wm8971_i2c_driver); | ||
822 | if (ret != 0) { | ||
823 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
824 | return ret; | ||
825 | } | ||
826 | |||
827 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
828 | info.addr = setup->i2c_address; | ||
829 | strlcpy(info.type, "wm8971", I2C_NAME_SIZE); | ||
830 | |||
831 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
832 | if (!adapter) { | ||
833 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
834 | setup->i2c_bus); | ||
835 | goto err_driver; | ||
836 | } | ||
837 | |||
838 | client = i2c_new_device(adapter, &info); | ||
839 | i2c_put_adapter(adapter); | ||
840 | if (!client) { | ||
841 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
842 | (unsigned int)info.addr); | ||
843 | goto err_driver; | ||
844 | } | ||
845 | |||
846 | return 0; | ||
847 | |||
848 | err_driver: | ||
849 | i2c_del_driver(&wm8971_i2c_driver); | ||
850 | return -ENODEV; | ||
851 | } | ||
852 | |||
853 | #endif | ||
854 | |||
855 | static int wm8971_probe(struct platform_device *pdev) | ||
856 | { | ||
857 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
858 | struct wm8971_setup_data *setup; | ||
859 | struct snd_soc_codec *codec; | ||
860 | struct wm8971_priv *wm8971; | ||
861 | int ret = 0; | ||
862 | |||
863 | pr_info("WM8971 Audio Codec %s", WM8971_VERSION); | ||
864 | |||
865 | setup = socdev->codec_data; | ||
866 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
867 | if (codec == NULL) | ||
868 | return -ENOMEM; | ||
869 | |||
870 | wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL); | ||
871 | if (wm8971 == NULL) { | ||
872 | kfree(codec); | ||
873 | return -ENOMEM; | ||
874 | } | ||
875 | |||
876 | codec->private_data = wm8971; | ||
877 | socdev->codec = codec; | ||
878 | mutex_init(&codec->mutex); | ||
879 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
880 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
881 | wm8971_socdev = socdev; | ||
882 | |||
883 | INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work); | ||
884 | wm8971_workq = create_workqueue("wm8971"); | ||
885 | if (wm8971_workq == NULL) { | ||
886 | kfree(codec->private_data); | ||
887 | kfree(codec); | ||
888 | return -ENOMEM; | ||
889 | } | ||
890 | |||
891 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
892 | if (setup->i2c_address) { | ||
893 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
894 | ret = wm8971_add_i2c_device(pdev, setup); | ||
895 | } | ||
896 | #endif | ||
897 | /* Add other interfaces here */ | ||
898 | |||
899 | if (ret != 0) { | ||
900 | destroy_workqueue(wm8971_workq); | ||
901 | kfree(codec->private_data); | ||
902 | kfree(codec); | ||
903 | } | ||
904 | |||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | /* power down chip */ | ||
909 | static int wm8971_remove(struct platform_device *pdev) | ||
910 | { | ||
911 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
912 | struct snd_soc_codec *codec = socdev->codec; | ||
913 | |||
914 | if (codec->control_data) | ||
915 | wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
916 | if (wm8971_workq) | ||
917 | destroy_workqueue(wm8971_workq); | ||
918 | snd_soc_free_pcms(socdev); | ||
919 | snd_soc_dapm_free(socdev); | ||
920 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | ||
921 | i2c_unregister_device(codec->control_data); | ||
922 | i2c_del_driver(&wm8971_i2c_driver); | ||
923 | #endif | ||
924 | kfree(codec->private_data); | ||
925 | kfree(codec); | ||
926 | |||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | struct snd_soc_codec_device soc_codec_dev_wm8971 = { | ||
931 | .probe = wm8971_probe, | ||
932 | .remove = wm8971_remove, | ||
933 | .suspend = wm8971_suspend, | ||
934 | .resume = wm8971_resume, | ||
935 | }; | ||
936 | |||
937 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); | ||
938 | |||
939 | MODULE_DESCRIPTION("ASoC WM8971 driver"); | ||
940 | MODULE_AUTHOR("Lab126"); | ||
941 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8971.h b/sound/soc/codecs/wm8971.h new file mode 100644 index 000000000000..ef4f08f9f344 --- /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 dd995ef448b4..572d22b0880b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -30,7 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8990.h" | 31 | #include "wm8990.h" |
32 | 32 | ||
33 | #define AUDIO_NAME "wm8990" | ||
34 | #define WM8990_VERSION "0.2" | 33 | #define WM8990_VERSION "0.2" |
35 | 34 | ||
36 | /* codec private data */ | 35 | /* codec private data */ |
@@ -1477,81 +1476,86 @@ static struct snd_soc_device *wm8990_socdev; | |||
1477 | * low = 0x34 | 1476 | * low = 0x34 |
1478 | * high = 0x36 | 1477 | * high = 0x36 |
1479 | */ | 1478 | */ |
1480 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1481 | 1479 | ||
1482 | /* Magic definition of all other variables and things */ | 1480 | static int wm8990_i2c_probe(struct i2c_client *i2c, |
1483 | I2C_CLIENT_INSMOD; | 1481 | 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 | { | 1482 | { |
1490 | struct snd_soc_device *socdev = wm8990_socdev; | 1483 | struct snd_soc_device *socdev = wm8990_socdev; |
1491 | struct wm8990_setup_data *setup = socdev->codec_data; | ||
1492 | struct snd_soc_codec *codec = socdev->codec; | 1484 | struct snd_soc_codec *codec = socdev->codec; |
1493 | struct i2c_client *i2c; | ||
1494 | int ret; | 1485 | int ret; |
1495 | 1486 | ||
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); | 1487 | i2c_set_clientdata(i2c, codec); |
1507 | codec->control_data = i2c; | 1488 | codec->control_data = i2c; |
1508 | 1489 | ||
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); | 1490 | ret = wm8990_init(socdev); |
1516 | if (ret < 0) { | 1491 | if (ret < 0) |
1517 | pr_err("failed to initialise WM8990\n"); | 1492 | pr_err("failed to initialise WM8990\n"); |
1518 | goto err; | ||
1519 | } | ||
1520 | return ret; | ||
1521 | 1493 | ||
1522 | err: | ||
1523 | kfree(i2c); | ||
1524 | return ret; | 1494 | return ret; |
1525 | } | 1495 | } |
1526 | 1496 | ||
1527 | static int wm8990_i2c_detach(struct i2c_client *client) | 1497 | static int wm8990_i2c_remove(struct i2c_client *client) |
1528 | { | 1498 | { |
1529 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1499 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1530 | i2c_detach_client(client); | ||
1531 | kfree(codec->reg_cache); | 1500 | kfree(codec->reg_cache); |
1532 | kfree(client); | ||
1533 | return 0; | 1501 | return 0; |
1534 | } | 1502 | } |
1535 | 1503 | ||
1536 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | 1504 | static const struct i2c_device_id wm8990_i2c_id[] = { |
1537 | { | 1505 | { "wm8990", 0 }, |
1538 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | 1506 | { } |
1539 | } | 1507 | }; |
1508 | MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); | ||
1540 | 1509 | ||
1541 | static struct i2c_driver wm8990_i2c_driver = { | 1510 | static struct i2c_driver wm8990_i2c_driver = { |
1542 | .driver = { | 1511 | .driver = { |
1543 | .name = "WM8990 I2C Codec", | 1512 | .name = "WM8990 I2C Codec", |
1544 | .owner = THIS_MODULE, | 1513 | .owner = THIS_MODULE, |
1545 | }, | 1514 | }, |
1546 | .attach_adapter = wm8990_i2c_attach, | 1515 | .probe = wm8990_i2c_probe, |
1547 | .detach_client = wm8990_i2c_detach, | 1516 | .remove = wm8990_i2c_remove, |
1548 | .command = NULL, | 1517 | .id_table = wm8990_i2c_id, |
1549 | }; | 1518 | }; |
1550 | 1519 | ||
1551 | static struct i2c_client client_template = { | 1520 | static int wm8990_add_i2c_device(struct platform_device *pdev, |
1552 | .name = "WM8990", | 1521 | const struct wm8990_setup_data *setup) |
1553 | .driver = &wm8990_i2c_driver, | 1522 | { |
1554 | }; | 1523 | struct i2c_board_info info; |
1524 | struct i2c_adapter *adapter; | ||
1525 | struct i2c_client *client; | ||
1526 | int ret; | ||
1527 | |||
1528 | ret = i2c_add_driver(&wm8990_i2c_driver); | ||
1529 | if (ret != 0) { | ||
1530 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1531 | return ret; | ||
1532 | } | ||
1533 | |||
1534 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1535 | info.addr = setup->i2c_address; | ||
1536 | strlcpy(info.type, "wm8990", I2C_NAME_SIZE); | ||
1537 | |||
1538 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1539 | if (!adapter) { | ||
1540 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1541 | setup->i2c_bus); | ||
1542 | goto err_driver; | ||
1543 | } | ||
1544 | |||
1545 | client = i2c_new_device(adapter, &info); | ||
1546 | i2c_put_adapter(adapter); | ||
1547 | if (!client) { | ||
1548 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1549 | (unsigned int)info.addr); | ||
1550 | goto err_driver; | ||
1551 | } | ||
1552 | |||
1553 | return 0; | ||
1554 | |||
1555 | err_driver: | ||
1556 | i2c_del_driver(&wm8990_i2c_driver); | ||
1557 | return -ENODEV; | ||
1558 | } | ||
1555 | #endif | 1559 | #endif |
1556 | 1560 | ||
1557 | static int wm8990_probe(struct platform_device *pdev) | 1561 | static int wm8990_probe(struct platform_device *pdev) |
@@ -1560,7 +1564,7 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1560 | struct wm8990_setup_data *setup; | 1564 | struct wm8990_setup_data *setup; |
1561 | struct snd_soc_codec *codec; | 1565 | struct snd_soc_codec *codec; |
1562 | struct wm8990_priv *wm8990; | 1566 | struct wm8990_priv *wm8990; |
1563 | int ret = 0; | 1567 | int ret; |
1564 | 1568 | ||
1565 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | 1569 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); |
1566 | 1570 | ||
@@ -1582,16 +1586,13 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1582 | INIT_LIST_HEAD(&codec->dapm_paths); | 1586 | INIT_LIST_HEAD(&codec->dapm_paths); |
1583 | wm8990_socdev = socdev; | 1587 | wm8990_socdev = socdev; |
1584 | 1588 | ||
1589 | ret = -ENODEV; | ||
1590 | |||
1585 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1591 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1586 | if (setup->i2c_address) { | 1592 | if (setup->i2c_address) { |
1587 | normal_i2c[0] = setup->i2c_address; | ||
1588 | codec->hw_write = (hw_write_t)i2c_master_send; | 1593 | codec->hw_write = (hw_write_t)i2c_master_send; |
1589 | ret = i2c_add_driver(&wm8990_i2c_driver); | 1594 | ret = wm8990_add_i2c_device(pdev, setup); |
1590 | if (ret != 0) | ||
1591 | printk(KERN_ERR "can't add i2c driver"); | ||
1592 | } | 1595 | } |
1593 | #else | ||
1594 | /* Add other interfaces here */ | ||
1595 | #endif | 1596 | #endif |
1596 | 1597 | ||
1597 | if (ret != 0) { | 1598 | if (ret != 0) { |
@@ -1612,6 +1613,7 @@ static int wm8990_remove(struct platform_device *pdev) | |||
1612 | snd_soc_free_pcms(socdev); | 1613 | snd_soc_free_pcms(socdev); |
1613 | snd_soc_dapm_free(socdev); | 1614 | snd_soc_dapm_free(socdev); |
1614 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1615 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1616 | i2c_unregister_device(codec->control_data); | ||
1615 | i2c_del_driver(&wm8990_i2c_driver); | 1617 | i2c_del_driver(&wm8990_i2c_driver); |
1616 | #endif | 1618 | #endif |
1617 | kfree(codec->private_data); | 1619 | kfree(codec->private_data); |
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 0a08325d5443..0e192f3b0788 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/wm9712.c b/sound/soc/codecs/wm9712.c index 2f1c91b1d556..ffb471e420e2 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm9712.c -- ALSA Soc WM9712 codec support | 2 | * wm9712.c -- ALSA Soc WM9712 codec support |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * 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 | 8 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 38d1fe0971fc..aba402b3c999 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * wm9713.c -- ALSA Soc WM9713 codec support | 2 | * wm9713.c -- ALSA Soc WM9713 codec support |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 7 | * 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 | 8 | * under the terms of the GNU General Public License as published by the |
@@ -419,8 +418,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), | 418 | 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), | 419 | 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), | 420 | 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), | 421 | 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), | 422 | SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0), |
423 | SND_SOC_DAPM_ADC("Left HiFi ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
424 | SND_SOC_DAPM_ADC("Right HiFi ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0), | ||
425 | SND_SOC_DAPM_ADC("Left Voice ADC", "Left Voice Capture", SND_SOC_NOPM, 0, 0), | ||
426 | 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), | 427 | 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), | 428 | 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), | 429 | SND_SOC_DAPM_PGA("Left Speaker", AC97_EXTENDED_MSTATUS, 8, 1, NULL, 0), |
@@ -583,9 +586,13 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
583 | 586 | ||
584 | /* left ADC */ | 587 | /* left ADC */ |
585 | {"Left ADC", NULL, "Left Capture Source"}, | 588 | {"Left ADC", NULL, "Left Capture Source"}, |
589 | {"Left Voice ADC", NULL, "Left ADC"}, | ||
590 | {"Left HiFi ADC", NULL, "Left ADC"}, | ||
586 | 591 | ||
587 | /* right ADC */ | 592 | /* right ADC */ |
588 | {"Right ADC", NULL, "Right Capture Source"}, | 593 | {"Right ADC", NULL, "Right Capture Source"}, |
594 | {"Right Voice ADC", NULL, "Right ADC"}, | ||
595 | {"Right HiFi ADC", NULL, "Right ADC"}, | ||
589 | 596 | ||
590 | /* mic */ | 597 | /* mic */ |
591 | {"Mic A Pre Amp", NULL, "Mic A Source"}, | 598 | {"Mic A Pre Amp", NULL, "Mic A Source"}, |
@@ -949,17 +956,17 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, | |||
949 | 956 | ||
950 | static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) | 957 | static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) |
951 | { | 958 | { |
952 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 959 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
953 | struct snd_soc_device *socdev = rtd->socdev; | 960 | struct snd_soc_device *socdev = rtd->socdev; |
954 | struct snd_soc_codec *codec = socdev->codec; | 961 | struct snd_soc_codec *codec = socdev->codec; |
955 | u16 status; | 962 | u16 status; |
956 | 963 | ||
957 | /* Gracefully shut down the voice interface. */ | 964 | /* Gracefully shut down the voice interface. */ |
958 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; | 965 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; |
959 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); | 966 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); |
960 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | 967 | schedule_timeout_interruptible(msecs_to_jiffies(1)); |
961 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); | 968 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); |
962 | ac97_write(codec, AC97_EXTENDED_MID, status); | 969 | ac97_write(codec, AC97_EXTENDED_MID, status); |
963 | } | 970 | } |
964 | 971 | ||
965 | static int ac97_hifi_prepare(struct snd_pcm_substream *substream) | 972 | static int ac97_hifi_prepare(struct snd_pcm_substream *substream) |