16dc4fa17SJerome Brunet // SPDX-License-Identifier: (GPL-2.0 OR MIT)
26dc4fa17SJerome Brunet //
36dc4fa17SJerome Brunet // Copyright (c) 2018 BayLibre, SAS.
46dc4fa17SJerome Brunet // Author: Jerome Brunet <jbrunet@baylibre.com>
56dc4fa17SJerome Brunet
69e6f3953SJerome Brunet #include <linux/bitfield.h>
76dc4fa17SJerome Brunet #include <linux/clk.h>
86dc4fa17SJerome Brunet #include <linux/of_irq.h>
96dc4fa17SJerome Brunet #include <linux/of_platform.h>
106dc4fa17SJerome Brunet #include <linux/module.h>
116dc4fa17SJerome Brunet #include <linux/regmap.h>
126dc4fa17SJerome Brunet #include <linux/reset.h>
136dc4fa17SJerome Brunet #include <sound/pcm_params.h>
146dc4fa17SJerome Brunet #include <sound/soc.h>
156dc4fa17SJerome Brunet #include <sound/soc-dai.h>
166dc4fa17SJerome Brunet
176dc4fa17SJerome Brunet #include "axg-fifo.h"
186dc4fa17SJerome Brunet
196dc4fa17SJerome Brunet /*
206dc4fa17SJerome Brunet * This file implements the platform operations common to the playback and
216dc4fa17SJerome Brunet * capture frontend DAI. The logic behind this two types of fifo is very
226dc4fa17SJerome Brunet * similar but some difference exist.
237c02509aSJerome Brunet * These differences are handled in the respective DAI drivers
246dc4fa17SJerome Brunet */
256dc4fa17SJerome Brunet
267b5ce9f0SKrzysztof Kozlowski static const struct snd_pcm_hardware axg_fifo_hw = {
276dc4fa17SJerome Brunet .info = (SNDRV_PCM_INFO_INTERLEAVED |
286dc4fa17SJerome Brunet SNDRV_PCM_INFO_MMAP |
296dc4fa17SJerome Brunet SNDRV_PCM_INFO_MMAP_VALID |
306dc4fa17SJerome Brunet SNDRV_PCM_INFO_BLOCK_TRANSFER |
319be701ecSJerome Brunet SNDRV_PCM_INFO_PAUSE |
329be701ecSJerome Brunet SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
336dc4fa17SJerome Brunet .formats = AXG_FIFO_FORMATS,
346dc4fa17SJerome Brunet .rate_min = 5512,
35730674b2SJerome Brunet .rate_max = 768000,
366dc4fa17SJerome Brunet .channels_min = 1,
376dc4fa17SJerome Brunet .channels_max = AXG_FIFO_CH_MAX,
3842b5ac83SJerome Brunet .period_bytes_min = AXG_FIFO_BURST,
396dc4fa17SJerome Brunet .period_bytes_max = UINT_MAX,
406dc4fa17SJerome Brunet .periods_min = 2,
416dc4fa17SJerome Brunet .periods_max = UINT_MAX,
426dc4fa17SJerome Brunet
436dc4fa17SJerome Brunet /* No real justification for this */
446dc4fa17SJerome Brunet .buffer_bytes_max = 1 * 1024 * 1024,
456dc4fa17SJerome Brunet };
466dc4fa17SJerome Brunet
axg_fifo_dai(struct snd_pcm_substream * ss)476dc4fa17SJerome Brunet static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss)
486dc4fa17SJerome Brunet {
4922f5680aSKrzysztof Kozlowski struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(ss);
506dc4fa17SJerome Brunet
510d102e68SKuninori Morimoto return snd_soc_rtd_to_cpu(rtd, 0);
526dc4fa17SJerome Brunet }
536dc4fa17SJerome Brunet
axg_fifo_data(struct snd_pcm_substream * ss)546dc4fa17SJerome Brunet static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss)
556dc4fa17SJerome Brunet {
566dc4fa17SJerome Brunet struct snd_soc_dai *dai = axg_fifo_dai(ss);
576dc4fa17SJerome Brunet
586dc4fa17SJerome Brunet return snd_soc_dai_get_drvdata(dai);
596dc4fa17SJerome Brunet }
606dc4fa17SJerome Brunet
axg_fifo_dev(struct snd_pcm_substream * ss)616dc4fa17SJerome Brunet static struct device *axg_fifo_dev(struct snd_pcm_substream *ss)
626dc4fa17SJerome Brunet {
636dc4fa17SJerome Brunet struct snd_soc_dai *dai = axg_fifo_dai(ss);
646dc4fa17SJerome Brunet
656dc4fa17SJerome Brunet return dai->dev;
666dc4fa17SJerome Brunet }
676dc4fa17SJerome Brunet
__dma_enable(struct axg_fifo * fifo,bool enable)686dc4fa17SJerome Brunet static void __dma_enable(struct axg_fifo *fifo, bool enable)
696dc4fa17SJerome Brunet {
706dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_DMA_EN,
716dc4fa17SJerome Brunet enable ? CTRL0_DMA_EN : 0);
726dc4fa17SJerome Brunet }
736dc4fa17SJerome Brunet
axg_fifo_pcm_trigger(struct snd_soc_component * component,struct snd_pcm_substream * ss,int cmd)74bb4ba744SKuninori Morimoto int axg_fifo_pcm_trigger(struct snd_soc_component *component,
75bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss, int cmd)
766dc4fa17SJerome Brunet {
776dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
786dc4fa17SJerome Brunet
796dc4fa17SJerome Brunet switch (cmd) {
806dc4fa17SJerome Brunet case SNDRV_PCM_TRIGGER_START:
816dc4fa17SJerome Brunet case SNDRV_PCM_TRIGGER_RESUME:
826dc4fa17SJerome Brunet case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
836dc4fa17SJerome Brunet __dma_enable(fifo, true);
846dc4fa17SJerome Brunet break;
856dc4fa17SJerome Brunet case SNDRV_PCM_TRIGGER_SUSPEND:
866dc4fa17SJerome Brunet case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
876dc4fa17SJerome Brunet case SNDRV_PCM_TRIGGER_STOP:
886dc4fa17SJerome Brunet __dma_enable(fifo, false);
896dc4fa17SJerome Brunet break;
906dc4fa17SJerome Brunet default:
916dc4fa17SJerome Brunet return -EINVAL;
926dc4fa17SJerome Brunet }
936dc4fa17SJerome Brunet
946dc4fa17SJerome Brunet return 0;
956dc4fa17SJerome Brunet }
96bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger);
976dc4fa17SJerome Brunet
axg_fifo_pcm_pointer(struct snd_soc_component * component,struct snd_pcm_substream * ss)98bb4ba744SKuninori Morimoto snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component,
99bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss)
1006dc4fa17SJerome Brunet {
1016dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
1026dc4fa17SJerome Brunet struct snd_pcm_runtime *runtime = ss->runtime;
1036dc4fa17SJerome Brunet unsigned int addr;
1046dc4fa17SJerome Brunet
1056dc4fa17SJerome Brunet regmap_read(fifo->map, FIFO_STATUS2, &addr);
1066dc4fa17SJerome Brunet
1076dc4fa17SJerome Brunet return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
1086dc4fa17SJerome Brunet }
109bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer);
1106dc4fa17SJerome Brunet
axg_fifo_pcm_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * ss,struct snd_pcm_hw_params * params)111bb4ba744SKuninori Morimoto int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
112bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss,
1136dc4fa17SJerome Brunet struct snd_pcm_hw_params *params)
1146dc4fa17SJerome Brunet {
1156dc4fa17SJerome Brunet struct snd_pcm_runtime *runtime = ss->runtime;
1166dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
1179be701ecSJerome Brunet unsigned int burst_num, period, threshold, irq_en;
1186dc4fa17SJerome Brunet dma_addr_t end_ptr;
119864cee90SJerome Brunet
120864cee90SJerome Brunet period = params_period_bytes(params);
1216dc4fa17SJerome Brunet
1226dc4fa17SJerome Brunet /* Setup dma memory pointers */
1236dc4fa17SJerome Brunet end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
1246dc4fa17SJerome Brunet regmap_write(fifo->map, FIFO_START_ADDR, runtime->dma_addr);
1256dc4fa17SJerome Brunet regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
1266dc4fa17SJerome Brunet
1276dc4fa17SJerome Brunet /* Setup interrupt periodicity */
128864cee90SJerome Brunet burst_num = period / AXG_FIFO_BURST;
1296dc4fa17SJerome Brunet regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
1306dc4fa17SJerome Brunet
131864cee90SJerome Brunet /*
132864cee90SJerome Brunet * Start the fifo request on the smallest of the following:
133864cee90SJerome Brunet * - Half the fifo size
134864cee90SJerome Brunet * - Half the period size
135864cee90SJerome Brunet */
13623b89e1dSJerome Brunet threshold = min(period / 2, fifo->depth / 2);
137864cee90SJerome Brunet
138864cee90SJerome Brunet /*
139864cee90SJerome Brunet * With the threshold in bytes, register value is:
140864cee90SJerome Brunet * V = (threshold / burst) - 1
141864cee90SJerome Brunet */
142864cee90SJerome Brunet threshold /= AXG_FIFO_BURST;
143864cee90SJerome Brunet regmap_field_write(fifo->field_threshold,
144864cee90SJerome Brunet threshold ? threshold - 1 : 0);
145864cee90SJerome Brunet
1469be701ecSJerome Brunet /* Enable irq if necessary */
1479be701ecSJerome Brunet irq_en = runtime->no_period_wakeup ? 0 : FIFO_INT_COUNT_REPEAT;
1486dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL0,
1499e6f3953SJerome Brunet CTRL0_INT_EN,
1509e6f3953SJerome Brunet FIELD_PREP(CTRL0_INT_EN, irq_en));
1516dc4fa17SJerome Brunet
1526dc4fa17SJerome Brunet return 0;
1536dc4fa17SJerome Brunet }
154bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params);
1556dc4fa17SJerome Brunet
g12a_fifo_pcm_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * ss,struct snd_pcm_hw_params * params)156bb4ba744SKuninori Morimoto int g12a_fifo_pcm_hw_params(struct snd_soc_component *component,
157bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss,
1587c02509aSJerome Brunet struct snd_pcm_hw_params *params)
1597c02509aSJerome Brunet {
1607c02509aSJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
1617c02509aSJerome Brunet struct snd_pcm_runtime *runtime = ss->runtime;
1627c02509aSJerome Brunet int ret;
1637c02509aSJerome Brunet
164bb4ba744SKuninori Morimoto ret = axg_fifo_pcm_hw_params(component, ss, params);
1657c02509aSJerome Brunet if (ret)
1667c02509aSJerome Brunet return ret;
1677c02509aSJerome Brunet
1687c02509aSJerome Brunet /* Set the initial memory address of the DMA */
1697c02509aSJerome Brunet regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr);
1707c02509aSJerome Brunet
1717c02509aSJerome Brunet return 0;
1727c02509aSJerome Brunet }
173bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params);
1747c02509aSJerome Brunet
axg_fifo_pcm_hw_free(struct snd_soc_component * component,struct snd_pcm_substream * ss)175bb4ba744SKuninori Morimoto int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
176bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss)
1776dc4fa17SJerome Brunet {
1786dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
1796dc4fa17SJerome Brunet
1809e6f3953SJerome Brunet /* Disable irqs */
1816dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL0,
1829e6f3953SJerome Brunet CTRL0_INT_EN, 0);
1836dc4fa17SJerome Brunet
184bace3caaSTakashi Iwai return 0;
1856dc4fa17SJerome Brunet }
186bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
1876dc4fa17SJerome Brunet
axg_fifo_ack_irq(struct axg_fifo * fifo,u8 mask)1886dc4fa17SJerome Brunet static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
1896dc4fa17SJerome Brunet {
1906dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL1,
1919e6f3953SJerome Brunet CTRL1_INT_CLR,
1929e6f3953SJerome Brunet FIELD_PREP(CTRL1_INT_CLR, mask));
1936dc4fa17SJerome Brunet
1946dc4fa17SJerome Brunet /* Clear must also be cleared */
1956dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL1,
1969e6f3953SJerome Brunet CTRL1_INT_CLR,
1979e6f3953SJerome Brunet FIELD_PREP(CTRL1_INT_CLR, 0));
1986dc4fa17SJerome Brunet }
1996dc4fa17SJerome Brunet
axg_fifo_pcm_irq_block(int irq,void * dev_id)2006dc4fa17SJerome Brunet static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
2016dc4fa17SJerome Brunet {
2026dc4fa17SJerome Brunet struct snd_pcm_substream *ss = dev_id;
2036dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
2046dc4fa17SJerome Brunet unsigned int status;
2056dc4fa17SJerome Brunet
2066dc4fa17SJerome Brunet regmap_read(fifo->map, FIFO_STATUS1, &status);
2079e6f3953SJerome Brunet status = FIELD_GET(STATUS1_INT_STS, status);
208b11d2666SJerome Brunet axg_fifo_ack_irq(fifo, status);
209b11d2666SJerome Brunet
210*5003d0ceSJerome Brunet if (status & ~FIFO_INT_COUNT_REPEAT)
2116dc4fa17SJerome Brunet dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
2126dc4fa17SJerome Brunet status);
2136dc4fa17SJerome Brunet
214*5003d0ceSJerome Brunet if (status & FIFO_INT_COUNT_REPEAT) {
215*5003d0ceSJerome Brunet snd_pcm_period_elapsed(ss);
216*5003d0ceSJerome Brunet return IRQ_HANDLED;
217b11d2666SJerome Brunet }
2186dc4fa17SJerome Brunet
219*5003d0ceSJerome Brunet return IRQ_NONE;
2206dc4fa17SJerome Brunet }
2216dc4fa17SJerome Brunet
axg_fifo_pcm_open(struct snd_soc_component * component,struct snd_pcm_substream * ss)222bb4ba744SKuninori Morimoto int axg_fifo_pcm_open(struct snd_soc_component *component,
223bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss)
2246dc4fa17SJerome Brunet {
2256dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
2266dc4fa17SJerome Brunet struct device *dev = axg_fifo_dev(ss);
2276dc4fa17SJerome Brunet int ret;
2286dc4fa17SJerome Brunet
2296dc4fa17SJerome Brunet snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw);
2306dc4fa17SJerome Brunet
2316dc4fa17SJerome Brunet /*
2326dc4fa17SJerome Brunet * Make sure the buffer and period size are multiple of the FIFO
23342b5ac83SJerome Brunet * burst
2346dc4fa17SJerome Brunet */
2356dc4fa17SJerome Brunet ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
2366dc4fa17SJerome Brunet SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
23742b5ac83SJerome Brunet AXG_FIFO_BURST);
2386dc4fa17SJerome Brunet if (ret)
2396dc4fa17SJerome Brunet return ret;
2406dc4fa17SJerome Brunet
2416dc4fa17SJerome Brunet ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
2426dc4fa17SJerome Brunet SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
24342b5ac83SJerome Brunet AXG_FIFO_BURST);
2446dc4fa17SJerome Brunet if (ret)
2456dc4fa17SJerome Brunet return ret;
2466dc4fa17SJerome Brunet
247*5003d0ceSJerome Brunet /* Use the threaded irq handler only with non-atomic links */
248*5003d0ceSJerome Brunet ret = request_threaded_irq(fifo->irq, NULL,
249*5003d0ceSJerome Brunet axg_fifo_pcm_irq_block,
250b11d2666SJerome Brunet IRQF_ONESHOT, dev_name(dev), ss);
251dadfab72SJerome Brunet if (ret)
252dadfab72SJerome Brunet return ret;
2536dc4fa17SJerome Brunet
2546dc4fa17SJerome Brunet /* Enable pclk to access registers and clock the fifo ip */
2556dc4fa17SJerome Brunet ret = clk_prepare_enable(fifo->pclk);
2566dc4fa17SJerome Brunet if (ret)
2573b8a299aSPavel Machek (CIP) goto free_irq;
2586dc4fa17SJerome Brunet
2596dc4fa17SJerome Brunet /* Setup status2 so it reports the memory pointer */
2606dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL1,
2619e6f3953SJerome Brunet CTRL1_STATUS2_SEL,
2629e6f3953SJerome Brunet FIELD_PREP(CTRL1_STATUS2_SEL, STATUS2_SEL_DDR_READ));
2636dc4fa17SJerome Brunet
2646dc4fa17SJerome Brunet /* Make sure the dma is initially disabled */
2656dc4fa17SJerome Brunet __dma_enable(fifo, false);
2666dc4fa17SJerome Brunet
2676dc4fa17SJerome Brunet /* Disable irqs until params are ready */
2686dc4fa17SJerome Brunet regmap_update_bits(fifo->map, FIFO_CTRL0,
2699e6f3953SJerome Brunet CTRL0_INT_EN, 0);
2706dc4fa17SJerome Brunet
2716dc4fa17SJerome Brunet /* Clear any pending interrupt */
2726dc4fa17SJerome Brunet axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
2736dc4fa17SJerome Brunet
2746dc4fa17SJerome Brunet /* Take memory arbitror out of reset */
2756dc4fa17SJerome Brunet ret = reset_control_deassert(fifo->arb);
2766dc4fa17SJerome Brunet if (ret)
2773b8a299aSPavel Machek (CIP) goto free_clk;
2786dc4fa17SJerome Brunet
2793b8a299aSPavel Machek (CIP) return 0;
2803b8a299aSPavel Machek (CIP)
2813b8a299aSPavel Machek (CIP) free_clk:
2823b8a299aSPavel Machek (CIP) clk_disable_unprepare(fifo->pclk);
2833b8a299aSPavel Machek (CIP) free_irq:
2843b8a299aSPavel Machek (CIP) free_irq(fifo->irq, ss);
2856dc4fa17SJerome Brunet return ret;
2866dc4fa17SJerome Brunet }
287bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_open);
2886dc4fa17SJerome Brunet
axg_fifo_pcm_close(struct snd_soc_component * component,struct snd_pcm_substream * ss)289bb4ba744SKuninori Morimoto int axg_fifo_pcm_close(struct snd_soc_component *component,
290bb4ba744SKuninori Morimoto struct snd_pcm_substream *ss)
2916dc4fa17SJerome Brunet {
2926dc4fa17SJerome Brunet struct axg_fifo *fifo = axg_fifo_data(ss);
2936dc4fa17SJerome Brunet int ret;
2946dc4fa17SJerome Brunet
2956dc4fa17SJerome Brunet /* Put the memory arbitror back in reset */
2966dc4fa17SJerome Brunet ret = reset_control_assert(fifo->arb);
2976dc4fa17SJerome Brunet
2986dc4fa17SJerome Brunet /* Disable fifo ip and register access */
2996dc4fa17SJerome Brunet clk_disable_unprepare(fifo->pclk);
3006dc4fa17SJerome Brunet
3016dc4fa17SJerome Brunet /* remove IRQ */
3026dc4fa17SJerome Brunet free_irq(fifo->irq, ss);
3036dc4fa17SJerome Brunet
3046dc4fa17SJerome Brunet return ret;
3056dc4fa17SJerome Brunet }
306bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_close);
3077c02509aSJerome Brunet
axg_fifo_pcm_new(struct snd_soc_pcm_runtime * rtd,unsigned int type)3086dc4fa17SJerome Brunet int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
3096dc4fa17SJerome Brunet {
3106dc4fa17SJerome Brunet struct snd_card *card = rtd->card->snd_card;
3116dc4fa17SJerome Brunet size_t size = axg_fifo_hw.buffer_bytes_max;
3126dc4fa17SJerome Brunet
313bace3caaSTakashi Iwai snd_pcm_set_managed_buffer(rtd->pcm->streams[type].substream,
3146dc4fa17SJerome Brunet SNDRV_DMA_TYPE_DEV, card->dev,
3156dc4fa17SJerome Brunet size, size);
316fba3b09fSTakashi Iwai return 0;
3176dc4fa17SJerome Brunet }
3186dc4fa17SJerome Brunet EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
3196dc4fa17SJerome Brunet
3206dc4fa17SJerome Brunet static const struct regmap_config axg_fifo_regmap_cfg = {
3216dc4fa17SJerome Brunet .reg_bits = 32,
3226dc4fa17SJerome Brunet .val_bits = 32,
3236dc4fa17SJerome Brunet .reg_stride = 4,
32452dd80d8SJerome Brunet .max_register = FIFO_CTRL2,
3256dc4fa17SJerome Brunet };
3266dc4fa17SJerome Brunet
axg_fifo_probe(struct platform_device * pdev)3276dc4fa17SJerome Brunet int axg_fifo_probe(struct platform_device *pdev)
3286dc4fa17SJerome Brunet {
3296dc4fa17SJerome Brunet struct device *dev = &pdev->dev;
3306dc4fa17SJerome Brunet const struct axg_fifo_match_data *data;
3316dc4fa17SJerome Brunet struct axg_fifo *fifo;
3326dc4fa17SJerome Brunet void __iomem *regs;
33323b89e1dSJerome Brunet int ret;
3346dc4fa17SJerome Brunet
3356dc4fa17SJerome Brunet data = of_device_get_match_data(dev);
3366dc4fa17SJerome Brunet if (!data) {
3376dc4fa17SJerome Brunet dev_err(dev, "failed to match device\n");
3386dc4fa17SJerome Brunet return -ENODEV;
3396dc4fa17SJerome Brunet }
3406dc4fa17SJerome Brunet
3416dc4fa17SJerome Brunet fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
3426dc4fa17SJerome Brunet if (!fifo)
3436dc4fa17SJerome Brunet return -ENOMEM;
3446dc4fa17SJerome Brunet platform_set_drvdata(pdev, fifo);
3456dc4fa17SJerome Brunet
3469b208931SYueHaibing regs = devm_platform_ioremap_resource(pdev, 0);
3476dc4fa17SJerome Brunet if (IS_ERR(regs))
3486dc4fa17SJerome Brunet return PTR_ERR(regs);
3496dc4fa17SJerome Brunet
3506dc4fa17SJerome Brunet fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg);
3516dc4fa17SJerome Brunet if (IS_ERR(fifo->map)) {
3526dc4fa17SJerome Brunet dev_err(dev, "failed to init regmap: %ld\n",
3536dc4fa17SJerome Brunet PTR_ERR(fifo->map));
3546dc4fa17SJerome Brunet return PTR_ERR(fifo->map);
3556dc4fa17SJerome Brunet }
3566dc4fa17SJerome Brunet
3576dc4fa17SJerome Brunet fifo->pclk = devm_clk_get(dev, NULL);
3582ff4e003SKuninori Morimoto if (IS_ERR(fifo->pclk))
3592ff4e003SKuninori Morimoto return dev_err_probe(dev, PTR_ERR(fifo->pclk), "failed to get pclk\n");
3606dc4fa17SJerome Brunet
3616dc4fa17SJerome Brunet fifo->arb = devm_reset_control_get_exclusive(dev, NULL);
3622ff4e003SKuninori Morimoto if (IS_ERR(fifo->arb))
3632ff4e003SKuninori Morimoto return dev_err_probe(dev, PTR_ERR(fifo->arb), "failed to get arb reset\n");
3646dc4fa17SJerome Brunet
3656dc4fa17SJerome Brunet fifo->irq = of_irq_get(dev->of_node, 0);
3666dc4fa17SJerome Brunet if (fifo->irq <= 0) {
3676dc4fa17SJerome Brunet dev_err(dev, "failed to get irq: %d\n", fifo->irq);
3686dc4fa17SJerome Brunet return fifo->irq;
3696dc4fa17SJerome Brunet }
3706dc4fa17SJerome Brunet
371864cee90SJerome Brunet fifo->field_threshold =
372864cee90SJerome Brunet devm_regmap_field_alloc(dev, fifo->map, data->field_threshold);
373864cee90SJerome Brunet if (IS_ERR(fifo->field_threshold))
374864cee90SJerome Brunet return PTR_ERR(fifo->field_threshold);
375864cee90SJerome Brunet
37623b89e1dSJerome Brunet ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth",
37723b89e1dSJerome Brunet &fifo->depth);
37823b89e1dSJerome Brunet if (ret) {
37923b89e1dSJerome Brunet /* Error out for anything but a missing property */
38023b89e1dSJerome Brunet if (ret != -EINVAL)
38123b89e1dSJerome Brunet return ret;
38223b89e1dSJerome Brunet /*
38323b89e1dSJerome Brunet * If the property is missing, it might be because of an old
38423b89e1dSJerome Brunet * DT. In such case, assume the smallest known fifo depth
38523b89e1dSJerome Brunet */
38623b89e1dSJerome Brunet fifo->depth = 256;
38723b89e1dSJerome Brunet dev_warn(dev, "fifo depth not found, assume %u bytes\n",
38823b89e1dSJerome Brunet fifo->depth);
38923b89e1dSJerome Brunet }
39023b89e1dSJerome Brunet
3916dc4fa17SJerome Brunet return devm_snd_soc_register_component(dev, data->component_drv,
3926dc4fa17SJerome Brunet data->dai_drv, 1);
3936dc4fa17SJerome Brunet }
3946dc4fa17SJerome Brunet EXPORT_SYMBOL_GPL(axg_fifo_probe);
3956dc4fa17SJerome Brunet
3967c02509aSJerome Brunet MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver");
3976dc4fa17SJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
3986dc4fa17SJerome Brunet MODULE_LICENSE("GPL v2");
399