diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2011-03-07 02:04:55 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-03-07 07:19:22 -0500 |
commit | 9b0a25f0386f9775b69c46ced9b5632b649f00ba (patch) | |
tree | 82aa924b21417d281c4eeb19f5b4b7fbbefc3d9e | |
parent | 004c52e009e3c585eb0692740b714867fd2b3555 (diff) |
ASoC: neo1973_wm8753: Move lm4857 specefic code to its own module
This patch moves the code for the lm4857 AMP from the neo1973_wm8753 sound
board driver to its own module.
The lm4857 is a generic AMP IC and not specific to the neo1973.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/lm4857.c | 276 | ||||
-rw-r--r-- | sound/soc/samsung/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/samsung/lm4857.h | 32 | ||||
-rw-r--r-- | sound/soc/samsung/neo1973_wm8753.c | 269 |
6 files changed, 347 insertions, 236 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 82a46309ded6..37035e6984bb 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -347,6 +347,9 @@ config SND_SOC_WM9713 | |||
347 | tristate | 347 | tristate |
348 | 348 | ||
349 | # Amp | 349 | # Amp |
350 | config SND_SOC_LM4857 | ||
351 | tristate | ||
352 | |||
350 | config SND_SOC_MAX9877 | 353 | config SND_SOC_MAX9877 |
351 | tristate | 354 | tristate |
352 | 355 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b43f9d418c9b..0663d22e86be 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -77,6 +77,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o | |||
77 | snd-soc-jz4740-codec-objs := jz4740.o | 77 | snd-soc-jz4740-codec-objs := jz4740.o |
78 | 78 | ||
79 | # Amp | 79 | # Amp |
80 | snd-soc-lm4857-objs := lm4857.o | ||
80 | snd-soc-max9877-objs := max9877.o | 81 | snd-soc-max9877-objs := max9877.o |
81 | snd-soc-tpa6130a2-objs := tpa6130a2.o | 82 | snd-soc-tpa6130a2-objs := tpa6130a2.o |
82 | snd-soc-wm2000-objs := wm2000.o | 83 | snd-soc-wm2000-objs := wm2000.o |
@@ -161,6 +162,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | |||
161 | obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o | 162 | obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o |
162 | 163 | ||
163 | # Amp | 164 | # Amp |
165 | obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o | ||
164 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o | 166 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o |
165 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o | 167 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o |
166 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o | 168 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o |
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c new file mode 100644 index 000000000000..72de47e5d040 --- /dev/null +++ b/sound/soc/codecs/lm4857.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * LM4857 AMP driver | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/soc.h> | ||
23 | #include <sound/tlv.h> | ||
24 | |||
25 | struct lm4857 { | ||
26 | struct i2c_client *i2c; | ||
27 | uint8_t mode; | ||
28 | }; | ||
29 | |||
30 | static const uint8_t lm4857_default_regs[] = { | ||
31 | 0x00, 0x00, 0x00, 0x00, | ||
32 | }; | ||
33 | |||
34 | /* The register offsets in the cache array */ | ||
35 | #define LM4857_MVOL 0 | ||
36 | #define LM4857_LVOL 1 | ||
37 | #define LM4857_RVOL 2 | ||
38 | #define LM4857_CTRL 3 | ||
39 | |||
40 | /* the shifts required to set these bits */ | ||
41 | #define LM4857_3D 5 | ||
42 | #define LM4857_WAKEUP 5 | ||
43 | #define LM4857_EPGAIN 4 | ||
44 | |||
45 | static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg, | ||
46 | unsigned int value) | ||
47 | { | ||
48 | uint8_t data; | ||
49 | int ret; | ||
50 | |||
51 | ret = snd_soc_cache_write(codec, reg, value); | ||
52 | if (ret < 0) | ||
53 | return ret; | ||
54 | |||
55 | data = (reg << 6) | value; | ||
56 | ret = i2c_master_send(codec->control_data, &data, 1); | ||
57 | if (ret != 1) { | ||
58 | dev_err(codec->dev, "Failed to write register: %d\n", ret); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static unsigned int lm4857_read(struct snd_soc_codec *codec, | ||
66 | unsigned int reg) | ||
67 | { | ||
68 | unsigned int val; | ||
69 | int ret; | ||
70 | |||
71 | ret = snd_soc_cache_read(codec, reg, &val); | ||
72 | if (ret) | ||
73 | return -1; | ||
74 | |||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | ||
79 | struct snd_ctl_elem_value *ucontrol) | ||
80 | { | ||
81 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
82 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
83 | |||
84 | ucontrol->value.integer.value[0] = lm4857->mode; | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | ||
90 | struct snd_ctl_elem_value *ucontrol) | ||
91 | { | ||
92 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
93 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
94 | uint8_t value = ucontrol->value.integer.value[0]; | ||
95 | |||
96 | lm4857->mode = value; | ||
97 | |||
98 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | ||
99 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6); | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | static int lm4857_set_bias_level(struct snd_soc_codec *codec, | ||
105 | enum snd_soc_bias_level level) | ||
106 | { | ||
107 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
108 | |||
109 | switch (level) { | ||
110 | case SND_SOC_BIAS_ON: | ||
111 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6); | ||
112 | break; | ||
113 | case SND_SOC_BIAS_STANDBY: | ||
114 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0); | ||
115 | break; | ||
116 | default: | ||
117 | break; | ||
118 | } | ||
119 | |||
120 | codec->dapm.bias_level = level; | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static const char *lm4857_mode[] = { | ||
126 | "Earpiece", | ||
127 | "Loudspeaker", | ||
128 | "Loudspeaker + Headphone", | ||
129 | "Headphone", | ||
130 | }; | ||
131 | |||
132 | static const struct soc_enum lm4857_mode_enum = | ||
133 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode); | ||
134 | |||
135 | static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { | ||
136 | SND_SOC_DAPM_INPUT("IN"), | ||
137 | |||
138 | SND_SOC_DAPM_OUTPUT("LS"), | ||
139 | SND_SOC_DAPM_OUTPUT("HP"), | ||
140 | SND_SOC_DAPM_OUTPUT("EP"), | ||
141 | }; | ||
142 | |||
143 | static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); | ||
144 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); | ||
145 | |||
146 | static const struct snd_kcontrol_new lm4857_controls[] = { | ||
147 | SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0, | ||
148 | stereo_tlv), | ||
149 | SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0, | ||
150 | stereo_tlv), | ||
151 | SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0, | ||
152 | mono_tlv), | ||
153 | SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0), | ||
154 | SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0), | ||
155 | SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL, | ||
156 | LM4857_WAKEUP, 1, 0), | ||
157 | SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, | ||
158 | LM4857_EPGAIN, 1, 0), | ||
159 | |||
160 | SOC_ENUM_EXT("Mode", lm4857_mode_enum, | ||
161 | lm4857_get_mode, lm4857_set_mode), | ||
162 | }; | ||
163 | |||
164 | /* There is a demux inbetween the the input signal and the output signals. | ||
165 | * Currently there is no easy way to model it in ASoC and since it does not make | ||
166 | * much of a difference in practice simply connect the input direclty to the | ||
167 | * outputs. */ | ||
168 | static const struct snd_soc_dapm_route lm4857_routes[] = { | ||
169 | {"LS", NULL, "IN"}, | ||
170 | {"HP", NULL, "IN"}, | ||
171 | {"EP", NULL, "IN"}, | ||
172 | }; | ||
173 | |||
174 | static int lm4857_probe(struct snd_soc_codec *codec) | ||
175 | { | ||
176 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
177 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
178 | int ret; | ||
179 | |||
180 | codec->control_data = lm4857->i2c; | ||
181 | |||
182 | ret = snd_soc_add_controls(codec, lm4857_controls, | ||
183 | ARRAY_SIZE(lm4857_controls)); | ||
184 | if (ret) | ||
185 | return ret; | ||
186 | |||
187 | ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets, | ||
188 | ARRAY_SIZE(lm4857_dapm_widgets)); | ||
189 | if (ret) | ||
190 | return ret; | ||
191 | |||
192 | ret = snd_soc_dapm_add_routes(dapm, lm4857_routes, | ||
193 | ARRAY_SIZE(lm4857_routes)); | ||
194 | if (ret) | ||
195 | return ret; | ||
196 | |||
197 | snd_soc_dapm_new_widgets(dapm); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { | ||
203 | .write = lm4857_write, | ||
204 | .read = lm4857_read, | ||
205 | .probe = lm4857_probe, | ||
206 | .reg_cache_size = ARRAY_SIZE(lm4857_default_regs), | ||
207 | .reg_word_size = sizeof(uint8_t), | ||
208 | .reg_cache_default = lm4857_default_regs, | ||
209 | .set_bias_level = lm4857_set_bias_level, | ||
210 | }; | ||
211 | |||
212 | static int __devinit lm4857_i2c_probe(struct i2c_client *i2c, | ||
213 | const struct i2c_device_id *id) | ||
214 | { | ||
215 | struct lm4857 *lm4857; | ||
216 | int ret; | ||
217 | |||
218 | lm4857 = kzalloc(sizeof(*lm4857), GFP_KERNEL); | ||
219 | if (!lm4857) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | i2c_set_clientdata(i2c, lm4857); | ||
223 | |||
224 | lm4857->i2c = i2c; | ||
225 | |||
226 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0); | ||
227 | |||
228 | if (ret) { | ||
229 | kfree(lm4857); | ||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int __devexit lm4857_i2c_remove(struct i2c_client *i2c) | ||
237 | { | ||
238 | struct lm4857 *lm4857 = i2c_get_clientdata(i2c); | ||
239 | |||
240 | snd_soc_unregister_codec(&i2c->dev); | ||
241 | kfree(lm4857); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static const struct i2c_device_id lm4857_i2c_id[] = { | ||
247 | { "lm4857", 0 }, | ||
248 | { } | ||
249 | }; | ||
250 | MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); | ||
251 | |||
252 | static struct i2c_driver lm4857_i2c_driver = { | ||
253 | .driver = { | ||
254 | .name = "lm4857", | ||
255 | .owner = THIS_MODULE, | ||
256 | }, | ||
257 | .probe = lm4857_i2c_probe, | ||
258 | .remove = __devexit_p(lm4857_i2c_remove), | ||
259 | .id_table = lm4857_i2c_id, | ||
260 | }; | ||
261 | |||
262 | static int __init lm4857_init(void) | ||
263 | { | ||
264 | return i2c_add_driver(&lm4857_i2c_driver); | ||
265 | } | ||
266 | module_init(lm4857_init); | ||
267 | |||
268 | static void __exit lm4857_exit(void) | ||
269 | { | ||
270 | i2c_del_driver(&lm4857_i2c_driver); | ||
271 | } | ||
272 | module_exit(lm4857_exit); | ||
273 | |||
274 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
275 | MODULE_DESCRIPTION("LM4857 amplifier driver"); | ||
276 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index a6a6b5fa2f2f..ba78e26e20f2 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -39,6 +39,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753 | |||
39 | depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01 | 39 | depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01 |
40 | select SND_S3C24XX_I2S | 40 | select SND_S3C24XX_I2S |
41 | select SND_SOC_WM8753 | 41 | select SND_SOC_WM8753 |
42 | select SND_SOC_LM4857 | ||
42 | help | 43 | help |
43 | Say Y if you want to add support for SoC audio on smdk2440 | 44 | Say Y if you want to add support for SoC audio on smdk2440 |
44 | with the WM8753. | 45 | with the WM8753. |
diff --git a/sound/soc/samsung/lm4857.h b/sound/soc/samsung/lm4857.h deleted file mode 100644 index 0cf5b7011d6f..000000000000 --- a/sound/soc/samsung/lm4857.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | /* | ||
2 | * lm4857.h -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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 | * Revision history | ||
14 | * 18th Jun 2007 Initial version. | ||
15 | */ | ||
16 | |||
17 | #ifndef LM4857_H_ | ||
18 | #define LM4857_H_ | ||
19 | |||
20 | /* The register offsets in the cache array */ | ||
21 | #define LM4857_MVOL 0 | ||
22 | #define LM4857_LVOL 1 | ||
23 | #define LM4857_RVOL 2 | ||
24 | #define LM4857_CTRL 3 | ||
25 | |||
26 | /* the shifts required to set these bits */ | ||
27 | #define LM4857_3D 5 | ||
28 | #define LM4857_WAKEUP 5 | ||
29 | #define LM4857_EPGAIN 4 | ||
30 | |||
31 | #endif /*LM4857_H_*/ | ||
32 | |||
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index fe929467f93c..7761827314b2 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c | |||
@@ -17,11 +17,9 @@ | |||
17 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/i2c.h> | ||
21 | #include <sound/core.h> | 20 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
23 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
24 | #include <sound/tlv.h> | ||
25 | 23 | ||
26 | #include <asm/mach-types.h> | 24 | #include <asm/mach-types.h> |
27 | #include <mach/regs-clock.h> | 25 | #include <mach/regs-clock.h> |
@@ -33,12 +31,10 @@ | |||
33 | #include <plat/regs-iis.h> | 31 | #include <plat/regs-iis.h> |
34 | 32 | ||
35 | #include "../codecs/wm8753.h" | 33 | #include "../codecs/wm8753.h" |
36 | #include "lm4857.h" | ||
37 | #include "dma.h" | 34 | #include "dma.h" |
38 | #include "s3c24xx-i2s.h" | 35 | #include "s3c24xx-i2s.h" |
39 | 36 | ||
40 | static struct snd_soc_card neo1973; | 37 | static struct snd_soc_card neo1973; |
41 | static struct i2c_client *i2c; | ||
42 | 38 | ||
43 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | 39 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, |
44 | struct snd_pcm_hw_params *params) | 40 | struct snd_pcm_hw_params *params) |
@@ -213,85 +209,7 @@ static struct snd_soc_ops neo1973_voice_ops = { | |||
213 | .hw_free = neo1973_voice_hw_free, | 209 | .hw_free = neo1973_voice_hw_free, |
214 | }; | 210 | }; |
215 | 211 | ||
216 | static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; | ||
217 | |||
218 | static void lm4857_write_regs(void) | ||
219 | { | ||
220 | pr_debug("Entered %s\n", __func__); | ||
221 | |||
222 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) | ||
223 | printk(KERN_ERR "lm4857: i2c write failed\n"); | ||
224 | } | ||
225 | |||
226 | static int lm4857_get_reg(struct snd_kcontrol *kcontrol, | ||
227 | struct snd_ctl_elem_value *ucontrol) | ||
228 | { | ||
229 | struct soc_mixer_control *mc = | ||
230 | (struct soc_mixer_control *)kcontrol->private_value; | ||
231 | int reg = mc->reg; | ||
232 | int shift = mc->shift; | ||
233 | int mask = mc->max; | ||
234 | |||
235 | pr_debug("Entered %s\n", __func__); | ||
236 | |||
237 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int lm4857_set_reg(struct snd_kcontrol *kcontrol, | ||
242 | struct snd_ctl_elem_value *ucontrol) | ||
243 | { | ||
244 | struct soc_mixer_control *mc = | ||
245 | (struct soc_mixer_control *)kcontrol->private_value; | ||
246 | int reg = mc->reg; | ||
247 | int shift = mc->shift; | ||
248 | int mask = mc->max; | ||
249 | |||
250 | if (((lm4857_regs[reg] >> shift) & mask) == | ||
251 | ucontrol->value.integer.value[0]) | ||
252 | return 0; | ||
253 | |||
254 | lm4857_regs[reg] &= ~(mask << shift); | ||
255 | lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift; | ||
256 | lm4857_write_regs(); | ||
257 | return 1; | ||
258 | } | ||
259 | |||
260 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | ||
261 | struct snd_ctl_elem_value *ucontrol) | ||
262 | { | ||
263 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; | ||
264 | |||
265 | pr_debug("Entered %s\n", __func__); | ||
266 | |||
267 | if (value) | ||
268 | value -= 5; | ||
269 | |||
270 | ucontrol->value.integer.value[0] = value; | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | ||
275 | struct snd_ctl_elem_value *ucontrol) | ||
276 | { | ||
277 | u8 value = ucontrol->value.integer.value[0]; | ||
278 | |||
279 | pr_debug("Entered %s\n", __func__); | ||
280 | |||
281 | if (value) | ||
282 | value += 5; | ||
283 | |||
284 | if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value) | ||
285 | return 0; | ||
286 | |||
287 | lm4857_regs[LM4857_CTRL] &= 0xF0; | ||
288 | lm4857_regs[LM4857_CTRL] |= value; | ||
289 | lm4857_write_regs(); | ||
290 | return 1; | ||
291 | } | ||
292 | |||
293 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | 212 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { |
294 | SND_SOC_DAPM_LINE("Audio Out", NULL), | ||
295 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | 213 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), |
296 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | 214 | SND_SOC_DAPM_LINE("GSM Line In", NULL), |
297 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | 215 | SND_SOC_DAPM_MIC("Headset Mic", NULL), |
@@ -299,12 +217,7 @@ static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | |||
299 | }; | 217 | }; |
300 | 218 | ||
301 | 219 | ||
302 | static const struct snd_soc_dapm_route dapm_routes[] = { | 220 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { |
303 | |||
304 | /* Connections to the lm4857 amp */ | ||
305 | {"Audio Out", NULL, "LOUT1"}, | ||
306 | {"Audio Out", NULL, "ROUT1"}, | ||
307 | |||
308 | /* Connections to the GSM Module */ | 221 | /* Connections to the GSM Module */ |
309 | {"GSM Line Out", NULL, "MONO1"}, | 222 | {"GSM Line Out", NULL, "MONO1"}, |
310 | {"GSM Line Out", NULL, "MONO2"}, | 223 | {"GSM Line Out", NULL, "MONO2"}, |
@@ -324,46 +237,14 @@ static const struct snd_soc_dapm_route dapm_routes[] = { | |||
324 | {"ACIN", NULL, "ACOP"}, | 237 | {"ACIN", NULL, "ACOP"}, |
325 | }; | 238 | }; |
326 | 239 | ||
327 | static const char *lm4857_mode[] = { | 240 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { |
328 | "Off", | ||
329 | "Call Speaker", | ||
330 | "Stereo Speakers", | ||
331 | "Stereo Speakers + Headphones", | ||
332 | "Headphones" | ||
333 | }; | ||
334 | |||
335 | static const struct soc_enum lm4857_mode_enum[] = { | ||
336 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode), | ||
337 | }; | ||
338 | |||
339 | static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); | ||
340 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); | ||
341 | |||
342 | static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { | ||
343 | SOC_DAPM_PIN_SWITCH("Audio Out"), | ||
344 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | 241 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), |
345 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | 242 | SOC_DAPM_PIN_SWITCH("GSM Line In"), |
346 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | 243 | SOC_DAPM_PIN_SWITCH("Headset Mic"), |
347 | SOC_DAPM_PIN_SWITCH("Call Mic"), | 244 | SOC_DAPM_PIN_SWITCH("Call Mic"), |
348 | |||
349 | SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, | ||
350 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), | ||
351 | SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, | ||
352 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), | ||
353 | SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, | ||
354 | lm4857_get_reg, lm4857_set_reg, mono_tlv), | ||
355 | SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], | ||
356 | lm4857_get_mode, lm4857_set_mode), | ||
357 | SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0, | ||
358 | lm4857_get_reg, lm4857_set_reg), | ||
359 | SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0, | ||
360 | lm4857_get_reg, lm4857_set_reg), | ||
361 | SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0, | ||
362 | lm4857_get_reg, lm4857_set_reg), | ||
363 | SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0, | ||
364 | lm4857_get_reg, lm4857_set_reg), | ||
365 | }; | 245 | }; |
366 | 246 | ||
247 | |||
367 | /* | 248 | /* |
368 | * This is an example machine initialisation for a wm8753 connected to a | 249 | * This is an example machine initialisation for a wm8753 connected to a |
369 | * neo1973 II. It is missing logic to detect hp/mic insertions and logic | 250 | * neo1973 II. It is missing logic to detect hp/mic insertions and logic |
@@ -387,29 +268,66 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) | |||
387 | 268 | ||
388 | /* Add neo1973 specific widgets */ | 269 | /* Add neo1973 specific widgets */ |
389 | snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, | 270 | snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, |
390 | ARRAY_SIZE(wm8753_dapm_widgets)); | 271 | ARRAY_SIZE(wm8753_dapm_widgets)); |
391 | 272 | ||
392 | /* set endpoints to default mode */ | 273 | /* set endpoints to default mode */ |
393 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
394 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | 274 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); |
395 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | 275 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); |
396 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | 276 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); |
397 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | 277 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); |
398 | 278 | ||
399 | /* add neo1973 specific controls */ | 279 | /* add neo1973 specific controls */ |
400 | err = snd_soc_add_controls(codec, wm8753_neo1973_controls, | 280 | err = snd_soc_add_controls(codec, neo1973_wm8753_controls, |
401 | ARRAY_SIZE(8753_neo1973_controls)); | 281 | ARRAY_SIZE(neo1973_wm8753_controls)); |
402 | if (err < 0) | 282 | if (err < 0) |
403 | return err; | 283 | return err; |
404 | 284 | ||
405 | /* set up neo1973 specific audio routes */ | 285 | /* set up neo1973 specific audio routes */ |
406 | err = snd_soc_dapm_add_routes(dapm, dapm_routes, | 286 | err = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, |
407 | ARRAY_SIZE(dapm_routes)); | 287 | ARRAY_SIZE(neo1973_wm8753_routes)); |
408 | 288 | ||
409 | snd_soc_dapm_sync(dapm); | 289 | snd_soc_dapm_sync(dapm); |
410 | return 0; | 290 | return 0; |
411 | } | 291 | } |
412 | 292 | ||
293 | static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { | ||
294 | {"Amp IN", NULL, "ROUT1"}, | ||
295 | {"Amp IN", NULL, "LOUT1"}, | ||
296 | |||
297 | {"Handset Spk", NULL, "Amp EP"}, | ||
298 | {"Stereo Out", NULL, "Amp LS"}, | ||
299 | {"Headphone", NULL, "Amp HP"}, | ||
300 | }; | ||
301 | |||
302 | static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { | ||
303 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
304 | SND_SOC_DAPM_SPK("Stereo Out", NULL), | ||
305 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
306 | }; | ||
307 | |||
308 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) | ||
309 | { | ||
310 | int ret; | ||
311 | |||
312 | ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, | ||
313 | ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); | ||
314 | if (ret) | ||
315 | return ret; | ||
316 | |||
317 | ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, | ||
318 | ARRAY_SIZE(neo1973_lm4857_routes)); | ||
319 | if (ret) | ||
320 | return ret; | ||
321 | |||
322 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | ||
323 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | ||
324 | snd_soc_dapm_ignore_suspend(dapm, "Headphone"); | ||
325 | |||
326 | snd_soc_dapm_sync(dapm); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
413 | /* | 331 | /* |
414 | * BT Codec DAI | 332 | * BT Codec DAI |
415 | */ | 333 | */ |
@@ -449,83 +367,29 @@ static struct snd_soc_dai_link neo1973_dai[] = { | |||
449 | }, | 367 | }, |
450 | }; | 368 | }; |
451 | 369 | ||
452 | static struct snd_soc_card neo1973 = { | 370 | static struct snd_soc_aux_dev neo1973_aux_devs[] = { |
453 | .name = "neo1973", | 371 | { |
454 | .dai_link = neo1973_dai, | 372 | .name = "lm4857", |
455 | .num_links = ARRAY_SIZE(neo1973_dai), | 373 | .codec_name = "lm4857.0-007c", |
374 | .init = neo1973_lm4857_init, | ||
375 | }, | ||
456 | }; | 376 | }; |
457 | 377 | ||
458 | static int lm4857_i2c_probe(struct i2c_client *client, | 378 | static struct snd_soc_codec_conf neo1973_codec_conf[] = { |
459 | const struct i2c_device_id *id) | 379 | { |
460 | { | 380 | .dev_name = "lm4857.0-007c", |
461 | pr_debug("Entered %s\n", __func__); | 381 | .name_prefix = "Amp", |
462 | 382 | }, | |
463 | i2c = client; | ||
464 | |||
465 | lm4857_write_regs(); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int lm4857_i2c_remove(struct i2c_client *client) | ||
470 | { | ||
471 | pr_debug("Entered %s\n", __func__); | ||
472 | |||
473 | i2c = NULL; | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static u8 lm4857_state; | ||
479 | |||
480 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | ||
481 | { | ||
482 | pr_debug("Entered %s\n", __func__); | ||
483 | |||
484 | dev_dbg(&dev->dev, "lm4857_suspend\n"); | ||
485 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; | ||
486 | if (lm4857_state) { | ||
487 | lm4857_regs[LM4857_CTRL] &= 0xf0; | ||
488 | lm4857_write_regs(); | ||
489 | } | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static int lm4857_resume(struct i2c_client *dev) | ||
494 | { | ||
495 | pr_debug("Entered %s\n", __func__); | ||
496 | |||
497 | if (lm4857_state) { | ||
498 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); | ||
499 | lm4857_write_regs(); | ||
500 | } | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | static void lm4857_shutdown(struct i2c_client *dev) | ||
505 | { | ||
506 | pr_debug("Entered %s\n", __func__); | ||
507 | |||
508 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); | ||
509 | lm4857_regs[LM4857_CTRL] &= 0xf0; | ||
510 | lm4857_write_regs(); | ||
511 | } | ||
512 | |||
513 | static const struct i2c_device_id lm4857_i2c_id[] = { | ||
514 | { "neo1973_lm4857", 0 }, | ||
515 | { } | ||
516 | }; | 383 | }; |
517 | 384 | ||
518 | static struct i2c_driver lm4857_i2c_driver = { | 385 | static struct snd_soc_card neo1973 = { |
519 | .driver = { | 386 | .name = "neo1973", |
520 | .name = "LM4857 I2C Amp", | 387 | .dai_link = neo1973_dai, |
521 | .owner = THIS_MODULE, | 388 | .num_links = ARRAY_SIZE(neo1973_dai), |
522 | }, | 389 | .aux_dev = neo1973_aux_devs, |
523 | .suspend = lm4857_suspend, | 390 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), |
524 | .resume = lm4857_resume, | 391 | .codec_conf = neo1973_codec_conf, |
525 | .shutdown = lm4857_shutdown, | 392 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), |
526 | .probe = lm4857_i2c_probe, | ||
527 | .remove = lm4857_i2c_remove, | ||
528 | .id_table = lm4857_i2c_id, | ||
529 | }; | 393 | }; |
530 | 394 | ||
531 | static struct platform_device *neo1973_snd_device; | 395 | static struct platform_device *neo1973_snd_device; |
@@ -554,8 +418,6 @@ static int __init neo1973_init(void) | |||
554 | return ret; | 418 | return ret; |
555 | } | 419 | } |
556 | 420 | ||
557 | ret = i2c_add_driver(&lm4857_i2c_driver); | ||
558 | |||
559 | if (ret != 0) | 421 | if (ret != 0) |
560 | platform_device_unregister(neo1973_snd_device); | 422 | platform_device_unregister(neo1973_snd_device); |
561 | 423 | ||
@@ -566,7 +428,6 @@ static void __exit neo1973_exit(void) | |||
566 | { | 428 | { |
567 | pr_debug("Entered %s\n", __func__); | 429 | pr_debug("Entered %s\n", __func__); |
568 | 430 | ||
569 | i2c_del_driver(&lm4857_i2c_driver); | ||
570 | platform_device_unregister(neo1973_snd_device); | 431 | platform_device_unregister(neo1973_snd_device); |
571 | } | 432 | } |
572 | 433 | ||