File Index
Files and directories
Sign in
FILE

kmb_platform.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/intel/keembay/kmb_platform.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright (C) 2020 Intel Corporation.
  4//
  5// Intel KeemBay Platform driver.
  6//
  7
  8#include <linux/bitrev.h>
  9#include <linux/clk.h>
 10#include <linux/dma-mapping.h>
 11#include <linux/io.h>
 12#include <linux/module.h>
 13#include <linux/of.h>
 14#include <sound/dmaengine_pcm.h>
 15#include <sound/pcm.h>
 16#include <sound/pcm_params.h>
 17#include <sound/soc.h>
 18#include "kmb_platform.h"
 19
 20#define PERIODS_MIN		2
 21#define PERIODS_MAX		48
 22#define PERIOD_BYTES_MIN	4096
 23#define BUFFER_BYTES_MAX	(PERIODS_MAX * PERIOD_BYTES_MIN)
 24#define TDM_OPERATION		5
 25#define I2S_OPERATION		0
 26#define DATA_WIDTH_CONFIG_BIT	6
 27#define TDM_CHANNEL_CONFIG_BIT	3
 28
 29static const struct snd_pcm_hardware kmb_pcm_hardware = {
 30	.info = SNDRV_PCM_INFO_INTERLEAVED |
 31		SNDRV_PCM_INFO_MMAP |
 32		SNDRV_PCM_INFO_MMAP_VALID |
 33		SNDRV_PCM_INFO_BATCH |
 34		SNDRV_PCM_INFO_BLOCK_TRANSFER,
 35	.rates = SNDRV_PCM_RATE_8000 |
 36		 SNDRV_PCM_RATE_16000 |
 37		 SNDRV_PCM_RATE_48000,
 38	.rate_min = 8000,
 39	.rate_max = 48000,
 40	.formats = SNDRV_PCM_FMTBIT_S16_LE |
 41		   SNDRV_PCM_FMTBIT_S24_LE |
 42		   SNDRV_PCM_FMTBIT_S32_LE |
 43		   SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
 44	.channels_min = 2,
 45	.channels_max = 2,
 46	.buffer_bytes_max = BUFFER_BYTES_MAX,
 47	.period_bytes_min = PERIOD_BYTES_MIN,
 48	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
 49	.periods_min = PERIODS_MIN,
 50	.periods_max = PERIODS_MAX,
 51	.fifo_size = 16,
 52};
 53
 54/*
 55 * Convert to ADV7511 HDMI hardware format.
 56 * ADV7511 HDMI chip need parity bit replaced by block start bit and
 57 * with the preamble bits left out.
 58 * ALSA IEC958 subframe format:
 59 * bit 0-3  = preamble (0x8 = block start)
 60 *     4-7  = AUX (=0)
 61 *     8-27 = audio data (without AUX if 24bit sample)
 62 *     28   = validity
 63 *     29   = user data
 64 *     30   = channel status
 65 *     31   = parity
 66 *
 67 * ADV7511 IEC958 subframe format:
 68 * bit 0-23  = audio data
 69 *     24    = validity
 70 *     25    = user data
 71 *     26    = channel status
 72 *     27    = block start
 73 *     28-31 = 0
 74 * MSB to LSB bit reverse by software as hardware not supporting it.
 75 */
 76static void hdmi_reformat_iec958(struct snd_pcm_runtime *runtime,
 77				 struct kmb_i2s_info *kmb_i2s,
 78				 unsigned int tx_ptr)
 79{
 80	u32(*buf)[2] = (void *)runtime->dma_area;
 81	unsigned long temp;
 82	u32 i, j, sample;
 83
 84	for (i = 0; i < kmb_i2s->fifo_th; i++) {
 85		j = 0;
 86		do {
 87			temp = buf[tx_ptr][j];
 88			/* Replace parity with block start*/
 89			assign_bit(31, &temp, (BIT(3) & temp));
 90			sample = bitrev32(temp);
 91			buf[tx_ptr][j] = sample << 4;
 92			j++;
 93		} while (j < 2);
 94		tx_ptr++;
 95	}
 96}
 97
 98static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
 99				  struct snd_pcm_runtime *runtime,
100				  unsigned int tx_ptr, bool *period_elapsed)
101{
102	unsigned int period_pos = tx_ptr % runtime->period_size;
103	void __iomem *i2s_base = kmb_i2s->i2s_base;
104	void *buf = runtime->dma_area;
105	int i;
106
107	if (kmb_i2s->iec958_fmt)
108		hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr);
109
110	/* KMB i2s uses two separate L/R FIFO */
111	for (i = 0; i < kmb_i2s->fifo_th; i++) {
112		if (kmb_i2s->config.data_width == 16) {
113			writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
114			writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
115		} else {
116			writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
117			writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
118		}
119
120		period_pos++;
121
122		if (++tx_ptr >= runtime->buffer_size)
123			tx_ptr = 0;
124	}
125
126	*period_elapsed = period_pos >= runtime->period_size;
127
128	return tx_ptr;
129}
130
131static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s,
132				  struct snd_pcm_runtime *runtime,
133				  unsigned int rx_ptr, bool *period_elapsed)
134{
135	unsigned int period_pos = rx_ptr % runtime->period_size;
136	void __iomem *i2s_base = kmb_i2s->i2s_base;
137	int chan = kmb_i2s->config.chan_nr;
138	void *buf = runtime->dma_area;
139	int i, j;
140
141	/* KMB i2s uses two separate L/R FIFO */
142	for (i = 0; i < kmb_i2s->fifo_th; i++) {
143		for (j = 0; j < chan / 2; j++) {
144			if (kmb_i2s->config.data_width == 16) {
145				((u16 *)buf)[rx_ptr * chan + (j * 2)] =
146						readl(i2s_base + LRBR_LTHR(j));
147				((u16 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
148						readl(i2s_base + RRBR_RTHR(j));
149			} else {
150				((u32 *)buf)[rx_ptr * chan + (j * 2)] =
151						readl(i2s_base + LRBR_LTHR(j));
152				((u32 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
153						readl(i2s_base + RRBR_RTHR(j));
154			}
155		}
156		period_pos++;
157
158		if (++rx_ptr >= runtime->buffer_size)
159			rx_ptr = 0;
160	}
161
162	*period_elapsed = period_pos >= runtime->period_size;
163
164	return rx_ptr;
165}
166
167static inline void kmb_i2s_disable_channels(struct kmb_i2s_info *kmb_i2s,
168					    u32 stream)
169{
170	u32 i;
171
172	/* Disable all channels regardless of configuration*/
173	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
174		for (i = 0; i < MAX_ISR; i++)
175			writel(0, kmb_i2s->i2s_base + TER(i));
176	} else {
177		for (i = 0; i < MAX_ISR; i++)
178			writel(0, kmb_i2s->i2s_base + RER(i));
179	}
180}
181
182static inline void kmb_i2s_clear_irqs(struct kmb_i2s_info *kmb_i2s, u32 stream)
183{
184	struct i2s_clk_config_data *config = &kmb_i2s->config;
185	u32 i;
186
187	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
188		for (i = 0; i < config->chan_nr / 2; i++)
189			readl(kmb_i2s->i2s_base + TOR(i));
190	} else {
191		for (i = 0; i < config->chan_nr / 2; i++)
192			readl(kmb_i2s->i2s_base + ROR(i));
193	}
194}
195
196static inline void kmb_i2s_irq_trigger(struct kmb_i2s_info *kmb_i2s,
197				       u32 stream, int chan_nr, bool trigger)
198{
199	u32 i, irq;
200	u32 flag;
201
202	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
203		flag = TX_INT_FLAG;
204	else
205		flag = RX_INT_FLAG;
206
207	for (i = 0; i < chan_nr / 2; i++) {
208		irq = readl(kmb_i2s->i2s_base + IMR(i));
209
210		if (trigger)
211			irq = irq & ~flag;
212		else
213			irq = irq | flag;
214
215		writel(irq, kmb_i2s->i2s_base + IMR(i));
216	}
217}
218
219static void kmb_pcm_operation(struct kmb_i2s_info *kmb_i2s, bool playback)
220{
221	struct snd_pcm_substream *substream;
222	bool period_elapsed;
223	unsigned int new_ptr;
224	unsigned int ptr;
225
226	if (playback)
227		substream = kmb_i2s->tx_substream;
228	else
229		substream = kmb_i2s->rx_substream;
230
231	if (!substream || !snd_pcm_running(substream))
232		return;
233
234	if (playback) {
235		ptr = kmb_i2s->tx_ptr;
236		new_ptr = kmb_pcm_tx_fn(kmb_i2s, substream->runtime,
237					ptr, &period_elapsed);
238		cmpxchg(&kmb_i2s->tx_ptr, ptr, new_ptr);
239	} else {
240		ptr = kmb_i2s->rx_ptr;
241		new_ptr = kmb_pcm_rx_fn(kmb_i2s, substream->runtime,
242					ptr, &period_elapsed);
243		cmpxchg(&kmb_i2s->rx_ptr, ptr, new_ptr);
244	}
245
246	if (period_elapsed)
247		snd_pcm_period_elapsed(substream);
248}
249
250static int kmb_pcm_open(struct snd_soc_component *component,
251			struct snd_pcm_substream *substream)
252{
253	struct snd_pcm_runtime *runtime = substream->runtime;
254	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
255	struct kmb_i2s_info *kmb_i2s;
256
257	kmb_i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
258	snd_soc_set_runtime_hwparams(substream, &kmb_pcm_hardware);
259	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
260	runtime->private_data = kmb_i2s;
261
262	return 0;
263}
264
265static int kmb_pcm_trigger(struct snd_soc_component *component,
266			   struct snd_pcm_substream *substream, int cmd)
267{
268	struct snd_pcm_runtime *runtime = substream->runtime;
269	struct kmb_i2s_info *kmb_i2s = runtime->private_data;
270
271	switch (cmd) {
272	case SNDRV_PCM_TRIGGER_START:
273		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
274			kmb_i2s->tx_ptr = 0;
275			kmb_i2s->tx_substream = substream;
276		} else {
277			kmb_i2s->rx_ptr = 0;
278			kmb_i2s->rx_substream = substream;
279		}
280		break;
281	case SNDRV_PCM_TRIGGER_STOP:
282		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
283			kmb_i2s->tx_substream = NULL;
284		else
285			kmb_i2s->rx_substream = NULL;
286		kmb_i2s->iec958_fmt = false;
287		break;
288	default:
289		return -EINVAL;
290	}
291
292	return 0;
293}
294
295static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id)
296{
297	struct kmb_i2s_info *kmb_i2s = dev_id;
298	struct i2s_clk_config_data *config = &kmb_i2s->config;
299	irqreturn_t ret = IRQ_NONE;
300	u32 tx_enabled = 0;
301	u32 isr[4];
302	int i;
303
304	for (i = 0; i < config->chan_nr / 2; i++)
305		isr[i] = readl(kmb_i2s->i2s_base + ISR(i));
306
307	kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK);
308	kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE);
309	/* Only check TX interrupt if TX is active */
310	tx_enabled = readl(kmb_i2s->i2s_base + ITER);
311
312	/*
313	 * Data available. Retrieve samples from FIFO
314	 */
315
316	/*
317	 * 8 channel audio will have isr[0..2] triggered,
318	 * reading the specific isr based on the audio configuration,
319	 * to avoid reading the buffers too early.
320	 */
321	switch (config->chan_nr) {
322	case 2:
323		if (isr[0] & ISR_RXDA)
324			kmb_pcm_operation(kmb_i2s, false);
325		ret = IRQ_HANDLED;
326		break;
327	case 4:
328		if (isr[1] & ISR_RXDA)
329			kmb_pcm_operation(kmb_i2s, false);
330		ret = IRQ_HANDLED;
331		break;
332	case 8:
333		if (isr[3] & ISR_RXDA)
334			kmb_pcm_operation(kmb_i2s, false);
335		ret = IRQ_HANDLED;
336		break;
337	}
338
339	for (i = 0; i < config->chan_nr / 2; i++) {
340		/*
341		 * Check if TX fifo is empty. If empty fill FIFO with samples
342		 */
343		if ((isr[i] & ISR_TXFE) && tx_enabled) {
344			kmb_pcm_operation(kmb_i2s, true);
345			ret = IRQ_HANDLED;
346		}
347
348		/* Error Handling: TX */
349		if (isr[i] & ISR_TXFO) {
350			dev_dbg(kmb_i2s->dev, "TX overrun (ch_id=%d)\n", i);
351			ret = IRQ_HANDLED;
352		}
353		/* Error Handling: RX */
354		if (isr[i] & ISR_RXFO) {
355			dev_dbg(kmb_i2s->dev, "RX overrun (ch_id=%d)\n", i);
356			ret = IRQ_HANDLED;
357		}
358	}
359
360	return ret;
361}
362
363static int kmb_platform_pcm_new(struct snd_soc_component *component,
364				struct snd_soc_pcm_runtime *soc_runtime)
365{
366	size_t size = kmb_pcm_hardware.buffer_bytes_max;
367	/* Use SNDRV_DMA_TYPE_CONTINUOUS as KMB doesn't use PCI sg buffer */
368	snd_pcm_set_managed_buffer_all(soc_runtime->pcm,
369				       SNDRV_DMA_TYPE_CONTINUOUS,
370				       NULL, size, size);
371	return 0;
372}
373
374static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component,
375					 struct snd_pcm_substream *substream)
376{
377	struct snd_pcm_runtime *runtime = substream->runtime;
378	struct kmb_i2s_info *kmb_i2s = runtime->private_data;
379	snd_pcm_uframes_t pos;
380
381	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
382		pos = kmb_i2s->tx_ptr;
383	else
384		pos = kmb_i2s->rx_ptr;
385
386	return pos < runtime->buffer_size ? pos : 0;
387}
388
389static const struct snd_soc_component_driver kmb_component = {
390	.name			= "kmb",
391	.pcm_construct		= kmb_platform_pcm_new,
392	.open			= kmb_pcm_open,
393	.trigger		= kmb_pcm_trigger,
394	.pointer		= kmb_pcm_pointer,
395	.legacy_dai_naming	= 1,
396};
397
398static const struct snd_soc_component_driver kmb_component_dma = {
399	.name			= "kmb",
400	.legacy_dai_naming	= 1,
401};
402
403static int kmb_probe(struct snd_soc_dai *cpu_dai)
404{
405	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
406
407	if (kmb_i2s->use_pio)
408		return 0;
409
410	snd_soc_dai_init_dma_data(cpu_dai, &kmb_i2s->play_dma_data,
411				  &kmb_i2s->capture_dma_data);
412
413	return 0;
414}
415
416static inline void kmb_i2s_enable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
417{
418	u32 dma_reg;
419
420	dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
421	/* Enable DMA handshake for stream */
422	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
423		dma_reg |= I2S_DMAEN_TXBLOCK;
424	else
425		dma_reg |= I2S_DMAEN_RXBLOCK;
426
427	writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
428}
429
430static inline void kmb_i2s_disable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
431{
432	u32 dma_reg;
433
434	dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
435	/* Disable DMA handshake for stream */
436	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
437		dma_reg &= ~I2S_DMAEN_TXBLOCK;
438		writel(1, kmb_i2s->i2s_base + I2S_RTXDMA);
439	} else {
440		dma_reg &= ~I2S_DMAEN_RXBLOCK;
441		writel(1, kmb_i2s->i2s_base + I2S_RRXDMA);
442	}
443	writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
444}
445
446static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
447			  struct snd_pcm_substream *substream)
448{
449	struct i2s_clk_config_data *config = &kmb_i2s->config;
450
451	/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
452	writel(1, kmb_i2s->i2s_base + IER);
453
454	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
455		writel(1, kmb_i2s->i2s_base + ITER);
456	else
457		writel(1, kmb_i2s->i2s_base + IRER);
458
459	if (kmb_i2s->use_pio)
460		kmb_i2s_irq_trigger(kmb_i2s, substream->stream,
461				    config->chan_nr, true);
462	else
463		kmb_i2s_enable_dma(kmb_i2s, substream->stream);
464
465	if (kmb_i2s->clock_provider)
466		writel(1, kmb_i2s->i2s_base + CER);
467	else
468		writel(0, kmb_i2s->i2s_base + CER);
469}
470
471static void kmb_i2s_stop(struct kmb_i2s_info *kmb_i2s,
472			 struct snd_pcm_substream *substream)
473{
474	/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
475	kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
476
477	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
478		writel(0, kmb_i2s->i2s_base + ITER);
479	else
480		writel(0, kmb_i2s->i2s_base + IRER);
481
482	kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
483
484	if (!kmb_i2s->active) {
485		writel(0, kmb_i2s->i2s_base + CER);
486		writel(0, kmb_i2s->i2s_base + IER);
487	}
488}
489
490static void kmb_disable_clk(void *clk)
491{
492	clk_disable_unprepare(clk);
493}
494
495static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
496{
497	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
498	int ret;
499
500	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
501	case SND_SOC_DAIFMT_BC_FC:
502		kmb_i2s->clock_provider = false;
503		ret = 0;
504		break;
505	case SND_SOC_DAIFMT_BP_FP:
506		writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
507
508		ret = clk_prepare_enable(kmb_i2s->clk_i2s);
509		if (ret < 0)
510			return ret;
511
512		ret = devm_add_action_or_reset(kmb_i2s->dev, kmb_disable_clk,
513					       kmb_i2s->clk_i2s);
514		if (ret)
515			return ret;
516
517		kmb_i2s->clock_provider = true;
518		break;
519	default:
520		return -EINVAL;
521	}
522
523	return ret;
524}
525
526static int kmb_dai_trigger(struct snd_pcm_substream *substream,
527			   int cmd, struct snd_soc_dai *cpu_dai)
528{
529	struct kmb_i2s_info *kmb_i2s  = snd_soc_dai_get_drvdata(cpu_dai);
530
531	switch (cmd) {
532	case SNDRV_PCM_TRIGGER_START:
533		/* Keep track of i2s activity before turn off
534		 * the i2s interface
535		 */
536		kmb_i2s->active++;
537		kmb_i2s_start(kmb_i2s, substream);
538		break;
539	case SNDRV_PCM_TRIGGER_STOP:
540		kmb_i2s->active--;
541		if (kmb_i2s->use_pio)
542			kmb_i2s_stop(kmb_i2s, substream);
543		break;
544	default:
545		return  -EINVAL;
546	}
547
548	return 0;
549}
550
551static void kmb_i2s_config(struct kmb_i2s_info *kmb_i2s, int stream)
552{
553	struct i2s_clk_config_data *config = &kmb_i2s->config;
554	u32 ch_reg;
555
556	kmb_i2s_disable_channels(kmb_i2s, stream);
557
558	for (ch_reg = 0; ch_reg < config->chan_nr / 2; ch_reg++) {
559		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
560			writel(kmb_i2s->xfer_resolution,
561			       kmb_i2s->i2s_base + TCR(ch_reg));
562
563			writel(kmb_i2s->fifo_th - 1,
564			       kmb_i2s->i2s_base + TFCR(ch_reg));
565
566			writel(1, kmb_i2s->i2s_base + TER(ch_reg));
567		} else {
568			writel(kmb_i2s->xfer_resolution,
569			       kmb_i2s->i2s_base + RCR(ch_reg));
570
571			writel(kmb_i2s->fifo_th - 1,
572			       kmb_i2s->i2s_base + RFCR(ch_reg));
573
574			writel(1, kmb_i2s->i2s_base + RER(ch_reg));
575		}
576	}
577}
578
579static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
580			     struct snd_pcm_hw_params *hw_params,
581			     struct snd_soc_dai *cpu_dai)
582{
583	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
584	struct i2s_clk_config_data *config = &kmb_i2s->config;
585	u32 write_val;
586	int ret;
587
588	switch (params_format(hw_params)) {
589	case SNDRV_PCM_FORMAT_S16_LE:
590		config->data_width = 16;
591		kmb_i2s->ccr = 0x00;
592		kmb_i2s->xfer_resolution = 0x02;
593		kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
594		kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
595		break;
596	case SNDRV_PCM_FORMAT_S24_LE:
597		config->data_width = 32;
598		kmb_i2s->ccr = 0x14;
599		kmb_i2s->xfer_resolution = 0x05;
600		kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
601		kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
602		break;
603	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
604		kmb_i2s->iec958_fmt = true;
605		fallthrough;
606	case SNDRV_PCM_FORMAT_S32_LE:
607		config->data_width = 32;
608		kmb_i2s->ccr = 0x10;
609		kmb_i2s->xfer_resolution = 0x05;
610		kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
611		kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
612		break;
613	default:
614		dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt");
615		return -EINVAL;
616	}
617
618	config->chan_nr = params_channels(hw_params);
619
620	switch (config->chan_nr) {
621	case 8:
622	case 4:
623		/*
624		 * Platform is not capable of providing clocks for
625		 * multi channel audio
626		 */
627		if (kmb_i2s->clock_provider)
628			return -EINVAL;
629
630		write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
631				(config->data_width << DATA_WIDTH_CONFIG_BIT) |
632				TDM_OPERATION;
633
634		writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
635		break;
636	case 2:
637		/*
638		 * Platform is only capable of providing clocks need for
639		 * 2 channel master mode
640		 */
641		if (!(kmb_i2s->clock_provider))
642			return -EINVAL;
643
644		write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
645				(config->data_width << DATA_WIDTH_CONFIG_BIT) |
646				CLOCK_PROVIDER_MODE | I2S_OPERATION;
647
648		writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
649		break;
650	default:
651		dev_dbg(kmb_i2s->dev, "channel not supported\n");
652		return -EINVAL;
653	}
654
655	kmb_i2s_config(kmb_i2s, substream->stream);
656
657	writel(kmb_i2s->ccr, kmb_i2s->i2s_base + CCR);
658
659	config->sample_rate = params_rate(hw_params);
660
661	if (kmb_i2s->clock_provider) {
662		/* Only 2 ch supported in Master mode */
663		u32 bitclk = config->sample_rate * config->data_width * 2;
664
665		ret = clk_set_rate(kmb_i2s->clk_i2s, bitclk);
666		if (ret) {
667			dev_err(kmb_i2s->dev,
668				"Can't set I2S clock rate: %d\n", ret);
669			return ret;
670		}
671	}
672
673	return 0;
674}
675
676static int kmb_dai_prepare(struct snd_pcm_substream *substream,
677			   struct snd_soc_dai *cpu_dai)
678{
679	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
680
681	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
682		writel(1, kmb_i2s->i2s_base + TXFFR);
683	else
684		writel(1, kmb_i2s->i2s_base + RXFFR);
685
686	return 0;
687}
688
689static int kmb_dai_startup(struct snd_pcm_substream *substream,
690			   struct snd_soc_dai *cpu_dai)
691{
692	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
693	struct snd_dmaengine_dai_dma_data *dma_data;
694
695	if (kmb_i2s->use_pio)
696		return 0;
697
698	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
699		dma_data = &kmb_i2s->play_dma_data;
700	else
701		dma_data = &kmb_i2s->capture_dma_data;
702
703	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
704
705	return 0;
706}
707
708static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
709			   struct snd_soc_dai *cpu_dai)
710{
711	struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
712	/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
713	if (kmb_i2s->use_pio)
714		kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
715
716	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
717		writel(0, kmb_i2s->i2s_base + ITER);
718	else
719		writel(0, kmb_i2s->i2s_base + IRER);
720
721	if (kmb_i2s->use_pio)
722		kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
723	else
724		kmb_i2s_disable_dma(kmb_i2s, substream->stream);
725
726	if (!kmb_i2s->active) {
727		writel(0, kmb_i2s->i2s_base + CER);
728		writel(0, kmb_i2s->i2s_base + IER);
729	}
730
731	return 0;
732}
733
734static const struct snd_soc_dai_ops kmb_dai_ops = {
735	.probe		= kmb_probe,
736	.startup	= kmb_dai_startup,
737	.trigger	= kmb_dai_trigger,
738	.hw_params	= kmb_dai_hw_params,
739	.hw_free	= kmb_dai_hw_free,
740	.prepare	= kmb_dai_prepare,
741	.set_fmt	= kmb_set_dai_fmt,
742};
743
744static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
745	{
746		.name = "intel_kmb_hdmi_i2s",
747		.playback = {
748			.channels_min = 2,
749			.channels_max = 2,
750			.rates = SNDRV_PCM_RATE_48000,
751			.rate_min = 48000,
752			.rate_max = 48000,
753			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
754				    SNDRV_PCM_FMTBIT_S24_LE |
755				    SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
756		},
757		.ops = &kmb_dai_ops,
758	},
759};
760
761static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
762	{
763		.name = "intel_kmb_i2s",
764		.playback = {
765			.channels_min = 2,
766			.channels_max = 2,
767			.rates = SNDRV_PCM_RATE_8000 |
768				 SNDRV_PCM_RATE_16000 |
769				 SNDRV_PCM_RATE_48000,
770			.rate_min = 8000,
771			.rate_max = 48000,
772			.formats = (SNDRV_PCM_FMTBIT_S32_LE |
773				    SNDRV_PCM_FMTBIT_S24_LE |
774				    SNDRV_PCM_FMTBIT_S16_LE),
775		},
776		.capture = {
777			.channels_min = 2,
778			.channels_max = 2,
779			.rates = SNDRV_PCM_RATE_8000 |
780				 SNDRV_PCM_RATE_16000 |
781				 SNDRV_PCM_RATE_48000,
782			.rate_min = 8000,
783			.rate_max = 48000,
784			.formats = (SNDRV_PCM_FMTBIT_S32_LE |
785				    SNDRV_PCM_FMTBIT_S24_LE |
786				    SNDRV_PCM_FMTBIT_S16_LE),
787		},
788		.ops = &kmb_dai_ops,
789	},
790};
791
792static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
793	{
794		.name = "intel_kmb_tdm",
795		.capture = {
796			.channels_min = 4,
797			.channels_max = 8,
798			.rates = SNDRV_PCM_RATE_8000 |
799				 SNDRV_PCM_RATE_16000 |
800				 SNDRV_PCM_RATE_48000,
801			.rate_min = 8000,
802			.rate_max = 48000,
803			.formats = (SNDRV_PCM_FMTBIT_S32_LE |
804				    SNDRV_PCM_FMTBIT_S24_LE |
805				    SNDRV_PCM_FMTBIT_S16_LE),
806		},
807		.ops = &kmb_dai_ops,
808	},
809};
810
811static const struct of_device_id kmb_plat_of_match[] = {
812	{ .compatible = "intel,keembay-i2s", .data = &intel_kmb_i2s_dai},
813	{ .compatible = "intel,keembay-hdmi-i2s", .data = &intel_kmb_hdmi_dai},
814	{ .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai},
815	{}
816};
817MODULE_DEVICE_TABLE(of, kmb_plat_of_match);
818
819static int kmb_plat_dai_probe(struct platform_device *pdev)
820{
821	struct device_node *np = pdev->dev.of_node;
822	struct snd_soc_dai_driver *kmb_i2s_dai;
823	struct device *dev = &pdev->dev;
824	struct kmb_i2s_info *kmb_i2s;
825	struct resource *res;
826	int ret, irq;
827	u32 comp1_reg;
828
829	kmb_i2s = devm_kzalloc(dev, sizeof(*kmb_i2s), GFP_KERNEL);
830	if (!kmb_i2s)
831		return -ENOMEM;
832
833	kmb_i2s_dai = (struct snd_soc_dai_driver *)device_get_match_data(&pdev->dev);
834
835	/* Prepare the related clocks */
836	kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk");
837	if (IS_ERR(kmb_i2s->clk_apb)) {
838		dev_err(dev, "Failed to get apb clock\n");
839		return PTR_ERR(kmb_i2s->clk_apb);
840	}
841
842	ret = clk_prepare_enable(kmb_i2s->clk_apb);
843	if (ret < 0)
844		return ret;
845
846	ret = devm_add_action_or_reset(dev, kmb_disable_clk, kmb_i2s->clk_apb);
847	if (ret) {
848		dev_err(dev, "Failed to add clk_apb reset action\n");
849		return ret;
850	}
851
852	kmb_i2s->clk_i2s = devm_clk_get(dev, "osc");
853	if (IS_ERR(kmb_i2s->clk_i2s)) {
854		dev_err(dev, "Failed to get osc clock\n");
855		return PTR_ERR(kmb_i2s->clk_i2s);
856	}
857
858	kmb_i2s->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
859	if (IS_ERR(kmb_i2s->i2s_base))
860		return PTR_ERR(kmb_i2s->i2s_base);
861
862	kmb_i2s->pss_base = devm_platform_ioremap_resource(pdev, 1);
863	if (IS_ERR(kmb_i2s->pss_base))
864		return PTR_ERR(kmb_i2s->pss_base);
865
866	kmb_i2s->dev = &pdev->dev;
867
868	comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1);
869
870	kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2;
871
872	kmb_i2s->use_pio = !of_property_present(np, "dmas");
873
874	if (kmb_i2s->use_pio) {
875		irq = platform_get_irq_optional(pdev, 0);
876		if (irq > 0) {
877			ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
878					       pdev->name, kmb_i2s);
879			if (ret < 0) {
880				dev_err(dev, "failed to request irq\n");
881				return ret;
882			}
883		}
884		ret = devm_snd_soc_register_component(dev, &kmb_component,
885						      kmb_i2s_dai, 1);
886	} else {
887		kmb_i2s->play_dma_data.addr = res->start + I2S_TXDMA;
888		kmb_i2s->capture_dma_data.addr = res->start + I2S_RXDMA;
889		ret = snd_dmaengine_pcm_register(&pdev->dev,
890						 NULL, 0);
891		if (ret) {
892			dev_err(&pdev->dev, "could not register dmaengine: %d\n",
893				ret);
894			return ret;
895		}
896		ret = devm_snd_soc_register_component(dev, &kmb_component_dma,
897						      kmb_i2s_dai, 1);
898	}
899
900	if (ret) {
901		dev_err(dev, "not able to register dai\n");
902		return ret;
903	}
904
905	/* To ensure none of the channels are enabled at boot up */
906	kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK);
907	kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE);
908
909	dev_set_drvdata(dev, kmb_i2s);
910
911	return ret;
912}
913
914static struct platform_driver kmb_plat_dai_driver = {
915	.driver		= {
916		.name		= "kmb-plat-dai",
917		.of_match_table = kmb_plat_of_match,
918	},
919	.probe		= kmb_plat_dai_probe,
920};
921
922module_platform_driver(kmb_plat_dai_driver);
923
924MODULE_DESCRIPTION("ASoC Intel KeemBay Platform driver");
925MODULE_AUTHOR("Sia Jee Heng <jee.heng.sia@intel.com>");
926MODULE_AUTHOR("Sit, Michael Wei Hong <michael.wei.hong.sit@intel.com>");
927MODULE_LICENSE("GPL v2");
928MODULE_ALIAS("platform:kmb_platform");
~/ Read-only file preview.