blob: 79c5027273cbe1553993d6ee6827cae09d37e114 [file] [log] [blame]
Graeme Gregory74930bb2007-05-14 11:03:52 +02001/*
2 * neo1973_wm8753.c -- SoC audio for Neo1973
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 * 20th Jan 2007 Initial version.
15 * 05th Feb 2007 Rename all to Neo1973
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/timer.h>
22#include <linux/interrupt.h>
23#include <linux/platform_device.h>
24#include <linux/i2c.h>
Graeme Gregory74930bb2007-05-14 11:03:52 +020025#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29
30#include <asm/mach-types.h>
31#include <asm/hardware/scoop.h>
Graeme Gregory74930bb2007-05-14 11:03:52 +020032#include <asm/arch/regs-clock.h>
33#include <asm/arch/regs-gpio.h>
34#include <asm/hardware.h>
35#include <asm/arch/audio.h>
Graeme Gregory8ba02ac2008-04-30 20:24:54 +020036#include <linux/io.h>
Graeme Gregory74930bb2007-05-14 11:03:52 +020037#include <asm/arch/spi-gpio.h>
Harald Welteaa9673c2007-12-19 15:37:49 +010038
39#include <asm/plat-s3c24xx/regs-iis.h>
40
Graeme Gregory74930bb2007-05-14 11:03:52 +020041#include "../codecs/wm8753.h"
42#include "lm4857.h"
43#include "s3c24xx-pcm.h"
44#include "s3c24xx-i2s.h"
45
Tim Niemeyer1894c592008-05-05 14:16:12 +020046/* Debugging stuff */
47#define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0
48#if S3C24XX_SOC_NEO1973_WM8753_DEBUG
49#define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x)
50#else
51#define DBG(x...)
52#endif
53
Graeme Gregory74930bb2007-05-14 11:03:52 +020054/* define the scenarios */
55#define NEO_AUDIO_OFF 0
56#define NEO_GSM_CALL_AUDIO_HANDSET 1
57#define NEO_GSM_CALL_AUDIO_HEADSET 2
58#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3
59#define NEO_STEREO_TO_SPEAKERS 4
60#define NEO_STEREO_TO_HEADPHONES 5
61#define NEO_CAPTURE_HANDSET 6
62#define NEO_CAPTURE_HEADSET 7
63#define NEO_CAPTURE_BLUETOOTH 8
64
65static struct snd_soc_machine neo1973;
66static struct i2c_client *i2c;
67
68static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
69 struct snd_pcm_hw_params *params)
70{
71 struct snd_soc_pcm_runtime *rtd = substream->private_data;
72 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
73 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
74 unsigned int pll_out = 0, bclk = 0;
75 int ret = 0;
76 unsigned long iis_clkrate;
77
Tim Niemeyer1894c592008-05-05 14:16:12 +020078 DBG("Entered %s\n", __func__);
79
Graeme Gregory74930bb2007-05-14 11:03:52 +020080 iis_clkrate = s3c24xx_i2s_get_clockrate();
81
82 switch (params_rate(params)) {
83 case 8000:
84 case 16000:
85 pll_out = 12288000;
86 break;
87 case 48000:
88 bclk = WM8753_BCLK_DIV_4;
89 pll_out = 12288000;
90 break;
91 case 96000:
92 bclk = WM8753_BCLK_DIV_2;
93 pll_out = 12288000;
94 break;
95 case 11025:
96 bclk = WM8753_BCLK_DIV_16;
97 pll_out = 11289600;
98 break;
99 case 22050:
100 bclk = WM8753_BCLK_DIV_8;
101 pll_out = 11289600;
102 break;
103 case 44100:
104 bclk = WM8753_BCLK_DIV_4;
105 pll_out = 11289600;
106 break;
107 case 88200:
108 bclk = WM8753_BCLK_DIV_2;
109 pll_out = 11289600;
110 break;
111 }
112
113 /* set codec DAI configuration */
114 ret = codec_dai->dai_ops.set_fmt(codec_dai,
115 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
116 SND_SOC_DAIFMT_CBM_CFM);
117 if (ret < 0)
118 return ret;
119
120 /* set cpu DAI configuration */
121 ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
122 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
123 SND_SOC_DAIFMT_CBM_CFM);
124 if (ret < 0)
125 return ret;
126
127 /* set the codec system clock for DAC and ADC */
128 ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
129 SND_SOC_CLOCK_IN);
130 if (ret < 0)
131 return ret;
132
133 /* set MCLK division for sample rate */
134 ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200135 S3C2410_IISMOD_32FS);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200136 if (ret < 0)
137 return ret;
138
139 /* set codec BCLK division for sample rate */
140 ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
141 if (ret < 0)
142 return ret;
143
144 /* set prescaler division for sample rate */
145 ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200146 S3C24XX_PRESCALE(4, 4));
Graeme Gregory74930bb2007-05-14 11:03:52 +0200147 if (ret < 0)
148 return ret;
149
150 /* codec PLL input is PCLK/4 */
151 ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1,
152 iis_clkrate / 4, pll_out);
153 if (ret < 0)
154 return ret;
155
156 return 0;
157}
158
159static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
160{
161 struct snd_soc_pcm_runtime *rtd = substream->private_data;
162 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
163
Tim Niemeyer1894c592008-05-05 14:16:12 +0200164 DBG("Entered %s\n", __func__);
165
Graeme Gregory74930bb2007-05-14 11:03:52 +0200166 /* disable the PLL */
167 return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
168}
169
170/*
171 * Neo1973 WM8753 HiFi DAI opserations.
172 */
173static struct snd_soc_ops neo1973_hifi_ops = {
174 .hw_params = neo1973_hifi_hw_params,
175 .hw_free = neo1973_hifi_hw_free,
176};
177
178static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
179 struct snd_pcm_hw_params *params)
180{
181 struct snd_soc_pcm_runtime *rtd = substream->private_data;
182 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
183 unsigned int pcmdiv = 0;
184 int ret = 0;
185 unsigned long iis_clkrate;
186
Tim Niemeyer1894c592008-05-05 14:16:12 +0200187 DBG("Entered %s\n", __func__);
188
Graeme Gregory74930bb2007-05-14 11:03:52 +0200189 iis_clkrate = s3c24xx_i2s_get_clockrate();
190
191 if (params_rate(params) != 8000)
192 return -EINVAL;
193 if (params_channels(params) != 1)
194 return -EINVAL;
195
196 pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
197
198 /* todo: gg check mode (DSP_B) against CSR datasheet */
199 /* set codec DAI configuration */
200 ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
201 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
202 if (ret < 0)
203 return ret;
204
205 /* set the codec system clock for DAC and ADC */
206 ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
207 SND_SOC_CLOCK_IN);
208 if (ret < 0)
209 return ret;
210
211 /* set codec PCM division for sample rate */
212 ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
213 if (ret < 0)
214 return ret;
215
216 /* configue and enable PLL for 12.288MHz output */
217 ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2,
218 iis_clkrate / 4, 12288000);
219 if (ret < 0)
220 return ret;
221
222 return 0;
223}
224
225static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
226{
227 struct snd_soc_pcm_runtime *rtd = substream->private_data;
228 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
229
Tim Niemeyer1894c592008-05-05 14:16:12 +0200230 DBG("Entered %s\n", __func__);
231
Graeme Gregory74930bb2007-05-14 11:03:52 +0200232 /* disable the PLL */
233 return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
234}
235
236static struct snd_soc_ops neo1973_voice_ops = {
237 .hw_params = neo1973_voice_hw_params,
238 .hw_free = neo1973_voice_hw_free,
239};
240
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200241static int neo1973_scenario;
Graeme Gregory74930bb2007-05-14 11:03:52 +0200242
243static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
244 struct snd_ctl_elem_value *ucontrol)
245{
246 ucontrol->value.integer.value[0] = neo1973_scenario;
247 return 0;
248}
249
250static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
251{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200252 DBG("Entered %s\n", __func__);
253
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200254 switch (neo1973_scenario) {
Graeme Gregory74930bb2007-05-14 11:03:52 +0200255 case NEO_AUDIO_OFF:
256 snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
257 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
258 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
259 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
260 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
261 break;
262 case NEO_GSM_CALL_AUDIO_HANDSET:
263 snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
264 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
265 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
266 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
267 snd_soc_dapm_set_endpoint(codec, "Call Mic", 1);
268 break;
269 case NEO_GSM_CALL_AUDIO_HEADSET:
270 snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
271 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
272 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
273 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1);
274 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
275 break;
276 case NEO_GSM_CALL_AUDIO_BLUETOOTH:
277 snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
278 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
279 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
280 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
281 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
282 break;
283 case NEO_STEREO_TO_SPEAKERS:
284 snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
285 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
286 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
287 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
288 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
289 break;
290 case NEO_STEREO_TO_HEADPHONES:
291 snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
292 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
293 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
294 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
295 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
296 break;
297 case NEO_CAPTURE_HANDSET:
298 snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
299 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
300 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
301 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
302 snd_soc_dapm_set_endpoint(codec, "Call Mic", 1);
303 break;
304 case NEO_CAPTURE_HEADSET:
305 snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
306 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
307 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
308 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1);
309 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
310 break;
311 case NEO_CAPTURE_BLUETOOTH:
312 snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
313 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
314 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
315 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
316 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
317 break;
318 default:
319 snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
320 snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
321 snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
322 snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
323 snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
324 }
325
326 snd_soc_dapm_sync_endpoints(codec);
327
328 return 0;
329}
330
331static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
332 struct snd_ctl_elem_value *ucontrol)
333{
334 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
335
Tim Niemeyer1894c592008-05-05 14:16:12 +0200336 DBG("Entered %s\n", __func__);
337
Graeme Gregory74930bb2007-05-14 11:03:52 +0200338 if (neo1973_scenario == ucontrol->value.integer.value[0])
339 return 0;
340
341 neo1973_scenario = ucontrol->value.integer.value[0];
342 set_scenario_endpoints(codec, neo1973_scenario);
343 return 1;
344}
345
346static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
347
348static void lm4857_write_regs(void)
349{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200350 DBG("Entered %s\n", __func__);
351
Graeme Gregory74930bb2007-05-14 11:03:52 +0200352 if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
353 printk(KERN_ERR "lm4857: i2c write failed\n");
354}
355
356static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
357 struct snd_ctl_elem_value *ucontrol)
358{
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200359 int reg = kcontrol->private_value & 0xFF;
Graeme Gregory74930bb2007-05-14 11:03:52 +0200360 int shift = (kcontrol->private_value >> 8) & 0x0F;
361 int mask = (kcontrol->private_value >> 16) & 0xFF;
362
Tim Niemeyer1894c592008-05-05 14:16:12 +0200363 DBG("Entered %s\n", __func__);
364
Graeme Gregory74930bb2007-05-14 11:03:52 +0200365 ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
366 return 0;
367}
368
369static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
370 struct snd_ctl_elem_value *ucontrol)
371{
372 int reg = kcontrol->private_value & 0xFF;
373 int shift = (kcontrol->private_value >> 8) & 0x0F;
374 int mask = (kcontrol->private_value >> 16) & 0xFF;
375
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200376 if (((lm4857_regs[reg] >> shift) & mask) ==
Graeme Gregory74930bb2007-05-14 11:03:52 +0200377 ucontrol->value.integer.value[0])
378 return 0;
379
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200380 lm4857_regs[reg] &= ~(mask << shift);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200381 lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
382 lm4857_write_regs();
383 return 1;
384}
385
386static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
387 struct snd_ctl_elem_value *ucontrol)
388{
389 u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
390
Tim Niemeyer1894c592008-05-05 14:16:12 +0200391 DBG("Entered %s\n", __func__);
392
Graeme Gregory74930bb2007-05-14 11:03:52 +0200393 if (value)
394 value -= 5;
395
396 ucontrol->value.integer.value[0] = value;
397 return 0;
398}
399
400static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
401 struct snd_ctl_elem_value *ucontrol)
402{
403 u8 value = ucontrol->value.integer.value[0];
404
Tim Niemeyer1894c592008-05-05 14:16:12 +0200405 DBG("Entered %s\n", __func__);
406
Graeme Gregory74930bb2007-05-14 11:03:52 +0200407 if (value)
408 value += 5;
409
410 if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
411 return 0;
412
413 lm4857_regs[LM4857_CTRL] &= 0xF0;
414 lm4857_regs[LM4857_CTRL] |= value;
415 lm4857_write_regs();
416 return 1;
417}
418
419static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
420 SND_SOC_DAPM_LINE("Audio Out", NULL),
421 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
422 SND_SOC_DAPM_LINE("GSM Line In", NULL),
423 SND_SOC_DAPM_MIC("Headset Mic", NULL),
424 SND_SOC_DAPM_MIC("Call Mic", NULL),
425};
426
427
Mark Brown8f3112d2008-05-13 14:58:03 +0200428static const struct snd_soc_dapm_route dapm_routes[] = {
Graeme Gregory74930bb2007-05-14 11:03:52 +0200429
430 /* Connections to the lm4857 amp */
431 {"Audio Out", NULL, "LOUT1"},
432 {"Audio Out", NULL, "ROUT1"},
433
434 /* Connections to the GSM Module */
435 {"GSM Line Out", NULL, "MONO1"},
436 {"GSM Line Out", NULL, "MONO2"},
437 {"RXP", NULL, "GSM Line In"},
438 {"RXN", NULL, "GSM Line In"},
439
440 /* Connections to Headset */
441 {"MIC1", NULL, "Mic Bias"},
442 {"Mic Bias", NULL, "Headset Mic"},
443
444 /* Call Mic */
445 {"MIC2", NULL, "Mic Bias"},
446 {"MIC2N", NULL, "Mic Bias"},
447 {"Mic Bias", NULL, "Call Mic"},
448
449 /* Connect the ALC pins */
450 {"ACIN", NULL, "ACOP"},
Graeme Gregory74930bb2007-05-14 11:03:52 +0200451};
452
453static const char *lm4857_mode[] = {
454 "Off",
455 "Call Speaker",
456 "Stereo Speakers",
457 "Stereo Speakers + Headphones",
458 "Headphones"
459};
460
461static const struct soc_enum lm4857_mode_enum[] = {
462 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
463};
464
465static const char *neo_scenarios[] = {
466 "Off",
467 "GSM Handset",
468 "GSM Headset",
469 "GSM Bluetooth",
470 "Speakers",
471 "Headphones",
472 "Capture Handset",
473 "Capture Headset",
474 "Capture Bluetooth"
475};
476
477static const struct soc_enum neo_scenario_enum[] = {
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200478 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
Graeme Gregory74930bb2007-05-14 11:03:52 +0200479};
480
481static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
482 SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
483 lm4857_get_reg, lm4857_set_reg),
484 SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
485 lm4857_get_reg, lm4857_set_reg),
486 SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
487 lm4857_get_reg, lm4857_set_reg),
488 SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
489 lm4857_get_mode, lm4857_set_mode),
490 SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
491 neo1973_get_scenario, neo1973_set_scenario),
492 SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
493 lm4857_get_reg, lm4857_set_reg),
494 SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
495 lm4857_get_reg, lm4857_set_reg),
496 SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
497 lm4857_get_reg, lm4857_set_reg),
498 SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
499 lm4857_get_reg, lm4857_set_reg),
500};
501
502/*
503 * This is an example machine initialisation for a wm8753 connected to a
504 * neo1973 II. It is missing logic to detect hp/mic insertions and logic
505 * to re-route the audio in such an event.
506 */
507static int neo1973_wm8753_init(struct snd_soc_codec *codec)
508{
509 int i, err;
510
Tim Niemeyer1894c592008-05-05 14:16:12 +0200511 DBG("Entered %s\n", __func__);
512
Graeme Gregory74930bb2007-05-14 11:03:52 +0200513 /* set up NC codec pins */
514 snd_soc_dapm_set_endpoint(codec, "LOUT2", 0);
515 snd_soc_dapm_set_endpoint(codec, "ROUT2", 0);
516 snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
517 snd_soc_dapm_set_endpoint(codec, "OUT4", 0);
518 snd_soc_dapm_set_endpoint(codec, "LINE1", 0);
519 snd_soc_dapm_set_endpoint(codec, "LINE2", 0);
520
521
522 /* set endpoints to default mode */
523 set_scenario_endpoints(codec, NEO_AUDIO_OFF);
524
525 /* Add neo1973 specific widgets */
Mark Brown8f3112d2008-05-13 14:58:03 +0200526 snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
527 ARRAY_SIZE(wm8753_dapm_widgets));
Graeme Gregory74930bb2007-05-14 11:03:52 +0200528
529 /* add neo1973 specific controls */
530 for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
531 err = snd_ctl_add(codec->card,
532 snd_soc_cnew(&wm8753_neo1973_controls[i],
533 codec, NULL));
534 if (err < 0)
535 return err;
536 }
537
Mark Brown8f3112d2008-05-13 14:58:03 +0200538 /* set up neo1973 specific audio routes */
539 err = snd_soc_dapm_add_routes(codec, dapm_routes,
540 ARRAY_SIZE(dapm_routes));
Graeme Gregory74930bb2007-05-14 11:03:52 +0200541
542 snd_soc_dapm_sync_endpoints(codec);
543 return 0;
544}
545
546/*
547 * BT Codec DAI
548 */
Graeme Gregory8ba02ac2008-04-30 20:24:54 +0200549static struct snd_soc_cpu_dai bt_dai = {
550 .name = "Bluetooth",
Graeme Gregory74930bb2007-05-14 11:03:52 +0200551 .id = 0,
552 .type = SND_SOC_DAI_PCM,
553 .playback = {
554 .channels_min = 1,
555 .channels_max = 1,
556 .rates = SNDRV_PCM_RATE_8000,
557 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
558 .capture = {
559 .channels_min = 1,
560 .channels_max = 1,
561 .rates = SNDRV_PCM_RATE_8000,
562 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
563};
564
565static struct snd_soc_dai_link neo1973_dai[] = {
566{ /* Hifi Playback - for similatious use with voice below */
567 .name = "WM8753",
568 .stream_name = "WM8753 HiFi",
569 .cpu_dai = &s3c24xx_i2s_dai,
570 .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
571 .init = neo1973_wm8753_init,
572 .ops = &neo1973_hifi_ops,
573},
574{ /* Voice via BT */
575 .name = "Bluetooth",
576 .stream_name = "Voice",
577 .cpu_dai = &bt_dai,
578 .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
579 .ops = &neo1973_voice_ops,
580},
581};
582
583static struct snd_soc_machine neo1973 = {
584 .name = "neo1973",
585 .dai_link = neo1973_dai,
586 .num_links = ARRAY_SIZE(neo1973_dai),
587};
588
589static struct wm8753_setup_data neo1973_wm8753_setup = {
590 .i2c_address = 0x1a,
591};
592
593static struct snd_soc_device neo1973_snd_devdata = {
594 .machine = &neo1973,
595 .platform = &s3c24xx_soc_platform,
596 .codec_dev = &soc_codec_dev_wm8753,
597 .codec_data = &neo1973_wm8753_setup,
598};
599
600static struct i2c_client client_template;
601
Jean Delvare2cdddeb2008-01-27 18:14:47 +0100602static const unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
Graeme Gregory74930bb2007-05-14 11:03:52 +0200603
604/* Magic definition of all other variables and things */
605I2C_CLIENT_INSMOD;
606
607static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
608{
609 int ret;
610
Tim Niemeyer1894c592008-05-05 14:16:12 +0200611 DBG("Entered %s\n", __func__);
612
Graeme Gregory74930bb2007-05-14 11:03:52 +0200613 client_template.adapter = adap;
614 client_template.addr = addr;
615
616 i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
617 if (i2c == NULL)
618 return -ENOMEM;
619
620 ret = i2c_attach_client(i2c);
621 if (ret < 0) {
622 printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
623 goto exit_err;
624 }
625
626 lm4857_write_regs();
627 return ret;
628
629exit_err:
630 kfree(i2c);
631 return ret;
632}
633
634static int lm4857_i2c_detach(struct i2c_client *client)
635{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200636 DBG("Entered %s\n", __func__);
637
Graeme Gregory74930bb2007-05-14 11:03:52 +0200638 i2c_detach_client(client);
639 kfree(client);
640 return 0;
641}
642
643static int lm4857_i2c_attach(struct i2c_adapter *adap)
644{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200645 DBG("Entered %s\n", __func__);
646
Graeme Gregory74930bb2007-05-14 11:03:52 +0200647 return i2c_probe(adap, &addr_data, lm4857_amp_probe);
648}
649
Graeme Gregoryfd403dc2008-04-30 20:26:45 +0200650static u8 lm4857_state;
651
652static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
653{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200654 DBG("Entered %s\n", __func__);
655
Graeme Gregoryfd403dc2008-04-30 20:26:45 +0200656 dev_dbg(&dev->dev, "lm4857_suspend\n");
657 lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
658 if (lm4857_state) {
659 lm4857_regs[LM4857_CTRL] &= 0xf0;
660 lm4857_write_regs();
661 }
662 return 0;
663}
664
665static int lm4857_resume(struct i2c_client *dev)
666{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200667 DBG("Entered %s\n", __func__);
668
Graeme Gregoryfd403dc2008-04-30 20:26:45 +0200669 if (lm4857_state) {
670 lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
671 lm4857_write_regs();
672 }
673 return 0;
674}
675
676static void lm4857_shutdown(struct i2c_client *dev)
677{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200678 DBG("Entered %s\n", __func__);
679
Graeme Gregoryfd403dc2008-04-30 20:26:45 +0200680 dev_dbg(&dev->dev, "lm4857_shutdown\n");
681 lm4857_regs[LM4857_CTRL] &= 0xf0;
682 lm4857_write_regs();
683}
684
Graeme Gregory74930bb2007-05-14 11:03:52 +0200685/* corgi i2c codec control layer */
686static struct i2c_driver lm4857_i2c_driver = {
687 .driver = {
688 .name = "LM4857 I2C Amp",
689 .owner = THIS_MODULE,
690 },
691 .id = I2C_DRIVERID_LM4857,
Graeme Gregoryfd403dc2008-04-30 20:26:45 +0200692 .suspend = lm4857_suspend,
693 .resume = lm4857_resume,
694 .shutdown = lm4857_shutdown,
Graeme Gregory74930bb2007-05-14 11:03:52 +0200695 .attach_adapter = lm4857_i2c_attach,
696 .detach_client = lm4857_i2c_detach,
697 .command = NULL,
698};
699
700static struct i2c_client client_template = {
701 .name = "LM4857",
702 .driver = &lm4857_i2c_driver,
703};
704
705static struct platform_device *neo1973_snd_device;
706
707static int __init neo1973_init(void)
708{
709 int ret;
710
Tim Niemeyer1894c592008-05-05 14:16:12 +0200711 DBG("Entered %s\n", __func__);
712
Graeme Gregory74930bb2007-05-14 11:03:52 +0200713 neo1973_snd_device = platform_device_alloc("soc-audio", -1);
714 if (!neo1973_snd_device)
715 return -ENOMEM;
716
717 platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
718 neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
719 ret = platform_device_add(neo1973_snd_device);
720
721 if (ret)
722 platform_device_put(neo1973_snd_device);
723
724 ret = i2c_add_driver(&lm4857_i2c_driver);
725 if (ret != 0)
726 printk(KERN_ERR "can't add i2c driver");
727
728 return ret;
729}
730
731static void __exit neo1973_exit(void)
732{
Tim Niemeyer1894c592008-05-05 14:16:12 +0200733 DBG("Entered %s\n", __func__);
734
Tim Niemeyer6b9a9b32008-04-22 17:10:23 +0200735 i2c_del_driver(&lm4857_i2c_driver);
Graeme Gregory74930bb2007-05-14 11:03:52 +0200736 platform_device_unregister(neo1973_snd_device);
737}
738
739module_init(neo1973_init);
740module_exit(neo1973_exit);
741
742/* Module information */
Graeme Gregory443590e2008-04-30 20:25:23 +0200743MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
Graeme Gregory74930bb2007-05-14 11:03:52 +0200744MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
745MODULE_LICENSE("GPL");