~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/keembay/kmb_platform.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 29 static 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  */
 76 static 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 
 98 static 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 
131 static 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 
167 static 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 
182 static 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 
196 static 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 
219 static 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 
250 static 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 
265 static 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 
295 static 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 
363 static 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 
374 static 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 
389 static 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 
398 static const struct snd_soc_component_driver kmb_component_dma = {
399         .name                   = "kmb",
400         .legacy_dai_naming      = 1,
401 };
402 
403 static 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 
416 static 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 
430 static 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 
446 static 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 
471 static 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 
490 static void kmb_disable_clk(void *clk)
491 {
492         clk_disable_unprepare(clk);
493 }
494 
495 static 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 
526 static 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 
551 static 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 
579 static 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 
676 static 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 
689 static 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 
708 static 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 
734 static 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 
744 static 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 
761 static 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 
792 static 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 
811 static 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 };
817 MODULE_DEVICE_TABLE(of, kmb_plat_of_match);
818 
819 static 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_read_bool(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 
914 static 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 
922 module_platform_driver(kmb_plat_dai_driver);
923 
924 MODULE_DESCRIPTION("ASoC Intel KeemBay Platform driver");
925 MODULE_AUTHOR("Sia Jee Heng <jee.heng.sia@intel.com>");
926 MODULE_AUTHOR("Sit, Michael Wei Hong <michael.wei.hong.sit@intel.com>");
927 MODULE_LICENSE("GPL v2");
928 MODULE_ALIAS("platform:kmb_platform");
929 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php