neo1973_wm8753.c 14.0 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
#include "s3c24xx-i2s.h"

40
static struct snd_soc_card neo1973;
41 42 43 44 45 46
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;
47 48
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
49 50 51 52
	unsigned int pll_out = 0, bclk = 0;
	int ret = 0;
	unsigned long iis_clkrate;

53
	pr_debug("Entered %s\n", __func__);
54

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
	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 */
89
	ret = snd_soc_dai_set_fmt(codec_dai,
90 91 92 93 94 95
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* set cpu DAI configuration */
96
	ret = snd_soc_dai_set_fmt(cpu_dai,
97 98 99 100 101 102
		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 */
103
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
104 105 106 107 108
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	/* set MCLK division for sample rate */
109
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
110
		S3C2410_IISMOD_32FS);
111 112 113 114
	if (ret < 0)
		return ret;

	/* set codec BCLK division for sample rate */
115
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
116 117 118 119
	if (ret < 0)
		return ret;

	/* set prescaler division for sample rate */
120
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
121
		S3C24XX_PRESCALE(4, 4));
122 123 124 125
	if (ret < 0)
		return ret;

	/* codec PLL input is PCLK/4 */
126
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
127 128 129 130 131 132 133 134 135 136
		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;
137
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
138

139
	pr_debug("Entered %s\n", __func__);
140

141
	/* disable the PLL */
142
	return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
143 144 145 146 147 148 149 150 151 152 153 154 155 156
}

/*
 * 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;
157
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
158 159 160 161
	unsigned int pcmdiv = 0;
	int ret = 0;
	unsigned long iis_clkrate;

162
	pr_debug("Entered %s\n", __func__);
163

164 165 166 167 168 169 170 171 172 173 174
	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 */
175
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
176 177 178 179 180
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

	/* set the codec system clock for DAC and ADC */
181
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
182 183 184 185 186
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	/* set codec PCM division for sample rate */
187
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
188 189 190
	if (ret < 0)
		return ret;

A
Andrea Gelmini 已提交
191
	/* configure and enable PLL for 12.288MHz output */
192
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
193 194 195 196 197 198 199 200 201 202
		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;
203
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
204

205
	pr_debug("Entered %s\n", __func__);
206

207
	/* disable the PLL */
208
	return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
209 210 211 212 213 214 215 216 217 218 219
}

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

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

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

222 223 224 225 226 227 228
	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 已提交
229 230 231 232 233
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int reg = mc->reg;
	int shift = mc->shift;
	int mask = mc->max;
234

235
	pr_debug("Entered %s\n", __func__);
236

237 238 239 240 241 242 243
	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 已提交
244 245 246 247 248
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int reg = mc->reg;
	int shift = mc->shift;
	int mask = mc->max;
249

250
	if (((lm4857_regs[reg] >> shift) & mask) ==
251 252 253
		ucontrol->value.integer.value[0])
		return 0;

254
	lm4857_regs[reg] &= ~(mask << shift);
255 256 257 258 259 260 261 262 263 264
	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;

265
	pr_debug("Entered %s\n", __func__);
266

267 268 269 270 271 272 273 274 275 276 277 278
	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];

279
	pr_debug("Entered %s\n", __func__);
280

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
	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),
};


302
static const struct snd_soc_dapm_route dapm_routes[] = {
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

	/* 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),
};

339 340 341
static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);

342
static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
343 344 345 346 347 348
	SOC_DAPM_PIN_SWITCH("Audio Out"),
	SOC_DAPM_PIN_SWITCH("GSM Line Out"),
	SOC_DAPM_PIN_SWITCH("GSM Line In"),
	SOC_DAPM_PIN_SWITCH("Headset Mic"),
	SOC_DAPM_PIN_SWITCH("Call Mic"),

349 350 351 352 353 354
	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),
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
		lm4857_get_mode, lm4857_set_mode),
	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.
 */
372
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
373
{
374
	struct snd_soc_codec *codec = rtd->codec;
L
Liam Girdwood 已提交
375
	struct snd_soc_dapm_context *dapm = &codec->dapm;
376
	int err;
377

378
	pr_debug("Entered %s\n", __func__);
379

380
	/* set up NC codec pins */
L
Liam Girdwood 已提交
381 382 383 384 385 386
	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");
387 388

	/* Add neo1973 specific widgets */
L
Liam Girdwood 已提交
389
	snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
390
				  ARRAY_SIZE(wm8753_dapm_widgets));
391

392
	/* set endpoints to default mode */
393 394 395 396 397
	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");
398

399
	/* add neo1973 specific controls */
400 401 402 403
	err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
				ARRAY_SIZE(8753_neo1973_controls));
	if (err < 0)
		return err;
404

405
	/* set up neo1973 specific audio routes */
L
Liam Girdwood 已提交
406
	err = snd_soc_dapm_add_routes(dapm, dapm_routes,
407
				      ARRAY_SIZE(dapm_routes));
408

L
Liam Girdwood 已提交
409
	snd_soc_dapm_sync(dapm);
410 411 412 413 414 415
	return 0;
}

/*
 * BT Codec DAI
 */
416
static struct snd_soc_dai bt_dai = {
417
	.name = "bluetooth-dai",
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	.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 已提交
434
	.platform_name = "samsung-audio",
435
	.cpu_dai_name = "s3c24xx-iis",
436
	.codec_dai_name = "wm8753-hifi",
437
	.codec_name = "wm8753-codec.0-001a",
438 439 440 441 442 443
	.init = neo1973_wm8753_init,
	.ops = &neo1973_hifi_ops,
},
{ /* Voice via BT */
	.name = "Bluetooth",
	.stream_name = "Voice",
J
Jassi Brar 已提交
444
	.platform_name = "samsung-audio",
445 446
	.cpu_dai_name = "bluetooth-dai",
	.codec_dai_name = "wm8753-voice",
447
	.codec_name = "wm8753-codec.0-001a",
448 449 450 451
	.ops = &neo1973_voice_ops,
},
};

452
static struct snd_soc_card neo1973 = {
453 454 455 456 457
	.name = "neo1973",
	.dai_link = neo1973_dai,
	.num_links = ARRAY_SIZE(neo1973_dai),
};

458 459
static int lm4857_i2c_probe(struct i2c_client *client,
			    const struct i2c_device_id *id)
460
{
461
	pr_debug("Entered %s\n", __func__);
462

463 464
	i2c = client;

465 466 467 468
	lm4857_write_regs();
	return 0;
}

469
static int lm4857_i2c_remove(struct i2c_client *client)
470
{
471
	pr_debug("Entered %s\n", __func__);
472

473 474
	i2c = NULL;

475
	return 0;
476 477
}

478 479 480 481
static u8 lm4857_state;

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

484 485 486 487 488 489 490 491 492 493 494
	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)
{
495
	pr_debug("Entered %s\n", __func__);
496

497 498 499 500 501 502 503 504 505
	if (lm4857_state) {
		lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
		lm4857_write_regs();
	}
	return 0;
}

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

508 509 510 511 512
	dev_dbg(&dev->dev, "lm4857_shutdown\n");
	lm4857_regs[LM4857_CTRL] &= 0xf0;
	lm4857_write_regs();
}

513
static const struct i2c_device_id lm4857_i2c_id[] = {
514
	{ "neo1973_lm4857", 0 },
515 516 517
	{ }
};

518 519 520 521 522
static struct i2c_driver lm4857_i2c_driver = {
	.driver = {
		.name = "LM4857 I2C Amp",
		.owner = THIS_MODULE,
	},
523 524 525
	.suspend =        lm4857_suspend,
	.resume	=         lm4857_resume,
	.shutdown =       lm4857_shutdown,
526 527 528
	.probe =          lm4857_i2c_probe,
	.remove =         lm4857_i2c_remove,
	.id_table =       lm4857_i2c_id,
529 530 531 532 533 534 535 536
};

static struct platform_device *neo1973_snd_device;

static int __init neo1973_init(void)
{
	int ret;

537
	pr_debug("Entered %s\n", __func__);
538

539 540 541 542 543 544
	if (!machine_is_neo1973_gta01()) {
		printk(KERN_INFO
			"Only GTA01 hardware supported by ASoC driver\n");
		return -ENODEV;
	}

545 546 547 548
	neo1973_snd_device = platform_device_alloc("soc-audio", -1);
	if (!neo1973_snd_device)
		return -ENOMEM;

549
	platform_set_drvdata(neo1973_snd_device, &neo1973);
550 551
	ret = platform_device_add(neo1973_snd_device);

552
	if (ret) {
553
		platform_device_put(neo1973_snd_device);
554 555
		return ret;
	}
556

557 558
	ret = i2c_add_driver(&lm4857_i2c_driver);

559
	if (ret != 0)
560
		platform_device_unregister(neo1973_snd_device);
561 562 563 564 565 566

	return ret;
}

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

569
	i2c_del_driver(&lm4857_i2c_driver);
570 571 572 573 574 575 576
	platform_device_unregister(neo1973_snd_device);
}

module_init(neo1973_init);
module_exit(neo1973_exit);

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