fsl_sai.c 31.4 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
};

801 802
static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
{
803 804 805 806 807 808 809 810 811
	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;

812
	switch (reg) {
813 814 815 816 817 818 819 820
	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:
821
	case FSL_SAI_TMR:
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
	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:
838 839 840 841 842 843 844 845 846
	case FSL_SAI_RMR:
		return true;
	default:
		return false;
	}
}

static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
{
847 848 849 850 851 852
	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;

853
	switch (reg) {
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
	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:
878 879 880 881 882 883 884 885
		return true;
	default:
		return false;
	}
}

static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
{
886 887 888 889 890 891 892 893 894
	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;

895
	switch (reg) {
896 897 898 899 900 901 902 903
	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:
904 905 906 907 908 909 910 911
	case FSL_SAI_TMR:
	case FSL_SAI_RMR:
		return true;
	default:
		return false;
	}
}

912
static struct regmap_config fsl_sai_regmap_config = {
913 914 915
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
916
	.fast_io = true,
917 918

	.max_register = FSL_SAI_RMR,
919 920
	.reg_defaults = fsl_sai_reg_defaults_ofs0,
	.num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0),
921 922 923
	.readable_reg = fsl_sai_readable_reg,
	.volatile_reg = fsl_sai_volatile_reg,
	.writeable_reg = fsl_sai_writeable_reg,
924
	.cache_type = REGCACHE_FLAT,
925 926
};

927 928
static int fsl_sai_probe(struct platform_device *pdev)
{
929
	struct device_node *np = pdev->dev.of_node;
930
	struct fsl_sai *sai;
931
	struct regmap *gpr;
932
	struct resource *res;
933
	void __iomem *base;
934 935
	char tmp[8];
	int irq, ret, i;
936
	int index;
937 938 939 940 941

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

942
	sai->pdev = pdev;
L
Lucas Stach 已提交
943
	sai->soc_data = of_device_get_match_data(&pdev->dev);
944

945
	sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
946

947
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
948 949 950 951
	base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base))
		return PTR_ERR(base);

952 953 954 955 956 957
	if (sai->soc_data->reg_offset == 8) {
		fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8;
		fsl_sai_regmap_config.num_reg_defaults =
			ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
	}

958
	sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
959 960 961
			"bus", base, &fsl_sai_regmap_config);

	/* Compatible with old DTB cases */
962
	if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER)
963 964
		sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
				"sai", base, &fsl_sai_regmap_config);
965 966 967
	if (IS_ERR(sai->regmap)) {
		dev_err(&pdev->dev, "regmap init failed\n");
		return PTR_ERR(sai->regmap);
968 969
	}

970 971 972 973 974 975 976 977
	/* 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;
	}

978 979 980
	sai->mclk_clk[0] = sai->bus_clk;
	for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
		sprintf(tmp, "mclk%d", i);
981 982 983 984 985 986 987 988
		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;
		}
	}

989
	irq = platform_get_irq(pdev, 0);
990
	if (irq < 0)
991 992
		return irq;

M
Michael Walle 已提交
993 994
	ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED,
			       np->name, sai);
995 996 997 998 999
	if (ret) {
		dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
		return ret;
	}

1000 1001 1002 1003 1004 1005 1006
	/* 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;

1007 1008 1009 1010 1011 1012 1013
	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;
	}

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
	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;
	}

1027
	if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
F
Fabio Estevam 已提交
1028
	    of_device_is_compatible(np, "fsl,imx6ul-sai")) {
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
		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));
	}

1043 1044
	sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
	sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
1045 1046 1047 1048 1049
	sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
	sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;

	platform_set_drvdata(pdev, sai);

1050
	pm_runtime_enable(&pdev->dev);
1051
	regcache_cache_only(sai->regmap, true);
1052

1053 1054 1055
	ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
			&fsl_sai_dai, 1);
	if (ret)
1056
		goto err_pm_disable;
1057

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
	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;
1074 1075
}

1076 1077 1078
static int fsl_sai_remove(struct platform_device *pdev)
{
	pm_runtime_disable(&pdev->dev);
1079 1080

	return 0;
1081 1082
}

L
Lucas Stach 已提交
1083 1084
static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
	.use_imx_pcm = false,
1085
	.use_edma = false,
1086
	.fifo_depth = 32,
1087
	.reg_offset = 0,
L
Lucas Stach 已提交
1088 1089 1090 1091
};

static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
	.use_imx_pcm = true,
1092
	.use_edma = false,
1093
	.fifo_depth = 32,
1094
	.reg_offset = 0,
L
Lucas Stach 已提交
1095 1096
};

1097 1098
static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
	.use_imx_pcm = true,
1099
	.use_edma = false,
1100 1101 1102 1103 1104 1105
	.fifo_depth = 16,
	.reg_offset = 8,
};

static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
	.use_imx_pcm = true,
1106
	.use_edma = false,
1107 1108 1109 1110
	.fifo_depth = 128,
	.reg_offset = 8,
};

1111 1112
static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
	.use_imx_pcm = true,
1113
	.use_edma = true,
1114 1115 1116 1117
	.fifo_depth = 64,
	.reg_offset = 0,
};

1118
static const struct of_device_id fsl_sai_ids[] = {
L
Lucas Stach 已提交
1119 1120 1121
	{ .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 },
1122 1123
	{ .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
	{ .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
1124
	{ .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data },
1125 1126
	{ /* sentinel */ }
};
1127
MODULE_DEVICE_TABLE(of, fsl_sai_ids);
1128

1129 1130
#ifdef CONFIG_PM
static int fsl_sai_runtime_suspend(struct device *dev)
1131 1132 1133
{
	struct fsl_sai *sai = dev_get_drvdata(dev);

1134 1135 1136 1137 1138 1139 1140 1141
	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);

1142 1143 1144 1145 1146
	regcache_cache_only(sai->regmap, true);

	return 0;
}

1147
static int fsl_sai_runtime_resume(struct device *dev)
1148 1149
{
	struct fsl_sai *sai = dev_get_drvdata(dev);
1150
	unsigned int ofs = sai->soc_data->reg_offset;
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
	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;
	}
1170 1171

	regcache_cache_only(sai->regmap, false);
1172
	regcache_mark_dirty(sai->regmap);
1173 1174
	regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
	regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
1175
	usleep_range(1000, 2000);
1176 1177
	regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
	regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194

	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;
1195
}
1196
#endif /* CONFIG_PM */
1197 1198

static const struct dev_pm_ops fsl_sai_pm_ops = {
1199 1200 1201 1202
	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)
1203 1204
};

1205 1206
static struct platform_driver fsl_sai_driver = {
	.probe = fsl_sai_probe,
1207
	.remove = fsl_sai_remove,
1208 1209
	.driver = {
		.name = "fsl-sai",
1210
		.pm = &fsl_sai_pm_ops,
1211 1212 1213 1214 1215 1216 1217 1218 1219
		.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");