omap-mcbsp.c 22.7 KB
Newer Older
1 2 3 4 5
/*
 * omap-mcbsp.c  --  OMAP ALSA SoC DAI driver using McBSP port
 *
 * Copyright (C) 2008 Nokia Corporation
 *
6
 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7
 *          Peter Ujfalusi <peter.ujfalusi@ti.com>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
28
#include <linux/pm_runtime.h>
29 30
#include <linux/of.h>
#include <linux/of_device.h>
31 32 33 34 35 36
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>

37 38
#include <plat/dma.h>
#include <plat/mcbsp.h>
39
#include "mcbsp.h"
40 41 42
#include "omap-mcbsp.h"
#include "omap-pcm.h"

43
#define OMAP_MCBSP_RATES	(SNDRV_PCM_RATE_8000_96000)
44

45 46 47 48 49 50 51 52
#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \
	xhandler_get, xhandler_put) \
{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
	.info = omap_mcbsp_st_info_volsw, \
	.get = xhandler_get, .put = xhandler_put, \
	.private_value = (unsigned long) &(struct soc_mixer_control) \
	{.min = xmin, .max = xmax} }

53 54 55 56 57 58 59 60 61
enum {
	OMAP_MCBSP_WORD_8 = 0,
	OMAP_MCBSP_WORD_12,
	OMAP_MCBSP_WORD_16,
	OMAP_MCBSP_WORD_20,
	OMAP_MCBSP_WORD_24,
	OMAP_MCBSP_WORD_32,
};

62 63 64 65
/*
 * Stream DMA parameters. DMA request line and port address are set runtime
 * since they are different between OMAP1 and later OMAPs
 */
66 67 68
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
69
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
70
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
71
	struct omap_pcm_dma_data *dma_data;
72
	int words;
73

74
	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
75

76 77 78 79 80 81 82 83 84 85 86
	/*
	 * Configure McBSP threshold based on either:
	 * packet_size, when the sDMA is in packet mode, or based on the
	 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
	 * for mono streams.
	 */
	if (dma_data->packet_size)
		words = dma_data->packet_size;
	else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
		words = snd_pcm_lib_period_bytes(substream) /
						(mcbsp->wlen / 8);
87
	else
88
		words = 1;
89 90 91

	/* Configure McBSP internal buffer usage */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
92
		omap_mcbsp_set_tx_threshold(mcbsp, words);
93
	else
94
		omap_mcbsp_set_rx_threshold(mcbsp, words);
95 96
}

97 98 99 100 101 102 103
static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
				    struct snd_pcm_hw_rule *rule)
{
	struct snd_interval *buffer_size = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
	struct snd_interval *channels = hw_param_interval(params,
					SNDRV_PCM_HW_PARAM_CHANNELS);
104
	struct omap_mcbsp *mcbsp = rule->private;
105 106 107 108
	struct snd_interval frames;
	int size;

	snd_interval_any(&frames);
109
	size = mcbsp->pdata->buffer_size;
110 111 112 113 114 115

	frames.min = size / channels->min;
	frames.integer = 1;
	return snd_interval_refine(buffer_size, &frames);
}

116
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
117
				  struct snd_soc_dai *cpu_dai)
118
{
119
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
120 121
	int err = 0;

122
	if (!cpu_dai->active)
123
		err = omap_mcbsp_request(mcbsp);
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	/*
	 * OMAP3 McBSP FIFO is word structured.
	 * McBSP2 has 1024 + 256 = 1280 word long buffer,
	 * McBSP1,3,4,5 has 128 word long buffer
	 * This means that the size of the FIFO depends on the sample format.
	 * For example on McBSP3:
	 * 16bit samples: size is 128 * 2 = 256 bytes
	 * 32bit samples: size is 128 * 4 = 512 bytes
	 * It is simpler to place constraint for buffer and period based on
	 * channels.
	 * McBSP3 as example again (16 or 32 bit samples):
	 * 1 channel (mono): size is 128 frames (128 words)
	 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
	 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
	 */
140
	if (mcbsp->pdata->buffer_size) {
141
		/*
142
		* Rule for the buffer size. We should not allow
143 144
		* smaller buffer than the FIFO size to avoid underruns.
		* This applies only for the playback stream.
145
		*/
146 147 148 149 150 151
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			snd_pcm_hw_rule_add(substream->runtime, 0,
					    SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
					    omap_mcbsp_hwrule_min_buffersize,
					    mcbsp,
					    SNDRV_PCM_HW_PARAM_CHANNELS, -1);
152

153 154 155
		/* Make sure, that the period size is always even */
		snd_pcm_hw_constraint_step(substream->runtime, 0,
					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
156 157
	}

158 159 160
	return err;
}

161
static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
162
				    struct snd_soc_dai *cpu_dai)
163
{
164
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
165 166

	if (!cpu_dai->active) {
167
		omap_mcbsp_free(mcbsp);
168
		mcbsp->configured = 0;
169 170 171
	}
}

172
static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
173
				  struct snd_soc_dai *cpu_dai)
174
{
175
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
176
	int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
177 178 179 180 181

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
182
		mcbsp->active++;
183
		omap_mcbsp_start(mcbsp, play, !play);
184 185 186 187 188
		break;

	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
189
		omap_mcbsp_stop(mcbsp, play, !play);
190
		mcbsp->active--;
191 192 193 194 195 196 197 198
		break;
	default:
		err = -EINVAL;
	}

	return err;
}

199 200 201 202 203
static snd_pcm_sframes_t omap_mcbsp_dai_delay(
			struct snd_pcm_substream *substream,
			struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
204
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
205
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
206 207 208 209
	u16 fifo_use;
	snd_pcm_sframes_t delay;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
210
		fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
211
	else
212
		fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
213 214 215 216 217 218 219 220 221 222 223

	/*
	 * Divide the used locations with the channel count to get the
	 * FIFO usage in samples (don't care about partial samples in the
	 * buffer).
	 */
	delay = fifo_use / substream->runtime->channels;

	return delay;
}

224
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
225
				    struct snd_pcm_hw_params *params,
226
				    struct snd_soc_dai *cpu_dai)
227
{
228
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
229
	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
230
	struct omap_pcm_dma_data *dma_data;
231
	int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
232
	int pkt_size = 0;
233
	unsigned int format, div, framesize, master;
234

235
	dma_data = &mcbsp->dma_data[substream->stream];
236
	channels = params_channels(params);
237

238 239
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
240
		dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
241
		wlen = 16;
242 243
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
244
		dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
245
		wlen = 32;
246 247 248 249
		break;
	default:
		return -EINVAL;
	}
250
	if (mcbsp->pdata->buffer_size) {
251
		dma_data->set_threshold = omap_mcbsp_set_threshold;
252
		if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
253 254 255 256
			int period_words, max_thrsh;

			period_words = params_period_bytes(params) / (wlen / 8);
			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
257
				max_thrsh = mcbsp->max_tx_thres;
258
			else
259
				max_thrsh = mcbsp->max_rx_thres;
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
			/*
			 * If the period contains less or equal number of words,
			 * we are using the original threshold mode setup:
			 * McBSP threshold = sDMA frame size = period_size
			 * Otherwise we switch to sDMA packet mode:
			 * McBSP threshold = sDMA packet size
			 * sDMA frame size = period size
			 */
			if (period_words > max_thrsh) {
				int divider = 0;

				/*
				 * Look for the biggest threshold value, which
				 * divides the period size evenly.
				 */
				divider = period_words / max_thrsh;
				if (period_words % max_thrsh)
					divider++;
				while (period_words % divider &&
					divider < period_words)
					divider++;
				if (divider == period_words)
					return -EINVAL;

				pkt_size = period_words / divider;
				sync_mode = OMAP_DMA_SYNC_PACKET;
			} else {
				sync_mode = OMAP_DMA_SYNC_FRAME;
			}
289 290 291 292
		} else if (channels > 1) {
			/* Use packet mode for non mono streams */
			pkt_size = channels;
			sync_mode = OMAP_DMA_SYNC_PACKET;
293
		}
294 295 296
	}

	dma_data->sync_mode = sync_mode;
297
	dma_data->packet_size = pkt_size;
298

299
	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
300

301
	if (mcbsp->configured) {
302 303 304 305
		/* McBSP already configured by another stream */
		return 0;
	}

306 307 308 309
	regs->rcr2	&= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7));
	regs->xcr2	&= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
	regs->rcr1	&= ~(RFRLEN1(0x7f) | RWDLEN1(7));
	regs->xcr1	&= ~(XFRLEN1(0x7f) | XWDLEN1(7));
310
	format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
311
	wpf = channels;
312 313
	if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
			      format == SND_SOC_DAIFMT_LEFT_J)) {
314 315 316 317 318 319 320
		/* Use dual-phase frames */
		regs->rcr2	|= RPHASE;
		regs->xcr2	|= XPHASE;
		/* Set 1 word per (McBSP) frame for phase1 and phase2 */
		wpf--;
		regs->rcr2	|= RFRLEN2(wpf - 1);
		regs->xcr2	|= XFRLEN2(wpf - 1);
321 322
	}

323 324 325
	regs->rcr1	|= RFRLEN1(wpf - 1);
	regs->xcr1	|= XFRLEN1(wpf - 1);

326 327 328 329 330 331 332 333
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		/* Set word lengths */
		regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_16);
		regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_16);
		regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_16);
		regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_16);
		break;
334 335 336 337 338 339 340
	case SNDRV_PCM_FORMAT_S32_LE:
		/* Set word lengths */
		regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_32);
		regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_32);
		regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_32);
		regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_32);
		break;
341 342 343 344 345
	default:
		/* Unsupported PCM format */
		return -EINVAL;
	}

346 347
	/* In McBSP master modes, FRAME (i.e. sample rate) is generated
	 * by _counting_ BCLKs. Calculate frame size in BCLKs */
348
	master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
349
	if (master ==	SND_SOC_DAIFMT_CBS_CFS) {
350 351
		div = mcbsp->clk_div ? mcbsp->clk_div : 1;
		framesize = (mcbsp->in_freq / div) / params_rate(params);
352 353 354 355 356 357 358 359 360

		if (framesize < wlen * channels) {
			printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
					"channels\n", __func__);
			return -EINVAL;
		}
	} else
		framesize = wlen * channels;

361
	/* Set FS period and length in terms of bit clock periods */
362 363
	regs->srgr2	&= ~FPER(0xfff);
	regs->srgr1	&= ~FWID(0xff);
364
	switch (format) {
365
	case SND_SOC_DAIFMT_I2S:
366
	case SND_SOC_DAIFMT_LEFT_J:
367 368
		regs->srgr2	|= FPER(framesize - 1);
		regs->srgr1	|= FWID((framesize >> 1) - 1);
369
		break;
370
	case SND_SOC_DAIFMT_DSP_A:
371
	case SND_SOC_DAIFMT_DSP_B:
372
		regs->srgr2	|= FPER(framesize - 1);
373
		regs->srgr1	|= FWID(0);
374 375 376
		break;
	}

377 378 379
	omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
	mcbsp->wlen = wlen;
	mcbsp->configured = 1;
380 381 382 383 384 385 386 387

	return 0;
}

/*
 * This must be called before _set_clkdiv and _set_sysclk since McBSP register
 * cache is initialized here
 */
388
static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
389 390
				      unsigned int fmt)
{
391
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
392
	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
393
	bool inv_fs = false;
394

395
	if (mcbsp->configured)
396 397
		return 0;

398
	mcbsp->fmt = fmt;
399 400 401 402
	memset(regs, 0, sizeof(*regs));
	/* Generic McBSP register settings */
	regs->spcr2	|= XINTM(3) | FREE;
	regs->spcr1	|= RINTM(3);
403 404
	/* RFIG and XFIG are not defined in 2430 and on OMAP3+ */
	if (!mcbsp->pdata->has_ccr) {
405 406 407
		regs->rcr2	|= RFIG;
		regs->xcr2	|= XFIG;
	}
408 409 410

	/* Configure XCCR/RCCR only for revisions which have ccr registers */
	if (mcbsp->pdata->has_ccr) {
411 412
		regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
		regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
413
	}
414 415 416 417 418 419 420

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		/* 1-bit data delay */
		regs->rcr2	|= RDATDLY(1);
		regs->xcr2	|= XDATDLY(1);
		break;
421 422 423 424 425 426
	case SND_SOC_DAIFMT_LEFT_J:
		/* 0-bit data delay */
		regs->rcr2	|= RDATDLY(0);
		regs->xcr2	|= XDATDLY(0);
		regs->spcr1	|= RJUST(2);
		/* Invert FS polarity configuration */
427
		inv_fs = true;
428
		break;
429 430 431 432 433
	case SND_SOC_DAIFMT_DSP_A:
		/* 1-bit data delay */
		regs->rcr2      |= RDATDLY(1);
		regs->xcr2      |= XDATDLY(1);
		/* Invert FS polarity configuration */
434
		inv_fs = true;
435
		break;
436
	case SND_SOC_DAIFMT_DSP_B:
437 438 439
		/* 0-bit data delay */
		regs->rcr2      |= RDATDLY(0);
		regs->xcr2      |= XDATDLY(0);
440
		/* Invert FS polarity configuration */
441
		inv_fs = true;
442
		break;
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
	default:
		/* Unsupported data format */
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		/* McBSP master. Set FS and bit clocks as outputs */
		regs->pcr0	|= FSXM | FSRM |
				   CLKXM | CLKRM;
		/* Sample rate generator drives the FS */
		regs->srgr2	|= FSGM;
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
		/* McBSP slave */
		break;
	default:
		/* Unsupported master/slave configuration */
		return -EINVAL;
	}

	/* Set bit clock (CLKX/CLKR) and FS polarities */
465
	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
	case SND_SOC_DAIFMT_NB_NF:
		/*
		 * Normal BCLK + FS.
		 * FS active low. TX data driven on falling edge of bit clock
		 * and RX data sampled on rising edge of bit clock.
		 */
		regs->pcr0	|= FSXP | FSRP |
				   CLKXP | CLKRP;
		break;
	case SND_SOC_DAIFMT_NB_IF:
		regs->pcr0	|= CLKXP | CLKRP;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		regs->pcr0	|= FSXP | FSRP;
		break;
	case SND_SOC_DAIFMT_IB_IF:
		break;
	default:
		return -EINVAL;
	}
486 487
	if (inv_fs == true)
		regs->pcr0 ^= FSXP | FSRP;
488 489 490 491

	return 0;
}

492
static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
493 494
				     int div_id, int div)
{
495
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
496
	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
497 498 499 500

	if (div_id != OMAP_MCBSP_CLKGDV)
		return -ENODEV;

501
	mcbsp->clk_div = div;
502
	regs->srgr1	&= ~CLKGDV(0xff);
503 504 505 506 507
	regs->srgr1	|= CLKGDV(div - 1);

	return 0;
}

508
static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
509 510 511
					 int clk_id, unsigned int freq,
					 int dir)
{
512
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
513
	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
514 515
	int err = 0;

516 517
	if (mcbsp->active) {
		if (freq == mcbsp->in_freq)
518 519 520
			return 0;
		else
			return -EBUSY;
521
	}
522

523 524 525
	mcbsp->in_freq = freq;
	regs->srgr2 &= ~CLKSM;
	regs->pcr0 &= ~SCLKME;
526

527 528 529 530 531
	switch (clk_id) {
	case OMAP_MCBSP_SYSCLK_CLK:
		regs->srgr2	|= CLKSM;
		break;
	case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
532 533 534 535
		if (cpu_class_is_omap1()) {
			err = -EINVAL;
			break;
		}
536
		err = omap2_mcbsp_set_clks_src(mcbsp,
537 538
					       MCBSP_CLKS_PRCM_SRC);
		break;
539
	case OMAP_MCBSP_SYSCLK_CLKS_EXT:
540 541 542 543
		if (cpu_class_is_omap1()) {
			err = 0;
			break;
		}
544
		err = omap2_mcbsp_set_clks_src(mcbsp,
545
					       MCBSP_CLKS_PAD_SRC);
546 547 548 549 550 551 552 553 554 555 556 557 558 559
		break;

	case OMAP_MCBSP_SYSCLK_CLKX_EXT:
		regs->srgr2	|= CLKSM;
	case OMAP_MCBSP_SYSCLK_CLKR_EXT:
		regs->pcr0	|= SCLKME;
		break;
	default:
		err = -ENODEV;
	}

	return err;
}

560
static const struct snd_soc_dai_ops mcbsp_dai_ops = {
561 562 563
	.startup	= omap_mcbsp_dai_startup,
	.shutdown	= omap_mcbsp_dai_shutdown,
	.trigger	= omap_mcbsp_dai_trigger,
564
	.delay		= omap_mcbsp_dai_delay,
565 566 567 568 569 570
	.hw_params	= omap_mcbsp_dai_hw_params,
	.set_fmt	= omap_mcbsp_dai_set_dai_fmt,
	.set_clkdiv	= omap_mcbsp_dai_set_clkdiv,
	.set_sysclk	= omap_mcbsp_dai_set_dai_sysclk,
};

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
static int omap_mcbsp_probe(struct snd_soc_dai *dai)
{
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);

	pm_runtime_enable(mcbsp->dev);

	return 0;
}

static int omap_mcbsp_remove(struct snd_soc_dai *dai)
{
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);

	pm_runtime_disable(mcbsp->dev);

	return 0;
}

589
static struct snd_soc_dai_driver omap_mcbsp_dai = {
590 591
	.probe = omap_mcbsp_probe,
	.remove = omap_mcbsp_remove,
592 593 594 595 596 597 598 599 600 601 602 603 604
	.playback = {
		.channels_min = 1,
		.channels_max = 16,
		.rates = OMAP_MCBSP_RATES,
		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
	},
	.capture = {
		.channels_min = 1,
		.channels_max = 16,
		.rates = OMAP_MCBSP_RATES,
		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
	},
	.ops = &mcbsp_dai_ops,
605
};
606

607
static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
608 609 610 611 612 613 614 615 616 617 618 619 620 621
			struct snd_ctl_elem_info *uinfo)
{
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	int max = mc->max;
	int min = mc->min;

	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->count = 1;
	uinfo->value.integer.min = min;
	uinfo->value.integer.max = max;
	return 0;
}

622
#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel)			\
623
static int								\
624
omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,	\
625 626
					struct snd_ctl_elem_value *uc)	\
{									\
627 628
	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);		\
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);	\
629 630 631 632 633 634 635 636 637 638
	struct soc_mixer_control *mc =					\
		(struct soc_mixer_control *)kc->private_value;		\
	int max = mc->max;						\
	int min = mc->min;						\
	int val = uc->value.integer.value[0];				\
									\
	if (val < min || val > max)					\
		return -EINVAL;						\
									\
	/* OMAP McBSP implementation uses index values 0..4 */		\
639
	return omap_st_set_chgain(mcbsp, channel, val);			\
640 641
}

642
#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel)			\
643
static int								\
644
omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,	\
645 646
					struct snd_ctl_elem_value *uc)	\
{									\
647 648
	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);		\
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);	\
649 650
	s16 chgain;							\
									\
651
	if (omap_st_get_chgain(mcbsp, channel, &chgain))		\
652 653 654 655 656 657
		return -EAGAIN;						\
									\
	uc->value.integer.value[0] = chgain;				\
	return 0;							\
}

658 659 660 661
OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0)
OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1)
OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0)
OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1)
662 663 664 665

static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
666 667
	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
668 669
	u8 value = ucontrol->value.integer.value[0];

670
	if (value == omap_st_is_enabled(mcbsp))
671 672 673
		return 0;

	if (value)
674
		omap_st_enable(mcbsp);
675
	else
676
		omap_st_disable(mcbsp);
677 678 679 680 681 682 683

	return 1;
}

static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
684 685
	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
686

687
	ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
688 689 690 691 692 693 694 695
	return 0;
}

static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
	SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0,
			omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
				      -32768, 32767,
696 697
				      omap_mcbsp_get_st_ch0_volume,
				      omap_mcbsp_set_st_ch0_volume),
698 699
	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
				      -32768, 32767,
700 701
				      omap_mcbsp_get_st_ch1_volume,
				      omap_mcbsp_set_st_ch1_volume),
702 703 704 705 706 707 708
};

static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
	SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0,
			omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
				      -32768, 32767,
709 710
				      omap_mcbsp_get_st_ch0_volume,
				      omap_mcbsp_set_st_ch0_volume),
711 712
	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
				      -32768, 32767,
713 714
				      omap_mcbsp_get_st_ch1_volume,
				      omap_mcbsp_set_st_ch1_volume),
715 716
};

717
int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
718
{
719 720 721
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);

722 723 724 725
	if (!mcbsp->st_data) {
		dev_warn(mcbsp->dev, "No sidetone data for port\n");
		return 0;
	}
726

727
	switch (mcbsp->id) {
728 729 730
	case 2: /* McBSP 2 */
		return snd_soc_add_dai_controls(cpu_dai,
					omap_mcbsp2_st_controls,
731
					ARRAY_SIZE(omap_mcbsp2_st_controls));
732 733 734
	case 3: /* McBSP 3 */
		return snd_soc_add_dai_controls(cpu_dai,
					omap_mcbsp3_st_controls,
735 736 737 738 739 740 741 742 743
					ARRAY_SIZE(omap_mcbsp3_st_controls));
	default:
		break;
	}

	return -EINVAL;
}
EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);

744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
static struct omap_mcbsp_platform_data omap2420_pdata = {
	.reg_step = 4,
	.reg_size = 2,
};

static struct omap_mcbsp_platform_data omap2430_pdata = {
	.reg_step = 4,
	.reg_size = 4,
	.has_ccr = true,
};

static struct omap_mcbsp_platform_data omap3_pdata = {
	.reg_step = 4,
	.reg_size = 4,
	.has_ccr = true,
	.has_wakeup = true,
};

static struct omap_mcbsp_platform_data omap4_pdata = {
	.reg_step = 4,
	.reg_size = 4,
	.has_ccr = true,
	.has_wakeup = true,
};

static const struct of_device_id omap_mcbsp_of_match[] = {
	{
		.compatible = "ti,omap2420-mcbsp",
		.data = &omap2420_pdata,
	},
	{
		.compatible = "ti,omap2430-mcbsp",
		.data = &omap2430_pdata,
	},
	{
		.compatible = "ti,omap3-mcbsp",
		.data = &omap3_pdata,
	},
	{
		.compatible = "ti,omap4-mcbsp",
		.data = &omap4_pdata,
	},
	{ },
};
MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match);

790 791
static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
{
792 793
	struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
	struct omap_mcbsp *mcbsp;
794
	const struct of_device_id *match;
795 796
	int ret;

797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
	match = of_match_device(omap_mcbsp_of_match, &pdev->dev);
	if (match) {
		struct device_node *node = pdev->dev.of_node;
		int buffer_size;

		pdata = devm_kzalloc(&pdev->dev,
				     sizeof(struct omap_mcbsp_platform_data),
				     GFP_KERNEL);
		if (!pdata)
			return -ENOMEM;

		memcpy(pdata, match->data, sizeof(*pdata));
		if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size))
			pdata->buffer_size = buffer_size;
	} else if (!pdata) {
812 813 814 815 816 817 818 819 820 821 822 823 824
		dev_err(&pdev->dev, "missing platform data.\n");
		return -EINVAL;
	}
	mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL);
	if (!mcbsp)
		return -ENOMEM;

	mcbsp->id = pdev->id;
	mcbsp->pdata = pdata;
	mcbsp->dev = &pdev->dev;
	platform_set_drvdata(pdev, mcbsp);

	ret = omap_mcbsp_init(pdev);
825 826 827 828
	if (!ret)
		return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);

	return ret;
829 830 831 832
}

static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
{
833 834
	struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);

835
	snd_soc_unregister_dai(&pdev->dev);
836 837 838 839 840 841 842 843 844 845

	if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
		mcbsp->pdata->ops->free(mcbsp->id);

	omap_mcbsp_sysfs_remove(mcbsp);

	clk_put(mcbsp->fclk);

	platform_set_drvdata(pdev, NULL);

846 847 848 849 850
	return 0;
}

static struct platform_driver asoc_mcbsp_driver = {
	.driver = {
851
			.name = "omap-mcbsp",
852
			.owner = THIS_MODULE,
853
			.of_match_table = omap_mcbsp_of_match,
854 855 856 857 858 859
	},

	.probe = asoc_mcbsp_probe,
	.remove = __devexit_p(asoc_mcbsp_remove),
};

860
module_platform_driver(asoc_mcbsp_driver);
M
Mark Brown 已提交
861

862
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
863 864
MODULE_DESCRIPTION("OMAP I2S SoC Interface");
MODULE_LICENSE("GPL");