neo1973_wm8753.c 17.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * neo1973_wm8753.c  --  SoC audio for Neo1973
 *
 * Copyright 2007 Wolfson Microelectronics PLC.
 * Author: Graeme Gregory
 *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
24
#include <sound/tlv.h>
25

26
#include <asm/mach-types.h>
27 28 29
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
30
#include <linux/io.h>
31
#include <mach/spi-gpio.h>
32

B
Ben Dooks 已提交
33
#include <plat/regs-iis.h>
34

35 36
#include "../codecs/wm8753.h"
#include "lm4857.h"
J
Jassi Brar 已提交
37
#include "dma.h"
38 39 40 41 42 43 44 45 46 47 48 49 50
#include "s3c24xx-i2s.h"

/* define the scenarios */
#define NEO_AUDIO_OFF			0
#define NEO_GSM_CALL_AUDIO_HANDSET	1
#define NEO_GSM_CALL_AUDIO_HEADSET	2
#define NEO_GSM_CALL_AUDIO_BLUETOOTH	3
#define NEO_STEREO_TO_SPEAKERS		4
#define NEO_STEREO_TO_HEADPHONES	5
#define NEO_CAPTURE_HANDSET		6
#define NEO_CAPTURE_HEADSET		7
#define NEO_CAPTURE_BLUETOOTH		8

51
static struct snd_soc_card neo1973;
52 53 54 55 56 57
static struct i2c_client *i2c;

static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
58 59
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
60 61 62 63
	unsigned int pll_out = 0, bclk = 0;
	int ret = 0;
	unsigned long iis_clkrate;

64
	pr_debug("Entered %s\n", __func__);
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	iis_clkrate = s3c24xx_i2s_get_clockrate();

	switch (params_rate(params)) {
	case 8000:
	case 16000:
		pll_out = 12288000;
		break;
	case 48000:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 12288000;
		break;
	case 96000:
		bclk = WM8753_BCLK_DIV_2;
		pll_out = 12288000;
		break;
	case 11025:
		bclk = WM8753_BCLK_DIV_16;
		pll_out = 11289600;
		break;
	case 22050:
		bclk = WM8753_BCLK_DIV_8;
		pll_out = 11289600;
		break;
	case 44100:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 11289600;
		break;
	case 88200:
		bclk = WM8753_BCLK_DIV_2;
		pll_out = 11289600;
		break;
	}

	/* set codec DAI configuration */
100
	ret = snd_soc_dai_set_fmt(codec_dai,
101 102 103 104 105 106
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* set cpu DAI configuration */
107
	ret = snd_soc_dai_set_fmt(cpu_dai,
108 109 110 111 112 113
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* set the codec system clock for DAC and ADC */
114
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
115 116 117 118 119
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	/* set MCLK division for sample rate */
120
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
121
		S3C2410_IISMOD_32FS);
122 123 124 125
	if (ret < 0)
		return ret;

	/* set codec BCLK division for sample rate */
126
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
127 128 129 130
	if (ret < 0)
		return ret;

	/* set prescaler division for sample rate */
131
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
132
		S3C24XX_PRESCALE(4, 4));
133 134 135 136
	if (ret < 0)
		return ret;

	/* codec PLL input is PCLK/4 */
137
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
138 139 140 141 142 143 144 145 146 147
		iis_clkrate / 4, pll_out);
	if (ret < 0)
		return ret;

	return 0;
}

static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
148
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
149

150
	pr_debug("Entered %s\n", __func__);
151

152
	/* disable the PLL */
153
	return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
154 155 156 157 158 159 160 161 162 163 164 165 166 167
}

/*
 * Neo1973 WM8753 HiFi DAI opserations.
 */
static struct snd_soc_ops neo1973_hifi_ops = {
	.hw_params = neo1973_hifi_hw_params,
	.hw_free = neo1973_hifi_hw_free,
};

static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
168
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
169 170 171 172
	unsigned int pcmdiv = 0;
	int ret = 0;
	unsigned long iis_clkrate;

173
	pr_debug("Entered %s\n", __func__);
174

175 176 177 178 179 180 181 182 183 184 185
	iis_clkrate = s3c24xx_i2s_get_clockrate();

	if (params_rate(params) != 8000)
		return -EINVAL;
	if (params_channels(params) != 1)
		return -EINVAL;

	pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */

	/* todo: gg check mode (DSP_B) against CSR datasheet */
	/* set codec DAI configuration */
186
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
187 188 189 190 191
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

	/* set the codec system clock for DAC and ADC */
192
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
193 194 195 196 197
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	/* set codec PCM division for sample rate */
198
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
199 200 201
	if (ret < 0)
		return ret;

A
Andrea Gelmini 已提交
202
	/* configure and enable PLL for 12.288MHz output */
203
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
204 205 206 207 208 209 210 211 212 213
		iis_clkrate / 4, 12288000);
	if (ret < 0)
		return ret;

	return 0;
}

static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
214
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
215

216
	pr_debug("Entered %s\n", __func__);
217

218
	/* disable the PLL */
219
	return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
220 221 222 223 224 225 226
}

static struct snd_soc_ops neo1973_voice_ops = {
	.hw_params = neo1973_voice_hw_params,
	.hw_free = neo1973_voice_hw_free,
};

227
static int neo1973_scenario;
228 229 230 231 232 233 234 235 236 237

static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	ucontrol->value.integer.value[0] = neo1973_scenario;
	return 0;
}

static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
{
L
Liam Girdwood 已提交
238 239
	struct snd_soc_dapm_context *dapm = &codec->dapm;

240
	pr_debug("Entered %s\n", __func__);
241

242
	switch (neo1973_scenario) {
243
	case NEO_AUDIO_OFF:
L
Liam Girdwood 已提交
244 245 246 247 248
		snd_soc_dapm_disable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
249 250
		break;
	case NEO_GSM_CALL_AUDIO_HANDSET:
L
Liam Girdwood 已提交
251 252 253 254 255
		snd_soc_dapm_enable_pin(dapm, "Audio Out");
		snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_enable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_enable_pin(dapm, "Call Mic");
256 257
		break;
	case NEO_GSM_CALL_AUDIO_HEADSET:
L
Liam Girdwood 已提交
258 259 260 261 262
		snd_soc_dapm_enable_pin(dapm, "Audio Out");
		snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_enable_pin(dapm, "GSM Line In");
		snd_soc_dapm_enable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
263 264
		break;
	case NEO_GSM_CALL_AUDIO_BLUETOOTH:
L
Liam Girdwood 已提交
265 266 267 268 269
		snd_soc_dapm_disable_pin(dapm, "Audio Out");
		snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_enable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
270 271
		break;
	case NEO_STEREO_TO_SPEAKERS:
L
Liam Girdwood 已提交
272 273 274 275 276
		snd_soc_dapm_enable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
277 278
		break;
	case NEO_STEREO_TO_HEADPHONES:
L
Liam Girdwood 已提交
279 280 281 282 283
		snd_soc_dapm_enable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
284 285
		break;
	case NEO_CAPTURE_HANDSET:
L
Liam Girdwood 已提交
286 287 288 289 290
		snd_soc_dapm_disable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_enable_pin(dapm, "Call Mic");
291 292
		break;
	case NEO_CAPTURE_HEADSET:
L
Liam Girdwood 已提交
293 294 295 296 297
		snd_soc_dapm_disable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_enable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
298 299
		break;
	case NEO_CAPTURE_BLUETOOTH:
L
Liam Girdwood 已提交
300 301 302 303 304
		snd_soc_dapm_disable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
305 306
		break;
	default:
L
Liam Girdwood 已提交
307 308 309 310 311
		snd_soc_dapm_disable_pin(dapm, "Audio Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
		snd_soc_dapm_disable_pin(dapm, "GSM Line In");
		snd_soc_dapm_disable_pin(dapm, "Headset Mic");
		snd_soc_dapm_disable_pin(dapm, "Call Mic");
312 313
	}

L
Liam Girdwood 已提交
314
	snd_soc_dapm_sync(dapm);
315 316 317 318 319 320 321 322 323

	return 0;
}

static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);

324
	pr_debug("Entered %s\n", __func__);
325

326 327 328 329 330 331 332 333 334 335 336 337
	if (neo1973_scenario == ucontrol->value.integer.value[0])
		return 0;

	neo1973_scenario = ucontrol->value.integer.value[0];
	set_scenario_endpoints(codec, neo1973_scenario);
	return 1;
}

static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};

static void lm4857_write_regs(void)
{
338
	pr_debug("Entered %s\n", __func__);
339

340 341 342 343 344 345 346
	if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
		printk(KERN_ERR "lm4857: i2c write failed\n");
}

static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
M
Mark Brown 已提交
347 348 349 350 351
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int reg = mc->reg;
	int shift = mc->shift;
	int mask = mc->max;
352

353
	pr_debug("Entered %s\n", __func__);
354

355 356 357 358 359 360 361
	ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
	return 0;
}

static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
M
Mark Brown 已提交
362 363 364 365 366
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int reg = mc->reg;
	int shift = mc->shift;
	int mask = mc->max;
367

368
	if (((lm4857_regs[reg] >> shift) & mask) ==
369 370 371
		ucontrol->value.integer.value[0])
		return 0;

372
	lm4857_regs[reg] &= ~(mask << shift);
373 374 375 376 377 378 379 380 381 382
	lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
	lm4857_write_regs();
	return 1;
}

static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;

383
	pr_debug("Entered %s\n", __func__);
384

385 386 387 388 389 390 391 392 393 394 395 396
	if (value)
		value -= 5;

	ucontrol->value.integer.value[0] = value;
	return 0;
}

static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	u8 value = ucontrol->value.integer.value[0];

397
	pr_debug("Entered %s\n", __func__);
398

399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
	if (value)
		value += 5;

	if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
		return 0;

	lm4857_regs[LM4857_CTRL] &= 0xF0;
	lm4857_regs[LM4857_CTRL] |= value;
	lm4857_write_regs();
	return 1;
}

static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
	SND_SOC_DAPM_LINE("Audio Out", NULL),
	SND_SOC_DAPM_LINE("GSM Line Out", NULL),
	SND_SOC_DAPM_LINE("GSM Line In", NULL),
	SND_SOC_DAPM_MIC("Headset Mic", NULL),
	SND_SOC_DAPM_MIC("Call Mic", NULL),
};


420
static const struct snd_soc_dapm_route dapm_routes[] = {
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

	/* Connections to the lm4857 amp */
	{"Audio Out", NULL, "LOUT1"},
	{"Audio Out", NULL, "ROUT1"},

	/* Connections to the GSM Module */
	{"GSM Line Out", NULL, "MONO1"},
	{"GSM Line Out", NULL, "MONO2"},
	{"RXP", NULL, "GSM Line In"},
	{"RXN", NULL, "GSM Line In"},

	/* Connections to Headset */
	{"MIC1", NULL, "Mic Bias"},
	{"Mic Bias", NULL, "Headset Mic"},

	/* Call Mic */
	{"MIC2", NULL, "Mic Bias"},
	{"MIC2N", NULL, "Mic Bias"},
	{"Mic Bias", NULL, "Call Mic"},

	/* Connect the ALC pins */
	{"ACIN", NULL, "ACOP"},
};

static const char *lm4857_mode[] = {
	"Off",
	"Call Speaker",
	"Stereo Speakers",
	"Stereo Speakers + Headphones",
	"Headphones"
};

static const struct soc_enum lm4857_mode_enum[] = {
	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
};

static const char *neo_scenarios[] = {
	"Off",
	"GSM Handset",
	"GSM Headset",
	"GSM Bluetooth",
	"Speakers",
	"Headphones",
	"Capture Handset",
	"Capture Headset",
	"Capture Bluetooth"
};

static const struct soc_enum neo_scenario_enum[] = {
470
	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
471 472
};

473 474 475
static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);

476
static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
477 478 479 480 481 482
	SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
		lm4857_get_reg, lm4857_set_reg, stereo_tlv),
	SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
		lm4857_get_reg, lm4857_set_reg, stereo_tlv),
	SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
		lm4857_get_reg, lm4857_set_reg, mono_tlv),
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
	SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
		lm4857_get_mode, lm4857_set_mode),
	SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
		neo1973_get_scenario, neo1973_set_scenario),
	SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
		lm4857_get_reg, lm4857_set_reg),
	SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
		lm4857_get_reg, lm4857_set_reg),
	SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
		lm4857_get_reg, lm4857_set_reg),
	SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
		lm4857_get_reg, lm4857_set_reg),
};

/*
 * This is an example machine initialisation for a wm8753 connected to a
 * neo1973 II. It is missing logic to detect hp/mic insertions and logic
 * to re-route the audio in such an event.
 */
502
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
503
{
504
	struct snd_soc_codec *codec = rtd->codec;
L
Liam Girdwood 已提交
505
	struct snd_soc_dapm_context *dapm = &codec->dapm;
506
	int err;
507

508
	pr_debug("Entered %s\n", __func__);
509

510
	/* set up NC codec pins */
L
Liam Girdwood 已提交
511 512 513 514 515 516
	snd_soc_dapm_nc_pin(dapm, "LOUT2");
	snd_soc_dapm_nc_pin(dapm, "ROUT2");
	snd_soc_dapm_nc_pin(dapm, "OUT3");
	snd_soc_dapm_nc_pin(dapm, "OUT4");
	snd_soc_dapm_nc_pin(dapm, "LINE1");
	snd_soc_dapm_nc_pin(dapm, "LINE2");
517 518

	/* Add neo1973 specific widgets */
L
Liam Girdwood 已提交
519
	snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
520
				  ARRAY_SIZE(wm8753_dapm_widgets));
521

522 523 524
	/* set endpoints to default mode */
	set_scenario_endpoints(codec, NEO_AUDIO_OFF);

525
	/* add neo1973 specific controls */
526 527 528 529
	err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
				ARRAY_SIZE(8753_neo1973_controls));
	if (err < 0)
		return err;
530

531
	/* set up neo1973 specific audio routes */
L
Liam Girdwood 已提交
532
	err = snd_soc_dapm_add_routes(dapm, dapm_routes,
533
				      ARRAY_SIZE(dapm_routes));
534

L
Liam Girdwood 已提交
535
	snd_soc_dapm_sync(dapm);
536 537 538 539 540 541
	return 0;
}

/*
 * BT Codec DAI
 */
542
static struct snd_soc_dai bt_dai = {
543
	.name = "bluetooth-dai",
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
	.playback = {
		.channels_min = 1,
		.channels_max = 1,
		.rates = SNDRV_PCM_RATE_8000,
		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
	.capture = {
		.channels_min = 1,
		.channels_max = 1,
		.rates = SNDRV_PCM_RATE_8000,
		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
};

static struct snd_soc_dai_link neo1973_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
	.name = "WM8753",
	.stream_name = "WM8753 HiFi",
J
Jassi Brar 已提交
560
	.platform_name = "samsung-audio",
561
	.cpu_dai_name = "s3c24xx-iis",
562
	.codec_dai_name = "wm8753-hifi",
563
	.codec_name = "wm8753-codec.0-001a",
564 565 566 567 568 569
	.init = neo1973_wm8753_init,
	.ops = &neo1973_hifi_ops,
},
{ /* Voice via BT */
	.name = "Bluetooth",
	.stream_name = "Voice",
J
Jassi Brar 已提交
570
	.platform_name = "samsung-audio",
571 572
	.cpu_dai_name = "bluetooth-dai",
	.codec_dai_name = "wm8753-voice",
573
	.codec_name = "wm8753-codec.0-001a",
574 575 576 577
	.ops = &neo1973_voice_ops,
},
};

578
static struct snd_soc_card neo1973 = {
579 580 581 582 583
	.name = "neo1973",
	.dai_link = neo1973_dai,
	.num_links = ARRAY_SIZE(neo1973_dai),
};

584 585
static int lm4857_i2c_probe(struct i2c_client *client,
			    const struct i2c_device_id *id)
586
{
587
	pr_debug("Entered %s\n", __func__);
588

589 590
	i2c = client;

591 592 593 594
	lm4857_write_regs();
	return 0;
}

595
static int lm4857_i2c_remove(struct i2c_client *client)
596
{
597
	pr_debug("Entered %s\n", __func__);
598

599 600
	i2c = NULL;

601
	return 0;
602 603
}

604 605 606 607
static u8 lm4857_state;

static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
{
608
	pr_debug("Entered %s\n", __func__);
609

610 611 612 613 614 615 616 617 618 619 620
	dev_dbg(&dev->dev, "lm4857_suspend\n");
	lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
	if (lm4857_state) {
		lm4857_regs[LM4857_CTRL] &= 0xf0;
		lm4857_write_regs();
	}
	return 0;
}

static int lm4857_resume(struct i2c_client *dev)
{
621
	pr_debug("Entered %s\n", __func__);
622

623 624 625 626 627 628 629 630 631
	if (lm4857_state) {
		lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
		lm4857_write_regs();
	}
	return 0;
}

static void lm4857_shutdown(struct i2c_client *dev)
{
632
	pr_debug("Entered %s\n", __func__);
633

634 635 636 637 638
	dev_dbg(&dev->dev, "lm4857_shutdown\n");
	lm4857_regs[LM4857_CTRL] &= 0xf0;
	lm4857_write_regs();
}

639
static const struct i2c_device_id lm4857_i2c_id[] = {
640
	{ "neo1973_lm4857", 0 },
641 642 643
	{ }
};

644 645 646 647 648
static struct i2c_driver lm4857_i2c_driver = {
	.driver = {
		.name = "LM4857 I2C Amp",
		.owner = THIS_MODULE,
	},
649 650 651
	.suspend =        lm4857_suspend,
	.resume	=         lm4857_resume,
	.shutdown =       lm4857_shutdown,
652 653 654
	.probe =          lm4857_i2c_probe,
	.remove =         lm4857_i2c_remove,
	.id_table =       lm4857_i2c_id,
655 656 657 658 659 660 661 662
};

static struct platform_device *neo1973_snd_device;

static int __init neo1973_init(void)
{
	int ret;

663
	pr_debug("Entered %s\n", __func__);
664

665 666 667 668 669 670
	if (!machine_is_neo1973_gta01()) {
		printk(KERN_INFO
			"Only GTA01 hardware supported by ASoC driver\n");
		return -ENODEV;
	}

671 672 673 674
	neo1973_snd_device = platform_device_alloc("soc-audio", -1);
	if (!neo1973_snd_device)
		return -ENOMEM;

675
	platform_set_drvdata(neo1973_snd_device, &neo1973);
676 677
	ret = platform_device_add(neo1973_snd_device);

678
	if (ret) {
679
		platform_device_put(neo1973_snd_device);
680 681
		return ret;
	}
682

683 684
	ret = i2c_add_driver(&lm4857_i2c_driver);

685
	if (ret != 0)
686
		platform_device_unregister(neo1973_snd_device);
687 688 689 690 691 692

	return ret;
}

static void __exit neo1973_exit(void)
{
693
	pr_debug("Entered %s\n", __func__);
694

695
	i2c_del_driver(&lm4857_i2c_driver);
696 697 698 699 700 701 702
	platform_device_unregister(neo1973_snd_device);
}

module_init(neo1973_init);
module_exit(neo1973_exit);

/* Module information */
703
MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
704 705
MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
MODULE_LICENSE("GPL");