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

TOMOYO Linux Cross Reference
Linux/sound/soc/meson/axg-fifo.c

Version: ~ [ linux-5.19-rc8 ] ~ [ linux-5.18.14 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.57 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.133 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.207 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.253 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.289 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.324 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ 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 OR MIT)
  2 //
  3 // Copyright (c) 2018 BayLibre, SAS.
  4 // Author: Jerome Brunet <jbrunet@baylibre.com>
  5 
  6 #include <linux/clk.h>
  7 #include <linux/of_irq.h>
  8 #include <linux/of_platform.h>
  9 #include <linux/module.h>
 10 #include <linux/regmap.h>
 11 #include <linux/reset.h>
 12 #include <sound/pcm_params.h>
 13 #include <sound/soc.h>
 14 #include <sound/soc-dai.h>
 15 
 16 #include "axg-fifo.h"
 17 
 18 /*
 19  * This file implements the platform operations common to the playback and
 20  * capture frontend DAI. The logic behind this two types of fifo is very
 21  * similar but some difference exist.
 22  * These differences are handled in the respective DAI drivers
 23  */
 24 
 25 static struct snd_pcm_hardware axg_fifo_hw = {
 26         .info = (SNDRV_PCM_INFO_INTERLEAVED |
 27                  SNDRV_PCM_INFO_MMAP |
 28                  SNDRV_PCM_INFO_MMAP_VALID |
 29                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
 30                  SNDRV_PCM_INFO_PAUSE),
 31 
 32         .formats = AXG_FIFO_FORMATS,
 33         .rate_min = 5512,
 34         .rate_max = 192000,
 35         .channels_min = 1,
 36         .channels_max = AXG_FIFO_CH_MAX,
 37         .period_bytes_min = AXG_FIFO_MIN_DEPTH,
 38         .period_bytes_max = UINT_MAX,
 39         .periods_min = 2,
 40         .periods_max = UINT_MAX,
 41 
 42         /* No real justification for this */
 43         .buffer_bytes_max = 1 * 1024 * 1024,
 44 };
 45 
 46 static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss)
 47 {
 48         struct snd_soc_pcm_runtime *rtd = ss->private_data;
 49 
 50         return rtd->cpu_dai;
 51 }
 52 
 53 static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss)
 54 {
 55         struct snd_soc_dai *dai = axg_fifo_dai(ss);
 56 
 57         return snd_soc_dai_get_drvdata(dai);
 58 }
 59 
 60 static struct device *axg_fifo_dev(struct snd_pcm_substream *ss)
 61 {
 62         struct snd_soc_dai *dai = axg_fifo_dai(ss);
 63 
 64         return dai->dev;
 65 }
 66 
 67 static void __dma_enable(struct axg_fifo *fifo,  bool enable)
 68 {
 69         regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_DMA_EN,
 70                            enable ? CTRL0_DMA_EN : 0);
 71 }
 72 
 73 int axg_fifo_pcm_trigger(struct snd_soc_component *component,
 74                          struct snd_pcm_substream *ss, int cmd)
 75 {
 76         struct axg_fifo *fifo = axg_fifo_data(ss);
 77 
 78         switch (cmd) {
 79         case SNDRV_PCM_TRIGGER_START:
 80         case SNDRV_PCM_TRIGGER_RESUME:
 81         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 82                 __dma_enable(fifo, true);
 83                 break;
 84         case SNDRV_PCM_TRIGGER_SUSPEND:
 85         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 86         case SNDRV_PCM_TRIGGER_STOP:
 87                 __dma_enable(fifo, false);
 88                 break;
 89         default:
 90                 return -EINVAL;
 91         }
 92 
 93         return 0;
 94 }
 95 EXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger);
 96 
 97 snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component,
 98                                        struct snd_pcm_substream *ss)
 99 {
100         struct axg_fifo *fifo = axg_fifo_data(ss);
101         struct snd_pcm_runtime *runtime = ss->runtime;
102         unsigned int addr;
103 
104         regmap_read(fifo->map, FIFO_STATUS2, &addr);
105 
106         return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
107 }
108 EXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer);
109 
110 int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
111                            struct snd_pcm_substream *ss,
112                            struct snd_pcm_hw_params *params)
113 {
114         struct snd_pcm_runtime *runtime = ss->runtime;
115         struct axg_fifo *fifo = axg_fifo_data(ss);
116         unsigned int burst_num, period, threshold;
117         dma_addr_t end_ptr;
118         int ret;
119 
120         period = params_period_bytes(params);
121 
122         ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(params));
123         if (ret < 0)
124                 return ret;
125 
126         /* Setup dma memory pointers */
127         end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
128         regmap_write(fifo->map, FIFO_START_ADDR, runtime->dma_addr);
129         regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
130 
131         /* Setup interrupt periodicity */
132         burst_num = period / AXG_FIFO_BURST;
133         regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
134 
135         /*
136          * Start the fifo request on the smallest of the following:
137          * - Half the fifo size
138          * - Half the period size
139          */
140         threshold = min(period / 2,
141                         (unsigned int)AXG_FIFO_MIN_DEPTH / 2);
142 
143         /*
144          * With the threshold in bytes, register value is:
145          * V = (threshold / burst) - 1
146          */
147         threshold /= AXG_FIFO_BURST;
148         regmap_field_write(fifo->field_threshold,
149                            threshold ? threshold - 1 : 0);
150 
151         /* Enable block count irq */
152         regmap_update_bits(fifo->map, FIFO_CTRL0,
153                            CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
154                            CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT));
155 
156         return 0;
157 }
158 EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params);
159 
160 int g12a_fifo_pcm_hw_params(struct snd_soc_component *component,
161                             struct snd_pcm_substream *ss,
162                             struct snd_pcm_hw_params *params)
163 {
164         struct axg_fifo *fifo = axg_fifo_data(ss);
165         struct snd_pcm_runtime *runtime = ss->runtime;
166         int ret;
167 
168         ret = axg_fifo_pcm_hw_params(component, ss, params);
169         if (ret)
170                 return ret;
171 
172         /* Set the initial memory address of the DMA */
173         regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr);
174 
175         return 0;
176 }
177 EXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params);
178 
179 int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
180                          struct snd_pcm_substream *ss)
181 {
182         struct axg_fifo *fifo = axg_fifo_data(ss);
183 
184         /* Disable the block count irq */
185         regmap_update_bits(fifo->map, FIFO_CTRL0,
186                            CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
187 
188         return snd_pcm_lib_free_pages(ss);
189 }
190 EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
191 
192 static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
193 {
194         regmap_update_bits(fifo->map, FIFO_CTRL1,
195                            CTRL1_INT_CLR(FIFO_INT_MASK),
196                            CTRL1_INT_CLR(mask));
197 
198         /* Clear must also be cleared */
199         regmap_update_bits(fifo->map, FIFO_CTRL1,
200                            CTRL1_INT_CLR(FIFO_INT_MASK),
201                            0);
202 }
203 
204 static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
205 {
206         struct snd_pcm_substream *ss = dev_id;
207         struct axg_fifo *fifo = axg_fifo_data(ss);
208         unsigned int status;
209 
210         regmap_read(fifo->map, FIFO_STATUS1, &status);
211 
212         status = STATUS1_INT_STS(status) & FIFO_INT_MASK;
213         if (status & FIFO_INT_COUNT_REPEAT)
214                 snd_pcm_period_elapsed(ss);
215         else
216                 dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
217                         status);
218 
219         /* Ack irqs */
220         axg_fifo_ack_irq(fifo, status);
221 
222         return IRQ_RETVAL(status);
223 }
224 
225 int axg_fifo_pcm_open(struct snd_soc_component *component,
226                       struct snd_pcm_substream *ss)
227 {
228         struct axg_fifo *fifo = axg_fifo_data(ss);
229         struct device *dev = axg_fifo_dev(ss);
230         int ret;
231 
232         snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw);
233 
234         /*
235          * Make sure the buffer and period size are multiple of the FIFO
236          * minimum depth size
237          */
238         ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
239                                          SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
240                                          AXG_FIFO_MIN_DEPTH);
241         if (ret)
242                 return ret;
243 
244         ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
245                                          SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
246                                          AXG_FIFO_MIN_DEPTH);
247         if (ret)
248                 return ret;
249 
250         ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
251                           dev_name(dev), ss);
252         if (ret)
253                 return ret;
254 
255         /* Enable pclk to access registers and clock the fifo ip */
256         ret = clk_prepare_enable(fifo->pclk);
257         if (ret)
258                 return ret;
259 
260         /* Setup status2 so it reports the memory pointer */
261         regmap_update_bits(fifo->map, FIFO_CTRL1,
262                            CTRL1_STATUS2_SEL_MASK,
263                            CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ));
264 
265         /* Make sure the dma is initially disabled */
266         __dma_enable(fifo, false);
267 
268         /* Disable irqs until params are ready */
269         regmap_update_bits(fifo->map, FIFO_CTRL0,
270                            CTRL0_INT_EN(FIFO_INT_MASK), 0);
271 
272         /* Clear any pending interrupt */
273         axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
274 
275         /* Take memory arbitror out of reset */
276         ret = reset_control_deassert(fifo->arb);
277         if (ret)
278                 clk_disable_unprepare(fifo->pclk);
279 
280         return ret;
281 }
282 EXPORT_SYMBOL_GPL(axg_fifo_pcm_open);
283 
284 int axg_fifo_pcm_close(struct snd_soc_component *component,
285                        struct snd_pcm_substream *ss)
286 {
287         struct axg_fifo *fifo = axg_fifo_data(ss);
288         int ret;
289 
290         /* Put the memory arbitror back in reset */
291         ret = reset_control_assert(fifo->arb);
292 
293         /* Disable fifo ip and register access */
294         clk_disable_unprepare(fifo->pclk);
295 
296         /* remove IRQ */
297         free_irq(fifo->irq, ss);
298 
299         return ret;
300 }
301 EXPORT_SYMBOL_GPL(axg_fifo_pcm_close);
302 
303 int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
304 {
305         struct snd_card *card = rtd->card->snd_card;
306         size_t size = axg_fifo_hw.buffer_bytes_max;
307 
308         snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream,
309                                       SNDRV_DMA_TYPE_DEV, card->dev,
310                                       size, size);
311         return 0;
312 }
313 EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
314 
315 static const struct regmap_config axg_fifo_regmap_cfg = {
316         .reg_bits       = 32,
317         .val_bits       = 32,
318         .reg_stride     = 4,
319         .max_register   = FIFO_CTRL2,
320 };
321 
322 int axg_fifo_probe(struct platform_device *pdev)
323 {
324         struct device *dev = &pdev->dev;
325         const struct axg_fifo_match_data *data;
326         struct axg_fifo *fifo;
327         void __iomem *regs;
328 
329         data = of_device_get_match_data(dev);
330         if (!data) {
331                 dev_err(dev, "failed to match device\n");
332                 return -ENODEV;
333         }
334 
335         fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
336         if (!fifo)
337                 return -ENOMEM;
338         platform_set_drvdata(pdev, fifo);
339 
340         regs = devm_platform_ioremap_resource(pdev, 0);
341         if (IS_ERR(regs))
342                 return PTR_ERR(regs);
343 
344         fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg);
345         if (IS_ERR(fifo->map)) {
346                 dev_err(dev, "failed to init regmap: %ld\n",
347                         PTR_ERR(fifo->map));
348                 return PTR_ERR(fifo->map);
349         }
350 
351         fifo->pclk = devm_clk_get(dev, NULL);
352         if (IS_ERR(fifo->pclk)) {
353                 if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER)
354                         dev_err(dev, "failed to get pclk: %ld\n",
355                                 PTR_ERR(fifo->pclk));
356                 return PTR_ERR(fifo->pclk);
357         }
358 
359         fifo->arb = devm_reset_control_get_exclusive(dev, NULL);
360         if (IS_ERR(fifo->arb)) {
361                 if (PTR_ERR(fifo->arb) != -EPROBE_DEFER)
362                         dev_err(dev, "failed to get arb reset: %ld\n",
363                                 PTR_ERR(fifo->arb));
364                 return PTR_ERR(fifo->arb);
365         }
366 
367         fifo->irq = of_irq_get(dev->of_node, 0);
368         if (fifo->irq <= 0) {
369                 dev_err(dev, "failed to get irq: %d\n", fifo->irq);
370                 return fifo->irq;
371         }
372 
373         fifo->field_threshold =
374                 devm_regmap_field_alloc(dev, fifo->map, data->field_threshold);
375         if (IS_ERR(fifo->field_threshold))
376                 return PTR_ERR(fifo->field_threshold);
377 
378         return devm_snd_soc_register_component(dev, data->component_drv,
379                                                data->dai_drv, 1);
380 }
381 EXPORT_SYMBOL_GPL(axg_fifo_probe);
382 
383 MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver");
384 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
385 MODULE_LICENSE("GPL v2");
386 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp