aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-03-07 02:04:55 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-03-07 07:19:22 -0500
commit9b0a25f0386f9775b69c46ced9b5632b649f00ba (patch)
tree82aa924b21417d281c4eeb19f5b4b7fbbefc3d9e
parent004c52e009e3c585eb0692740b714867fd2b3555 (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/Kconfig3
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/lm4857.c276
-rw-r--r--sound/soc/samsung/Kconfig1
-rw-r--r--sound/soc/samsung/lm4857.h32
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c269
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
350config SND_SOC_LM4857
351 tristate
352
350config SND_SOC_MAX9877 353config 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
77snd-soc-jz4740-codec-objs := jz4740.o 77snd-soc-jz4740-codec-objs := jz4740.o
78 78
79# Amp 79# Amp
80snd-soc-lm4857-objs := lm4857.o
80snd-soc-max9877-objs := max9877.o 81snd-soc-max9877-objs := max9877.o
81snd-soc-tpa6130a2-objs := tpa6130a2.o 82snd-soc-tpa6130a2-objs := tpa6130a2.o
82snd-soc-wm2000-objs := wm2000.o 83snd-soc-wm2000-objs := wm2000.o
@@ -161,6 +162,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
161obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o 162obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
162 163
163# Amp 164# Amp
165obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
164obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o 166obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
165obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o 167obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
166obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o 168obj-$(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
25struct lm4857 {
26 struct i2c_client *i2c;
27 uint8_t mode;
28};
29
30static 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
45static 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
65static 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
78static 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
89static 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
104static 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
125static const char *lm4857_mode[] = {
126 "Earpiece",
127 "Loudspeaker",
128 "Loudspeaker + Headphone",
129 "Headphone",
130};
131
132static const struct soc_enum lm4857_mode_enum =
133 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode);
134
135static 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
143static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
144static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
145
146static 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. */
168static const struct snd_soc_dapm_route lm4857_routes[] = {
169 {"LS", NULL, "IN"},
170 {"HP", NULL, "IN"},
171 {"EP", NULL, "IN"},
172};
173
174static 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
202static 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
212static 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
236static 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
246static const struct i2c_device_id lm4857_i2c_id[] = {
247 { "lm4857", 0 },
248 { }
249};
250MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id);
251
252static 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
262static int __init lm4857_init(void)
263{
264 return i2c_add_driver(&lm4857_i2c_driver);
265}
266module_init(lm4857_init);
267
268static void __exit lm4857_exit(void)
269{
270 i2c_del_driver(&lm4857_i2c_driver);
271}
272module_exit(lm4857_exit);
273
274MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
275MODULE_DESCRIPTION("LM4857 amplifier driver");
276MODULE_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
40static struct snd_soc_card neo1973; 37static struct snd_soc_card neo1973;
41static struct i2c_client *i2c;
42 38
43static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, 39static 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
216static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
217
218static 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
226static 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
241static 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
260static 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
274static 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
293static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { 212static 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
302static const struct snd_soc_dapm_route dapm_routes[] = { 220static 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
327static const char *lm4857_mode[] = { 240static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
328 "Off",
329 "Call Speaker",
330 "Stereo Speakers",
331 "Stereo Speakers + Headphones",
332 "Headphones"
333};
334
335static const struct soc_enum lm4857_mode_enum[] = {
336 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
337};
338
339static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
340static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
341
342static 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
293static 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
302static 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
308static 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
452static struct snd_soc_card neo1973 = { 370static 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
458static int lm4857_i2c_probe(struct i2c_client *client, 378static 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
469static 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
478static u8 lm4857_state;
479
480static 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
493static 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
504static 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
513static const struct i2c_device_id lm4857_i2c_id[] = {
514 { "neo1973_lm4857", 0 },
515 { }
516}; 383};
517 384
518static struct i2c_driver lm4857_i2c_driver = { 385static 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
531static struct platform_device *neo1973_snd_device; 395static 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