fsl_sai.c 33.2 KB
Newer Older
1 2 3 4 5
// SPDX-License-Identifier: GPL-2.0+
//
// Freescale ALSA SoC Digital Audio Interface (SAI) driver.
//
// Copyright 2012-2015 Freescale Semiconductor, Inc.
6 7 8 9 10 11

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of_address.h>
L
Lucas Stach 已提交
12
#include <linux/of_device.h>
13
#include <linux/pm_runtime.h>
14
#include <linux/regmap.h>
15
#include <linux/slab.h>
16
#include <linux/time.h>
17 18 19
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
20 21
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
22 23

#include "fsl_sai.h"
24
#include "imx-pcm.h"
25

26 27 28
#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
		       FSL_SAI_CSR_FEIE)

29
static const unsigned int fsl_sai_rates[] = {
30 31 32 33 34
	8000, 11025, 12000, 16000, 22050,
	24000, 32000, 44100, 48000, 64000,
	88200, 96000, 176400, 192000
};

35
static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
36 37 38 39
	.count = ARRAY_SIZE(fsl_sai_rates),
	.list = fsl_sai_rates,
};

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
/**
 * fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
 *
 * SAI supports synchronous mode using bit/frame clocks of either Transmitter's
 * or Receiver's for both streams. This function is used to check if clocks of
 * the stream's are synced by the opposite stream.
 *
 * @sai: SAI context
 * @dir: stream direction
 */
static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
{
	int adir = (dir == TX) ? RX : TX;

	/* current dir in async mode while opposite dir in sync mode */
	return !sai->synchronous[dir] && sai->synchronous[adir];
}

58 59 60
static irqreturn_t fsl_sai_isr(int irq, void *devid)
{
	struct fsl_sai *sai = (struct fsl_sai *)devid;
61
	unsigned int ofs = sai->soc_data->reg_offset;
62
	struct device *dev = &sai->pdev->dev;
63 64 65 66 67 68 69 70
	u32 flags, xcsr, mask;
	bool irq_none = true;

	/*
	 * Both IRQ status bits and IRQ mask bits are in the xCSR but
	 * different shifts. And we here create a mask only for those
	 * IRQs that we activated.
	 */
71 72 73
	mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;

	/* Tx IRQ */
74
	regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr);
75 76 77 78 79 80
	flags = xcsr & mask;

	if (flags)
		irq_none = false;
	else
		goto irq_rx;
81

82
	if (flags & FSL_SAI_CSR_WSF)
83 84
		dev_dbg(dev, "isr: Start of Tx word detected\n");

85
	if (flags & FSL_SAI_CSR_SEF)
86
		dev_dbg(dev, "isr: Tx Frame sync error detected\n");
87

88
	if (flags & FSL_SAI_CSR_FEF) {
89
		dev_dbg(dev, "isr: Transmit underrun detected\n");
90 91 92 93
		/* FIFO reset for safety */
		xcsr |= FSL_SAI_CSR_FR;
	}

94
	if (flags & FSL_SAI_CSR_FWF)
95 96
		dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");

97
	if (flags & FSL_SAI_CSR_FRF)
98 99
		dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");

100 101 102 103
	flags &= FSL_SAI_CSR_xF_W_MASK;
	xcsr &= ~FSL_SAI_CSR_xF_MASK;

	if (flags)
104
		regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr);
105

106
irq_rx:
107
	/* Rx IRQ */
108
	regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr);
109
	flags = xcsr & mask;
110

111 112 113 114 115 116
	if (flags)
		irq_none = false;
	else
		goto out;

	if (flags & FSL_SAI_CSR_WSF)
117 118
		dev_dbg(dev, "isr: Start of Rx word detected\n");

119
	if (flags & FSL_SAI_CSR_SEF)
120
		dev_dbg(dev, "isr: Rx Frame sync error detected\n");
121

122
	if (flags & FSL_SAI_CSR_FEF) {
123
		dev_dbg(dev, "isr: Receive overflow detected\n");
124 125 126 127
		/* FIFO reset for safety */
		xcsr |= FSL_SAI_CSR_FR;
	}

128
	if (flags & FSL_SAI_CSR_FWF)
129 130
		dev_dbg(dev, "isr: Enabled receive FIFO is full\n");

131
	if (flags & FSL_SAI_CSR_FRF)
132 133
		dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");

134 135
	flags &= FSL_SAI_CSR_xF_W_MASK;
	xcsr &= ~FSL_SAI_CSR_xF_MASK;
136

137
	if (flags)
138
		regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr);
139 140 141 142 143 144

out:
	if (irq_none)
		return IRQ_NONE;
	else
		return IRQ_HANDLED;
145 146
}

147 148 149 150 151 152 153 154 155 156 157
static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
				u32 rx_mask, int slots, int slot_width)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);

	sai->slots = slots;
	sai->slot_width = slot_width;

	return 0;
}

158 159 160 161 162 163 164 165 166 167
static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai,
				      unsigned int ratio)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);

	sai->bclk_ratio = ratio;

	return 0;
}

168 169 170 171
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
		int clk_id, unsigned int freq, int fsl_dir)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
172
	unsigned int ofs = sai->soc_data->reg_offset;
173 174
	bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
	u32 val_cr2 = 0;
X
Xiubo Li 已提交
175

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
	switch (clk_id) {
	case FSL_SAI_CLK_BUS:
		val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
		break;
	case FSL_SAI_CLK_MAST1:
		val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
		break;
	case FSL_SAI_CLK_MAST2:
		val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
		break;
	case FSL_SAI_CLK_MAST3:
		val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
		break;
	default:
		return -EINVAL;
	}
X
Xiubo Li 已提交
192

193
	regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
194
			   FSL_SAI_CR2_MSEL_MASK, val_cr2);
195 196 197 198 199 200 201

	return 0;
}

static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
		int clk_id, unsigned int freq, int dir)
{
202
	int ret;
203 204 205 206 207 208 209

	if (dir == SND_SOC_CLOCK_IN)
		return 0;

	ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
					FSL_FMT_TRANSMITTER);
	if (ret) {
210
		dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
211
		return ret;
212 213 214 215
	}

	ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
					FSL_FMT_RECEIVER);
216
	if (ret)
217
		dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
218

219
	return ret;
220 221 222 223 224 225
}

static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
				unsigned int fmt, int fsl_dir)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
226
	unsigned int ofs = sai->soc_data->reg_offset;
227 228
	bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
	u32 val_cr2 = 0, val_cr4 = 0;
229

230
	if (!sai->is_lsb_first)
231
		val_cr4 |= FSL_SAI_CR4_MF;
232

233
	/* DAI mode */
234 235
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
236 237 238 239 240 241
		/*
		 * Frame low, 1clk before data, one word length for frame sync,
		 * frame sync starts one serial clock cycle earlier,
		 * that is, together with the last bit of the previous
		 * data word.
		 */
242
		val_cr2 |= FSL_SAI_CR2_BCP;
243 244 245
		val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
246 247 248 249
		/*
		 * Frame high, one word length for frame sync,
		 * frame sync asserts with the first bit of the frame.
		 */
250
		val_cr2 |= FSL_SAI_CR2_BCP;
251
		break;
252 253 254 255 256 257 258
	case SND_SOC_DAIFMT_DSP_A:
		/*
		 * Frame high, 1clk before data, one bit for frame sync,
		 * frame sync starts one serial clock cycle earlier,
		 * that is, together with the last bit of the previous
		 * data word.
		 */
259
		val_cr2 |= FSL_SAI_CR2_BCP;
260 261 262 263 264 265 266 267
		val_cr4 |= FSL_SAI_CR4_FSE;
		sai->is_dsp_mode = true;
		break;
	case SND_SOC_DAIFMT_DSP_B:
		/*
		 * Frame high, one bit for frame sync,
		 * frame sync asserts with the first bit of the frame.
		 */
268
		val_cr2 |= FSL_SAI_CR2_BCP;
269 270
		sai->is_dsp_mode = true;
		break;
271 272
	case SND_SOC_DAIFMT_RIGHT_J:
		/* To be done */
273 274 275 276
	default:
		return -EINVAL;
	}

277
	/* DAI clock inversion */
278 279
	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_IB_IF:
280 281 282
		/* Invert both clocks */
		val_cr2 ^= FSL_SAI_CR2_BCP;
		val_cr4 ^= FSL_SAI_CR4_FSP;
283 284
		break;
	case SND_SOC_DAIFMT_IB_NF:
285 286
		/* Invert bit clock */
		val_cr2 ^= FSL_SAI_CR2_BCP;
287 288
		break;
	case SND_SOC_DAIFMT_NB_IF:
289 290
		/* Invert frame clock */
		val_cr4 ^= FSL_SAI_CR4_FSP;
291 292
		break;
	case SND_SOC_DAIFMT_NB_NF:
293
		/* Nothing to do for both normal cases */
294 295 296 297 298
		break;
	default:
		return -EINVAL;
	}

299
	/* DAI clock master masks */
300 301 302 303
	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
		val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
304
		sai->is_slave_mode = false;
305 306
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
307
		sai->is_slave_mode = true;
308
		break;
309 310
	case SND_SOC_DAIFMT_CBS_CFM:
		val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
311
		sai->is_slave_mode = false;
312 313 314
		break;
	case SND_SOC_DAIFMT_CBM_CFS:
		val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
315
		sai->is_slave_mode = true;
316
		break;
317 318 319 320
	default:
		return -EINVAL;
	}

321
	regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
322
			   FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
323
	regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
324 325
			   FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
			   FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
326 327 328 329 330 331

	return 0;
}

static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
332
	int ret;
333 334 335

	ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
	if (ret) {
336
		dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
337
		return ret;
338 339 340
	}

	ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
341
	if (ret)
342
		dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
343

344
	return ret;
345 346
}

347 348 349
static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
350
	unsigned int ofs = sai->soc_data->reg_offset;
351 352
	unsigned long clk_rate;
	u32 savediv = 0, ratio, savesub = freq;
353 354
	int adir = tx ? RX : TX;
	int dir = tx ? TX : RX;
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
	u32 id;
	int ret = 0;

	/* Don't apply to slave mode */
	if (sai->is_slave_mode)
		return 0;

	for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
		clk_rate = clk_get_rate(sai->mclk_clk[id]);
		if (!clk_rate)
			continue;

		ratio = clk_rate / freq;

		ret = clk_rate - ratio * freq;

		/*
		 * Drop the source that can not be
		 * divided into the required rate.
		 */
		if (ret != 0 && clk_rate / ret < 1000)
			continue;

		dev_dbg(dai->dev,
			"ratio %d for freq %dHz based on clock %ldHz\n",
			ratio, freq, clk_rate);

		if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512)
			ratio /= 2;
		else
			continue;

		if (ret < savesub) {
			savediv = ratio;
			sai->mclk_id[tx] = id;
			savesub = ret;
		}

		if (ret == 0)
			break;
	}

	if (savediv == 0) {
		dev_err(dai->dev, "failed to derive required %cx rate: %d\n",
				tx ? 'T' : 'R', freq);
		return -EINVAL;
	}

403 404 405 406 407 408 409 410 411 412
	/*
	 * 1) For Asynchronous mode, we must set RCR2 register for capture, and
	 *    set TCR2 register for playback.
	 * 2) For Tx sync with Rx clock, we must set RCR2 register for playback
	 *    and capture.
	 * 3) For Rx sync with Tx clock, we must set TCR2 register for playback
	 *    and capture.
	 * 4) For Tx and Rx are both Synchronous with another SAI, we just
	 *    ignore it.
	 */
413 414
	if (fsl_sai_dir_is_synced(sai, adir)) {
		regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs),
415 416
				   FSL_SAI_CR2_MSEL_MASK,
				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
417
		regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs),
418
				   FSL_SAI_CR2_DIV_MASK, savediv - 1);
419 420
	} else if (!sai->synchronous[dir]) {
		regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
421 422
				   FSL_SAI_CR2_MSEL_MASK,
				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
423
		regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
424 425 426 427 428 429 430 431 432
				   FSL_SAI_CR2_DIV_MASK, savediv - 1);
	}

	dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
			sai->mclk_id[tx], savediv, savesub);

	return 0;
}

433 434 435 436
static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *params,
		struct snd_soc_dai *cpu_dai)
{
437
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
438
	unsigned int ofs = sai->soc_data->reg_offset;
439
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
440
	unsigned int channels = params_channels(params);
441
	u32 word_width = params_width(params);
442
	u32 val_cr4 = 0, val_cr5 = 0;
443 444
	u32 slots = (channels == 1) ? 2 : channels;
	u32 slot_width = word_width;
445
	int adir = tx ? RX : TX;
446
	u32 pins;
447 448
	int ret;

449 450 451 452 453 454
	if (sai->slots)
		slots = sai->slots;

	if (sai->slot_width)
		slot_width = sai->slot_width;

455 456
	pins = DIV_ROUND_UP(channels, slots);

457
	if (!sai->is_slave_mode) {
458 459 460 461 462 463 464 465
		if (sai->bclk_ratio)
			ret = fsl_sai_set_bclk(cpu_dai, tx,
					       sai->bclk_ratio *
					       params_rate(params));
		else
			ret = fsl_sai_set_bclk(cpu_dai, tx,
					       slots * slot_width *
					       params_rate(params));
466 467 468 469 470 471 472 473 474 475 476 477
		if (ret)
			return ret;

		/* Do not enable the clock if it is already enabled */
		if (!(sai->mclk_streams & BIT(substream->stream))) {
			ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[tx]]);
			if (ret)
				return ret;

			sai->mclk_streams |= BIT(substream->stream);
		}
	}
478

479
	if (!sai->is_dsp_mode)
480
		val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
481

482 483
	val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
	val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
484

485
	if (sai->is_lsb_first)
486
		val_cr5 |= FSL_SAI_CR5_FBT(0);
487 488
	else
		val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
489

490
	val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
491

492 493 494 495
	/* Set to output mode to avoid tri-stated data pins */
	if (tx)
		val_cr4 |= FSL_SAI_CR4_CHMOD;

496 497 498
	/*
	 * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
	 * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
499
	 * RCR5(TCR5) for playback(capture), or there will be sync error.
500 501
	 */

502 503
	if (!sai->is_slave_mode && fsl_sai_dir_is_synced(sai, adir)) {
		regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
504 505
				   FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
				   FSL_SAI_CR4_CHMOD_MASK,
506 507 508 509
				   val_cr4);
		regmap_update_bits(sai->regmap, FSL_SAI_xCR5(!tx, ofs),
				   FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
				   FSL_SAI_CR5_FBT_MASK, val_cr5);
510
	}
511

512 513 514
	regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
			   FSL_SAI_CR3_TRCE_MASK,
			   FSL_SAI_CR3_TRCE((1 << pins) - 1));
515
	regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
516 517
			   FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
			   FSL_SAI_CR4_CHMOD_MASK,
518
			   val_cr4);
519
	regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
520 521
			   FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
			   FSL_SAI_CR5_FBT_MASK, val_cr5);
522 523
	regmap_write(sai->regmap, FSL_SAI_xMR(tx),
		     ~0UL - ((1 << min(channels, slots)) - 1));
524 525 526 527

	return 0;
}

528 529 530 531 532
static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
		struct snd_soc_dai *cpu_dai)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
533 534 535 536
	unsigned int ofs = sai->soc_data->reg_offset;

	regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
			   FSL_SAI_CR3_TRCE_MASK, 0);
537 538 539 540 541 542 543 544 545 546

	if (!sai->is_slave_mode &&
			sai->mclk_streams & BIT(substream->stream)) {
		clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
		sai->mclk_streams &= ~BIT(substream->stream);
	}

	return 0;
}

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
{
	unsigned int ofs = sai->soc_data->reg_offset;
	bool tx = dir == TX;
	u32 xcsr, count = 100;

	regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
			   FSL_SAI_CSR_TERE, 0);

	/* TERE will remain set till the end of current frame */
	do {
		udelay(10);
		regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr);
	} while (--count && xcsr & FSL_SAI_CSR_TERE);

	regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
			   FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);

	/*
	 * For sai master mode, after several open/close sai,
	 * there will be no frame clock, and can't recover
	 * anymore. Add software reset to fix this issue.
	 * This is a hardware bug, and will be fix in the
	 * next sai version.
	 */
	if (!sai->is_slave_mode) {
		/* Software Reset */
		regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
		/* Clear SR bit to finish the reset */
		regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0);
	}
}
579

580 581 582 583
static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
		struct snd_soc_dai *cpu_dai)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
584 585
	unsigned int ofs = sai->soc_data->reg_offset;

586
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
587 588 589
	int adir = tx ? RX : TX;
	int dir = tx ? TX : RX;
	u32 xcsr;
590

591
	/*
592 593 594
	 * Asynchronous mode: Clear SYNC for both Tx and Rx.
	 * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
	 * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
595
	 */
596 597 598
	regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC,
			   sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
	regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC,
599
			   sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
600

601 602 603 604
	/*
	 * It is recommended that the transmitter is the last enabled
	 * and the first disabled.
	 */
605 606 607 608
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
609
		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
610 611
				   FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);

612
		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
613
				   FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
614 615 616 617 618 619 620 621 622 623 624 625 626 627
		/*
		 * Enable the opposite direction for synchronous mode
		 * 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx
		 * 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx
		 *
		 * RM recommends to enable RE after TE for case 1 and to enable
		 * TE after RE for case 2, but we here may not always guarantee
		 * that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables
		 * TE after RE, which is against what RM recommends but should
		 * be safe to do, judging by years of testing results.
		 */
		if (fsl_sai_dir_is_synced(sai, adir))
			regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs),
					   FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
628

629
		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
630
				   FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
631 632 633 634
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
635
		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
636
				   FSL_SAI_CSR_FRDE, 0);
637
		regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
638
				   FSL_SAI_CSR_xIE_MASK, 0);
639

640
		/* Check if the opposite FRDE is also disabled */
641
		regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr);
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658

		/*
		 * If opposite stream provides clocks for synchronous mode and
		 * it is inactive, disable it before disabling the current one
		 */
		if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE))
			fsl_sai_config_disable(sai, adir);

		/*
		 * Disable current stream if either of:
		 * 1. current stream doesn't provide clocks for synchronous mode
		 * 2. current stream provides clocks for synchronous mode but no
		 *    more stream is active.
		 */
		if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE))
			fsl_sai_config_disable(sai, dir);

659 660 661 662 663 664 665 666 667 668 669 670
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int fsl_sai_startup(struct snd_pcm_substream *substream,
		struct snd_soc_dai *cpu_dai)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
671
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
672 673
	int ret;

674 675 676 677 678 679 680 681 682 683
	/*
	 * EDMA controller needs period size to be a multiple of
	 * tx/rx maxburst
	 */
	if (sai->soc_data->use_edma)
		snd_pcm_hw_constraint_step(substream->runtime, 0,
					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
					   tx ? sai->dma_params_tx.maxburst :
					   sai->dma_params_rx.maxburst);

684 685 686 687
	ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
			SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);

	return ret;
688 689 690
}

static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
691
	.set_bclk_ratio	= fsl_sai_set_dai_bclk_ratio,
692 693
	.set_sysclk	= fsl_sai_set_dai_sysclk,
	.set_fmt	= fsl_sai_set_dai_fmt,
694
	.set_tdm_slot	= fsl_sai_set_dai_tdm_slot,
695
	.hw_params	= fsl_sai_hw_params,
696
	.hw_free	= fsl_sai_hw_free,
697 698 699 700 701 702 703
	.trigger	= fsl_sai_trigger,
	.startup	= fsl_sai_startup,
};

static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
	struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
704
	unsigned int ofs = sai->soc_data->reg_offset;
705

706
	/* Software Reset for both Tx and Rx */
707 708
	regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
	regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
709
	/* Clear SR bit to finish the reset */
710 711
	regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
	regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
712

713
	regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs),
714
			   FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
715
			   sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX);
716
	regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs),
717 718
			   FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth),
			   FSL_SAI_MAXBURST_RX - 1);
719

720 721
	snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
				&sai->dma_params_rx);
722 723 724 725 726 727 728 729 730

	snd_soc_dai_set_drvdata(cpu_dai, sai);

	return 0;
}

static struct snd_soc_dai_driver fsl_sai_dai = {
	.probe = fsl_sai_dai_probe,
	.playback = {
731
		.stream_name = "CPU-Playback",
732
		.channels_min = 1,
733
		.channels_max = 32,
734 735 736
		.rate_min = 8000,
		.rate_max = 192000,
		.rates = SNDRV_PCM_RATE_KNOT,
737 738 739
		.formats = FSL_SAI_FORMATS,
	},
	.capture = {
740
		.stream_name = "CPU-Capture",
741
		.channels_min = 1,
742
		.channels_max = 32,
743 744 745
		.rate_min = 8000,
		.rate_max = 192000,
		.rates = SNDRV_PCM_RATE_KNOT,
746 747 748 749 750 751 752 753 754
		.formats = FSL_SAI_FORMATS,
	},
	.ops = &fsl_sai_pcm_dai_ops,
};

static const struct snd_soc_component_driver fsl_component = {
	.name           = "fsl-sai",
};

755 756 757 758 759 760
static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
	{FSL_SAI_TCR1(0), 0},
	{FSL_SAI_TCR2(0), 0},
	{FSL_SAI_TCR3(0), 0},
	{FSL_SAI_TCR4(0), 0},
	{FSL_SAI_TCR5(0), 0},
761 762 763 764 765 766 767 768
	{FSL_SAI_TDR0, 0},
	{FSL_SAI_TDR1, 0},
	{FSL_SAI_TDR2, 0},
	{FSL_SAI_TDR3, 0},
	{FSL_SAI_TDR4, 0},
	{FSL_SAI_TDR5, 0},
	{FSL_SAI_TDR6, 0},
	{FSL_SAI_TDR7, 0},
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
	{FSL_SAI_TMR, 0},
	{FSL_SAI_RCR1(0), 0},
	{FSL_SAI_RCR2(0), 0},
	{FSL_SAI_RCR3(0), 0},
	{FSL_SAI_RCR4(0), 0},
	{FSL_SAI_RCR5(0), 0},
	{FSL_SAI_RMR, 0},
};

static struct reg_default fsl_sai_reg_defaults_ofs8[] = {
	{FSL_SAI_TCR1(8), 0},
	{FSL_SAI_TCR2(8), 0},
	{FSL_SAI_TCR3(8), 0},
	{FSL_SAI_TCR4(8), 0},
	{FSL_SAI_TCR5(8), 0},
	{FSL_SAI_TDR0, 0},
	{FSL_SAI_TDR1, 0},
	{FSL_SAI_TDR2, 0},
	{FSL_SAI_TDR3, 0},
	{FSL_SAI_TDR4, 0},
	{FSL_SAI_TDR5, 0},
	{FSL_SAI_TDR6, 0},
	{FSL_SAI_TDR7, 0},
	{FSL_SAI_TMR, 0},
	{FSL_SAI_RCR1(8), 0},
	{FSL_SAI_RCR2(8), 0},
	{FSL_SAI_RCR3(8), 0},
	{FSL_SAI_RCR4(8), 0},
	{FSL_SAI_RCR5(8), 0},
	{FSL_SAI_RMR, 0},
799 800
	{FSL_SAI_MCTL, 0},
	{FSL_SAI_MDIV, 0},
801 802
};

803 804
static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
{
805 806 807 808 809 810 811 812 813
	struct fsl_sai *sai = dev_get_drvdata(dev);
	unsigned int ofs = sai->soc_data->reg_offset;

	if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs))
		return true;

	if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs))
		return true;

814
	switch (reg) {
815 816 817 818 819 820 821 822
	case FSL_SAI_TFR0:
	case FSL_SAI_TFR1:
	case FSL_SAI_TFR2:
	case FSL_SAI_TFR3:
	case FSL_SAI_TFR4:
	case FSL_SAI_TFR5:
	case FSL_SAI_TFR6:
	case FSL_SAI_TFR7:
823
	case FSL_SAI_TMR:
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
	case FSL_SAI_RDR0:
	case FSL_SAI_RDR1:
	case FSL_SAI_RDR2:
	case FSL_SAI_RDR3:
	case FSL_SAI_RDR4:
	case FSL_SAI_RDR5:
	case FSL_SAI_RDR6:
	case FSL_SAI_RDR7:
	case FSL_SAI_RFR0:
	case FSL_SAI_RFR1:
	case FSL_SAI_RFR2:
	case FSL_SAI_RFR3:
	case FSL_SAI_RFR4:
	case FSL_SAI_RFR5:
	case FSL_SAI_RFR6:
	case FSL_SAI_RFR7:
840
	case FSL_SAI_RMR:
841 842 843 844 845 846 847 848 849 850 851 852
	case FSL_SAI_MCTL:
	case FSL_SAI_MDIV:
	case FSL_SAI_VERID:
	case FSL_SAI_PARAM:
	case FSL_SAI_TTCTN:
	case FSL_SAI_RTCTN:
	case FSL_SAI_TTCTL:
	case FSL_SAI_TBCTN:
	case FSL_SAI_TTCAP:
	case FSL_SAI_RTCTL:
	case FSL_SAI_RBCTN:
	case FSL_SAI_RTCAP:
853 854 855 856 857 858 859 860
		return true;
	default:
		return false;
	}
}

static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
{
861 862 863 864 865 866
	struct fsl_sai *sai = dev_get_drvdata(dev);
	unsigned int ofs = sai->soc_data->reg_offset;

	if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs))
		return true;

867 868 869 870
	/* Set VERID and PARAM be volatile for reading value in probe */
	if (ofs == 8 && (reg == FSL_SAI_VERID || reg == FSL_SAI_PARAM))
		return true;

871
	switch (reg) {
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
	case FSL_SAI_TFR0:
	case FSL_SAI_TFR1:
	case FSL_SAI_TFR2:
	case FSL_SAI_TFR3:
	case FSL_SAI_TFR4:
	case FSL_SAI_TFR5:
	case FSL_SAI_TFR6:
	case FSL_SAI_TFR7:
	case FSL_SAI_RFR0:
	case FSL_SAI_RFR1:
	case FSL_SAI_RFR2:
	case FSL_SAI_RFR3:
	case FSL_SAI_RFR4:
	case FSL_SAI_RFR5:
	case FSL_SAI_RFR6:
	case FSL_SAI_RFR7:
	case FSL_SAI_RDR0:
	case FSL_SAI_RDR1:
	case FSL_SAI_RDR2:
	case FSL_SAI_RDR3:
	case FSL_SAI_RDR4:
	case FSL_SAI_RDR5:
	case FSL_SAI_RDR6:
	case FSL_SAI_RDR7:
896 897 898 899 900 901 902 903
		return true;
	default:
		return false;
	}
}

static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
{
904 905 906 907 908 909 910 911 912
	struct fsl_sai *sai = dev_get_drvdata(dev);
	unsigned int ofs = sai->soc_data->reg_offset;

	if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs))
		return true;

	if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs))
		return true;

913
	switch (reg) {
914 915 916 917 918 919 920 921
	case FSL_SAI_TDR0:
	case FSL_SAI_TDR1:
	case FSL_SAI_TDR2:
	case FSL_SAI_TDR3:
	case FSL_SAI_TDR4:
	case FSL_SAI_TDR5:
	case FSL_SAI_TDR6:
	case FSL_SAI_TDR7:
922 923
	case FSL_SAI_TMR:
	case FSL_SAI_RMR:
924 925 926 927
	case FSL_SAI_MCTL:
	case FSL_SAI_MDIV:
	case FSL_SAI_TTCTL:
	case FSL_SAI_RTCTL:
928 929 930 931 932 933
		return true;
	default:
		return false;
	}
}

934
static struct regmap_config fsl_sai_regmap_config = {
935 936 937
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
938
	.fast_io = true,
939 940

	.max_register = FSL_SAI_RMR,
941 942
	.reg_defaults = fsl_sai_reg_defaults_ofs0,
	.num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0),
943 944 945
	.readable_reg = fsl_sai_readable_reg,
	.volatile_reg = fsl_sai_volatile_reg,
	.writeable_reg = fsl_sai_writeable_reg,
946
	.cache_type = REGCACHE_FLAT,
947 948
};

949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
static int fsl_sai_check_version(struct device *dev)
{
	struct fsl_sai *sai = dev_get_drvdata(dev);
	unsigned char ofs = sai->soc_data->reg_offset;
	unsigned int val;
	int ret;

	if (FSL_SAI_TCSR(ofs) == FSL_SAI_VERID)
		return 0;

	ret = regmap_read(sai->regmap, FSL_SAI_VERID, &val);
	if (ret < 0)
		return ret;

	dev_dbg(dev, "VERID: 0x%016X\n", val);

	sai->verid.major = (val & FSL_SAI_VERID_MAJOR_MASK) >>
			   FSL_SAI_VERID_MAJOR_SHIFT;
	sai->verid.minor = (val & FSL_SAI_VERID_MINOR_MASK) >>
			   FSL_SAI_VERID_MINOR_SHIFT;
	sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK;

	ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
	if (ret < 0)
		return ret;

	dev_dbg(dev, "PARAM: 0x%016X\n", val);

	/* Max slots per frame, power of 2 */
	sai->param.slot_num = 1 <<
		((val & FSL_SAI_PARAM_SPF_MASK) >> FSL_SAI_PARAM_SPF_SHIFT);

	/* Words per fifo, power of 2 */
	sai->param.fifo_depth = 1 <<
		((val & FSL_SAI_PARAM_WPF_MASK) >> FSL_SAI_PARAM_WPF_SHIFT);

	/* Number of datalines implemented */
	sai->param.dataline = val & FSL_SAI_PARAM_DLN_MASK;

	return 0;
}

991 992
static int fsl_sai_probe(struct platform_device *pdev)
{
993
	struct device_node *np = pdev->dev.of_node;
994
	struct fsl_sai *sai;
995
	struct regmap *gpr;
996
	struct resource *res;
997
	void __iomem *base;
998 999
	char tmp[8];
	int irq, ret, i;
1000
	int index;
1001 1002 1003 1004 1005

	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
	if (!sai)
		return -ENOMEM;

1006
	sai->pdev = pdev;
L
Lucas Stach 已提交
1007
	sai->soc_data = of_device_get_match_data(&pdev->dev);
1008

1009
	sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
1010

1011
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1012 1013 1014 1015
	base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base))
		return PTR_ERR(base);

1016 1017
	if (sai->soc_data->reg_offset == 8) {
		fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8;
1018
		fsl_sai_regmap_config.max_register = FSL_SAI_MDIV;
1019 1020 1021 1022
		fsl_sai_regmap_config.num_reg_defaults =
			ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
	}

1023
	sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
1024 1025 1026
			"bus", base, &fsl_sai_regmap_config);

	/* Compatible with old DTB cases */
1027
	if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER)
1028 1029
		sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
				"sai", base, &fsl_sai_regmap_config);
1030 1031 1032
	if (IS_ERR(sai->regmap)) {
		dev_err(&pdev->dev, "regmap init failed\n");
		return PTR_ERR(sai->regmap);
1033 1034
	}

1035 1036 1037 1038 1039 1040 1041 1042
	/* No error out for old DTB cases but only mark the clock NULL */
	sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
	if (IS_ERR(sai->bus_clk)) {
		dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
				PTR_ERR(sai->bus_clk));
		sai->bus_clk = NULL;
	}

1043 1044 1045
	sai->mclk_clk[0] = sai->bus_clk;
	for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
		sprintf(tmp, "mclk%d", i);
1046 1047 1048 1049 1050 1051 1052 1053
		sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
		if (IS_ERR(sai->mclk_clk[i])) {
			dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
					i + 1, PTR_ERR(sai->mclk_clk[i]));
			sai->mclk_clk[i] = NULL;
		}
	}

1054
	irq = platform_get_irq(pdev, 0);
1055
	if (irq < 0)
1056 1057
		return irq;

M
Michael Walle 已提交
1058 1059
	ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED,
			       np->name, sai);
1060 1061 1062 1063 1064
	if (ret) {
		dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
		return ret;
	}

1065 1066 1067 1068 1069 1070 1071
	/* Sync Tx with Rx as default by following old DT binding */
	sai->synchronous[RX] = true;
	sai->synchronous[TX] = false;
	fsl_sai_dai.symmetric_rates = 1;
	fsl_sai_dai.symmetric_channels = 1;
	fsl_sai_dai.symmetric_samplebits = 1;

1072 1073 1074 1075 1076 1077 1078
	if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
	    of_find_property(np, "fsl,sai-asynchronous", NULL)) {
		/* error out if both synchronous and asynchronous are present */
		dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
		return -EINVAL;
	}

1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
	if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) {
		/* Sync Rx with Tx */
		sai->synchronous[RX] = false;
		sai->synchronous[TX] = true;
	} else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) {
		/* Discard all settings for asynchronous mode */
		sai->synchronous[RX] = false;
		sai->synchronous[TX] = false;
		fsl_sai_dai.symmetric_rates = 0;
		fsl_sai_dai.symmetric_channels = 0;
		fsl_sai_dai.symmetric_samplebits = 0;
	}

1092
	if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
F
Fabio Estevam 已提交
1093
	    of_device_is_compatible(np, "fsl,imx6ul-sai")) {
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
		gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
		if (IS_ERR(gpr)) {
			dev_err(&pdev->dev, "cannot find iomuxc registers\n");
			return PTR_ERR(gpr);
		}

		index = of_alias_get_id(np, "sai");
		if (index < 0)
			return index;

		regmap_update_bits(gpr, IOMUXC_GPR1, MCLK_DIR(index),
				   MCLK_DIR(index));
	}

1108 1109
	sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
	sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
1110 1111 1112 1113 1114
	sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
	sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;

	platform_set_drvdata(pdev, sai);

1115 1116 1117 1118 1119
	/* Get sai version */
	ret = fsl_sai_check_version(&pdev->dev);
	if (ret < 0)
		dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret);

1120
	pm_runtime_enable(&pdev->dev);
1121
	regcache_cache_only(sai->regmap, true);
1122

1123 1124 1125
	ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
			&fsl_sai_dai, 1);
	if (ret)
1126
		goto err_pm_disable;
1127

1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
	if (sai->soc_data->use_imx_pcm) {
		ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
		if (ret)
			goto err_pm_disable;
	} else {
		ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
		if (ret)
			goto err_pm_disable;
	}

	return ret;

err_pm_disable:
	pm_runtime_disable(&pdev->dev);

	return ret;
1144 1145
}

1146 1147 1148
static int fsl_sai_remove(struct platform_device *pdev)
{
	pm_runtime_disable(&pdev->dev);
1149 1150

	return 0;
1151 1152
}

L
Lucas Stach 已提交
1153 1154
static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
	.use_imx_pcm = false,
1155
	.use_edma = false,
1156
	.fifo_depth = 32,
1157
	.reg_offset = 0,
L
Lucas Stach 已提交
1158 1159 1160 1161
};

static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
	.use_imx_pcm = true,
1162
	.use_edma = false,
1163
	.fifo_depth = 32,
1164
	.reg_offset = 0,
L
Lucas Stach 已提交
1165 1166
};

1167 1168
static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
	.use_imx_pcm = true,
1169
	.use_edma = false,
1170 1171 1172 1173 1174 1175
	.fifo_depth = 16,
	.reg_offset = 8,
};

static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
	.use_imx_pcm = true,
1176
	.use_edma = false,
1177 1178 1179 1180
	.fifo_depth = 128,
	.reg_offset = 8,
};

1181 1182
static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
	.use_imx_pcm = true,
1183
	.use_edma = true,
1184 1185 1186 1187
	.fifo_depth = 64,
	.reg_offset = 0,
};

1188
static const struct of_device_id fsl_sai_ids[] = {
L
Lucas Stach 已提交
1189 1190 1191
	{ .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
	{ .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
	{ .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
1192 1193
	{ .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
	{ .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
1194
	{ .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data },
1195 1196
	{ /* sentinel */ }
};
1197
MODULE_DEVICE_TABLE(of, fsl_sai_ids);
1198

1199 1200
#ifdef CONFIG_PM
static int fsl_sai_runtime_suspend(struct device *dev)
1201 1202 1203
{
	struct fsl_sai *sai = dev_get_drvdata(dev);

1204 1205 1206 1207 1208 1209 1210 1211
	if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
		clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);

	if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK))
		clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]);

	clk_disable_unprepare(sai->bus_clk);

1212 1213 1214 1215 1216
	regcache_cache_only(sai->regmap, true);

	return 0;
}

1217
static int fsl_sai_runtime_resume(struct device *dev)
1218 1219
{
	struct fsl_sai *sai = dev_get_drvdata(dev);
1220
	unsigned int ofs = sai->soc_data->reg_offset;
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
	int ret;

	ret = clk_prepare_enable(sai->bus_clk);
	if (ret) {
		dev_err(dev, "failed to enable bus clock: %d\n", ret);
		return ret;
	}

	if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) {
		ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]);
		if (ret)
			goto disable_bus_clk;
	}

	if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) {
		ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]);
		if (ret)
			goto disable_tx_clk;
	}
1240 1241

	regcache_cache_only(sai->regmap, false);
1242
	regcache_mark_dirty(sai->regmap);
1243 1244
	regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
	regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
1245
	usleep_range(1000, 2000);
1246 1247
	regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
	regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264

	ret = regcache_sync(sai->regmap);
	if (ret)
		goto disable_rx_clk;

	return 0;

disable_rx_clk:
	if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
		clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
disable_tx_clk:
	if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK))
		clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]);
disable_bus_clk:
	clk_disable_unprepare(sai->bus_clk);

	return ret;
1265
}
1266
#endif /* CONFIG_PM */
1267 1268

static const struct dev_pm_ops fsl_sai_pm_ops = {
1269 1270 1271 1272
	SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend,
			   fsl_sai_runtime_resume, NULL)
	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
				pm_runtime_force_resume)
1273 1274
};

1275 1276
static struct platform_driver fsl_sai_driver = {
	.probe = fsl_sai_probe,
1277
	.remove = fsl_sai_remove,
1278 1279
	.driver = {
		.name = "fsl-sai",
1280
		.pm = &fsl_sai_pm_ops,
1281 1282 1283 1284 1285 1286 1287 1288 1289
		.of_match_table = fsl_sai_ids,
	},
};
module_platform_driver(fsl_sai_driver);

MODULE_DESCRIPTION("Freescale Soc SAI Interface");
MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
MODULE_ALIAS("platform:fsl-sai");
MODULE_LICENSE("GPL");