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

TOMOYO Linux Cross Reference
Linux/sound/soc/meson/aiu-fifo.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
  2 //
  3 // Copyright (c) 2020 BayLibre, SAS.
  4 // Author: Jerome Brunet <jbrunet@baylibre.com>
  5 
  6 #include <linux/bitfield.h>
  7 #include <linux/clk.h>
  8 #include <linux/dma-mapping.h>
  9 #include <sound/pcm_params.h>
 10 #include <sound/soc.h>
 11 #include <sound/soc-dai.h>
 12 
 13 #include "aiu-fifo.h"
 14 
 15 #define AIU_MEM_START   0x00
 16 #define AIU_MEM_RD      0x04
 17 #define AIU_MEM_END     0x08
 18 #define AIU_MEM_MASKS   0x0c
 19 #define  AIU_MEM_MASK_CH_RD GENMASK(7, 0)
 20 #define  AIU_MEM_MASK_CH_MEM GENMASK(15, 8)
 21 #define AIU_MEM_CONTROL 0x10
 22 #define  AIU_MEM_CONTROL_INIT BIT(0)
 23 #define  AIU_MEM_CONTROL_FILL_EN BIT(1)
 24 #define  AIU_MEM_CONTROL_EMPTY_EN BIT(2)
 25 
 26 static struct snd_soc_dai *aiu_fifo_dai(struct snd_pcm_substream *ss)
 27 {
 28         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss);
 29 
 30         return snd_soc_rtd_to_cpu(rtd, 0);
 31 }
 32 
 33 snd_pcm_uframes_t aiu_fifo_pointer(struct snd_soc_component *component,
 34                                    struct snd_pcm_substream *substream)
 35 {
 36         struct snd_soc_dai *dai = aiu_fifo_dai(substream);
 37         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
 38         struct snd_pcm_runtime *runtime = substream->runtime;
 39         unsigned int addr;
 40 
 41         addr = snd_soc_component_read(component, fifo->mem_offset + AIU_MEM_RD);
 42 
 43         return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
 44 }
 45 
 46 static void aiu_fifo_enable(struct snd_soc_dai *dai, bool enable)
 47 {
 48         struct snd_soc_component *component = dai->component;
 49         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
 50         unsigned int en_mask = (AIU_MEM_CONTROL_FILL_EN |
 51                                 AIU_MEM_CONTROL_EMPTY_EN);
 52 
 53         snd_soc_component_update_bits(component,
 54                                       fifo->mem_offset + AIU_MEM_CONTROL,
 55                                       en_mask, enable ? en_mask : 0);
 56 }
 57 
 58 int aiu_fifo_trigger(struct snd_pcm_substream *substream, int cmd,
 59                      struct snd_soc_dai *dai)
 60 {
 61         switch (cmd) {
 62         case SNDRV_PCM_TRIGGER_START:
 63         case SNDRV_PCM_TRIGGER_RESUME:
 64         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 65                 aiu_fifo_enable(dai, true);
 66                 break;
 67         case SNDRV_PCM_TRIGGER_SUSPEND:
 68         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 69         case SNDRV_PCM_TRIGGER_STOP:
 70                 aiu_fifo_enable(dai, false);
 71                 break;
 72         default:
 73                 return -EINVAL;
 74         }
 75 
 76         return 0;
 77 }
 78 
 79 int aiu_fifo_prepare(struct snd_pcm_substream *substream,
 80                      struct snd_soc_dai *dai)
 81 {
 82         struct snd_soc_component *component = dai->component;
 83         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
 84 
 85         snd_soc_component_update_bits(component,
 86                                       fifo->mem_offset + AIU_MEM_CONTROL,
 87                                       AIU_MEM_CONTROL_INIT,
 88                                       AIU_MEM_CONTROL_INIT);
 89         snd_soc_component_update_bits(component,
 90                                       fifo->mem_offset + AIU_MEM_CONTROL,
 91                                       AIU_MEM_CONTROL_INIT, 0);
 92         return 0;
 93 }
 94 
 95 int aiu_fifo_hw_params(struct snd_pcm_substream *substream,
 96                        struct snd_pcm_hw_params *params,
 97                        struct snd_soc_dai *dai)
 98 {
 99         struct snd_pcm_runtime *runtime = substream->runtime;
100         struct snd_soc_component *component = dai->component;
101         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
102         dma_addr_t end;
103 
104         /* Setup the fifo boundaries */
105         end = runtime->dma_addr + runtime->dma_bytes - fifo->fifo_block;
106         snd_soc_component_write(component, fifo->mem_offset + AIU_MEM_START,
107                                 runtime->dma_addr);
108         snd_soc_component_write(component, fifo->mem_offset + AIU_MEM_RD,
109                                 runtime->dma_addr);
110         snd_soc_component_write(component, fifo->mem_offset + AIU_MEM_END,
111                                 end);
112 
113         /* Setup the fifo to read all the memory - no skip */
114         snd_soc_component_update_bits(component,
115                                       fifo->mem_offset + AIU_MEM_MASKS,
116                                       AIU_MEM_MASK_CH_RD | AIU_MEM_MASK_CH_MEM,
117                                       FIELD_PREP(AIU_MEM_MASK_CH_RD, 0xff) |
118                                       FIELD_PREP(AIU_MEM_MASK_CH_MEM, 0xff));
119 
120         return 0;
121 }
122 
123 static irqreturn_t aiu_fifo_isr(int irq, void *dev_id)
124 {
125         struct snd_pcm_substream *playback = dev_id;
126 
127         snd_pcm_period_elapsed(playback);
128 
129         return IRQ_HANDLED;
130 }
131 
132 int aiu_fifo_startup(struct snd_pcm_substream *substream,
133                      struct snd_soc_dai *dai)
134 {
135         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
136         int ret;
137 
138         snd_soc_set_runtime_hwparams(substream, fifo->pcm);
139 
140         /*
141          * Make sure the buffer and period size are multiple of the fifo burst
142          * size
143          */
144         ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
145                                          SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
146                                          fifo->fifo_block);
147         if (ret)
148                 return ret;
149 
150         ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
151                                          SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
152                                          fifo->fifo_block);
153         if (ret)
154                 return ret;
155 
156         ret = clk_prepare_enable(fifo->pclk);
157         if (ret)
158                 return ret;
159 
160         ret = request_irq(fifo->irq, aiu_fifo_isr, 0, dev_name(dai->dev),
161                           substream);
162         if (ret)
163                 clk_disable_unprepare(fifo->pclk);
164 
165         return ret;
166 }
167 
168 void aiu_fifo_shutdown(struct snd_pcm_substream *substream,
169                        struct snd_soc_dai *dai)
170 {
171         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
172 
173         free_irq(fifo->irq, substream);
174         clk_disable_unprepare(fifo->pclk);
175 }
176 
177 int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd,
178                      struct snd_soc_dai *dai)
179 {
180         struct snd_card *card = rtd->card->snd_card;
181         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
182         size_t size = fifo->pcm->buffer_bytes_max;
183         int ret;
184 
185         ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
186         if (ret)
187                 return ret;
188 
189         snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
190                                        card->dev, size, size);
191 
192         return 0;
193 }
194 
195 int aiu_fifo_dai_probe(struct snd_soc_dai *dai)
196 {
197         struct aiu_fifo *fifo;
198 
199         fifo = kzalloc(sizeof(*fifo), GFP_KERNEL);
200         if (!fifo)
201                 return -ENOMEM;
202 
203         snd_soc_dai_dma_data_set_playback(dai, fifo);
204 
205         return 0;
206 }
207 
208 int aiu_fifo_dai_remove(struct snd_soc_dai *dai)
209 {
210         struct aiu_fifo *fifo = snd_soc_dai_dma_data_get_playback(dai);
211 
212         kfree(fifo);
213 
214         return 0;
215 }
216 

~ [ 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