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
#include <asm/hardware/scoop.h>
28 29 30
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
31
#include <linux/io.h>
32
#include <mach/spi-gpio.h>
33

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

36 37
#include "../codecs/wm8753.h"
#include "lm4857.h"
J
Jassi Brar 已提交
38
#include "dma.h"
39 40 41 42 43 44 45 46 47 48 49 50 51
#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

52
static struct snd_soc_card neo1973;
53 54 55 56 57 58
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;
59 60
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
61 62 63 64
	unsigned int pll_out = 0, bclk = 0;
	int ret = 0;
	unsigned long iis_clkrate;

65
	pr_debug("Entered %s\n", __func__);
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 100
	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 */
101
	ret = snd_soc_dai_set_fmt(codec_dai,
102 103 104 105 106 107
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* set cpu DAI configuration */
108
	ret = snd_soc_dai_set_fmt(cpu_dai,
109 110 111 112 113 114
		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 */
115
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
116 117 118 119 120
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

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

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

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

	/* codec PLL input is PCLK/4 */
138
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
139 140 141 142 143 144 145 146 147 148
		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;
149
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
150

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

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

/*
 * 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;
169
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
170 171 172 173
	unsigned int pcmdiv = 0;
	int ret = 0;
	unsigned long iis_clkrate;

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

176 177 178 179 180 181 182 183 184 185 186
	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 */
187
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
188 189 190 191 192
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

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

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

A
Andrea Gelmini 已提交
203
	/* configure and enable PLL for 12.288MHz output */
204
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
205 206 207 208 209 210 211 212 213 214
		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;
215
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
216

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

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

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

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

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 已提交
239 240
	struct snd_soc_dapm_context *dapm = &codec->dapm;

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

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

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

	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);

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

327 328 329 330 331 332 333 334 335 336 337 338
	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)
{
339
	pr_debug("Entered %s\n", __func__);
340

341 342 343 344 345 346 347
	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 已提交
348 349 350 351 352
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int reg = mc->reg;
	int shift = mc->shift;
	int mask = mc->max;
353

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

356 357 358 359 360 361 362
	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 已提交
363 364 365 366 367
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int reg = mc->reg;
	int shift = mc->shift;
	int mask = mc->max;
368

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

373
	lm4857_regs[reg] &= ~(mask << shift);
374 375 376 377 378 379 380 381 382 383
	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;

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

386 387 388 389 390 391 392 393 394 395 396 397
	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];

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

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
	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),
};


421
static const struct snd_soc_dapm_route dapm_routes[] = {
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 470

	/* 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[] = {
471
	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
472 473
};

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

477
static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
478 479 480 481 482 483
	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),
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
	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.
 */
503
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
504
{
505
	struct snd_soc_codec *codec = rtd->codec;
L
Liam Girdwood 已提交
506
	struct snd_soc_dapm_context *dapm = &codec->dapm;
507
	int err;
508

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

511
	/* set up NC codec pins */
L
Liam Girdwood 已提交
512 513 514 515 516 517
	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");
518 519

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

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

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

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

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

/*
 * BT Codec DAI
 */
543
static struct snd_soc_dai bt_dai = {
544
	.name = "bluetooth-dai",
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
	.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 已提交
561
	.platform_name = "samsung-audio",
562
	.cpu_dai_name = "s3c24xx-iis",
563
	.codec_dai_name = "wm8753-hifi",
564
	.codec_name = "wm8753-codec.0-001a",
565 566 567 568 569 570
	.init = neo1973_wm8753_init,
	.ops = &neo1973_hifi_ops,
},
{ /* Voice via BT */
	.name = "Bluetooth",
	.stream_name = "Voice",
J
Jassi Brar 已提交
571
	.platform_name = "samsung-audio",
572 573
	.cpu_dai_name = "bluetooth-dai",
	.codec_dai_name = "wm8753-voice",
574
	.codec_name = "wm8753-codec.0-001a",
575 576 577 578
	.ops = &neo1973_voice_ops,
},
};

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

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

590 591
	i2c = client;

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

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

600 601
	i2c = NULL;

602
	return 0;
603 604
}

605 606 607 608
static u8 lm4857_state;

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

611 612 613 614 615 616 617 618 619 620 621
	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)
{
622
	pr_debug("Entered %s\n", __func__);
623

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

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

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

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

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

static struct platform_device *neo1973_snd_device;

static int __init neo1973_init(void)
{
	int ret;

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

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

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

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

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

684 685
	ret = i2c_add_driver(&lm4857_i2c_driver);

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

	return ret;
}

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

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

module_init(neo1973_init);
module_exit(neo1973_exit);

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