xref: /linux/sound/soc/meson/axg-fifo.c (revision 3b8a299a58b2afce464ae11324b59dcf0f1d10a7)
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 
66dc4fa17SJerome Brunet #include <linux/clk.h>
76dc4fa17SJerome Brunet #include <linux/of_irq.h>
86dc4fa17SJerome Brunet #include <linux/of_platform.h>
96dc4fa17SJerome Brunet #include <linux/module.h>
106dc4fa17SJerome Brunet #include <linux/regmap.h>
116dc4fa17SJerome Brunet #include <linux/reset.h>
126dc4fa17SJerome Brunet #include <sound/pcm_params.h>
136dc4fa17SJerome Brunet #include <sound/soc.h>
146dc4fa17SJerome Brunet #include <sound/soc-dai.h>
156dc4fa17SJerome Brunet 
166dc4fa17SJerome Brunet #include "axg-fifo.h"
176dc4fa17SJerome Brunet 
186dc4fa17SJerome Brunet /*
196dc4fa17SJerome Brunet  * This file implements the platform operations common to the playback and
206dc4fa17SJerome Brunet  * capture frontend DAI. The logic behind this two types of fifo is very
216dc4fa17SJerome Brunet  * similar but some difference exist.
227c02509aSJerome Brunet  * These differences are handled in the respective DAI drivers
236dc4fa17SJerome Brunet  */
246dc4fa17SJerome Brunet 
256dc4fa17SJerome Brunet static struct snd_pcm_hardware axg_fifo_hw = {
266dc4fa17SJerome Brunet 	.info = (SNDRV_PCM_INFO_INTERLEAVED |
276dc4fa17SJerome Brunet 		 SNDRV_PCM_INFO_MMAP |
286dc4fa17SJerome Brunet 		 SNDRV_PCM_INFO_MMAP_VALID |
296dc4fa17SJerome Brunet 		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
306dc4fa17SJerome Brunet 		 SNDRV_PCM_INFO_PAUSE),
316dc4fa17SJerome Brunet 
326dc4fa17SJerome Brunet 	.formats = AXG_FIFO_FORMATS,
336dc4fa17SJerome Brunet 	.rate_min = 5512,
346dc4fa17SJerome Brunet 	.rate_max = 192000,
356dc4fa17SJerome Brunet 	.channels_min = 1,
366dc4fa17SJerome Brunet 	.channels_max = AXG_FIFO_CH_MAX,
3742b5ac83SJerome Brunet 	.period_bytes_min = AXG_FIFO_BURST,
386dc4fa17SJerome Brunet 	.period_bytes_max = UINT_MAX,
396dc4fa17SJerome Brunet 	.periods_min = 2,
406dc4fa17SJerome Brunet 	.periods_max = UINT_MAX,
416dc4fa17SJerome Brunet 
426dc4fa17SJerome Brunet 	/* No real justification for this */
436dc4fa17SJerome Brunet 	.buffer_bytes_max = 1 * 1024 * 1024,
446dc4fa17SJerome Brunet };
456dc4fa17SJerome Brunet 
466dc4fa17SJerome Brunet static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss)
476dc4fa17SJerome Brunet {
486dc4fa17SJerome Brunet 	struct snd_soc_pcm_runtime *rtd = ss->private_data;
496dc4fa17SJerome Brunet 
50385a5c60SKuninori Morimoto 	return asoc_rtd_to_cpu(rtd, 0);
516dc4fa17SJerome Brunet }
526dc4fa17SJerome Brunet 
536dc4fa17SJerome Brunet static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss)
546dc4fa17SJerome Brunet {
556dc4fa17SJerome Brunet 	struct snd_soc_dai *dai = axg_fifo_dai(ss);
566dc4fa17SJerome Brunet 
576dc4fa17SJerome Brunet 	return snd_soc_dai_get_drvdata(dai);
586dc4fa17SJerome Brunet }
596dc4fa17SJerome Brunet 
606dc4fa17SJerome Brunet static struct device *axg_fifo_dev(struct snd_pcm_substream *ss)
616dc4fa17SJerome Brunet {
626dc4fa17SJerome Brunet 	struct snd_soc_dai *dai = axg_fifo_dai(ss);
636dc4fa17SJerome Brunet 
646dc4fa17SJerome Brunet 	return dai->dev;
656dc4fa17SJerome Brunet }
666dc4fa17SJerome Brunet 
676dc4fa17SJerome Brunet static void __dma_enable(struct axg_fifo *fifo,  bool enable)
686dc4fa17SJerome Brunet {
696dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_DMA_EN,
706dc4fa17SJerome Brunet 			   enable ? CTRL0_DMA_EN : 0);
716dc4fa17SJerome Brunet }
726dc4fa17SJerome Brunet 
73bb4ba744SKuninori Morimoto int axg_fifo_pcm_trigger(struct snd_soc_component *component,
74bb4ba744SKuninori Morimoto 			 struct snd_pcm_substream *ss, int cmd)
756dc4fa17SJerome Brunet {
766dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
776dc4fa17SJerome Brunet 
786dc4fa17SJerome Brunet 	switch (cmd) {
796dc4fa17SJerome Brunet 	case SNDRV_PCM_TRIGGER_START:
806dc4fa17SJerome Brunet 	case SNDRV_PCM_TRIGGER_RESUME:
816dc4fa17SJerome Brunet 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
826dc4fa17SJerome Brunet 		__dma_enable(fifo, true);
836dc4fa17SJerome Brunet 		break;
846dc4fa17SJerome Brunet 	case SNDRV_PCM_TRIGGER_SUSPEND:
856dc4fa17SJerome Brunet 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
866dc4fa17SJerome Brunet 	case SNDRV_PCM_TRIGGER_STOP:
876dc4fa17SJerome Brunet 		__dma_enable(fifo, false);
886dc4fa17SJerome Brunet 		break;
896dc4fa17SJerome Brunet 	default:
906dc4fa17SJerome Brunet 		return -EINVAL;
916dc4fa17SJerome Brunet 	}
926dc4fa17SJerome Brunet 
936dc4fa17SJerome Brunet 	return 0;
946dc4fa17SJerome Brunet }
95bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger);
966dc4fa17SJerome Brunet 
97bb4ba744SKuninori Morimoto snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component,
98bb4ba744SKuninori Morimoto 				       struct snd_pcm_substream *ss)
996dc4fa17SJerome Brunet {
1006dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
1016dc4fa17SJerome Brunet 	struct snd_pcm_runtime *runtime = ss->runtime;
1026dc4fa17SJerome Brunet 	unsigned int addr;
1036dc4fa17SJerome Brunet 
1046dc4fa17SJerome Brunet 	regmap_read(fifo->map, FIFO_STATUS2, &addr);
1056dc4fa17SJerome Brunet 
1066dc4fa17SJerome Brunet 	return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
1076dc4fa17SJerome Brunet }
108bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer);
1096dc4fa17SJerome Brunet 
110bb4ba744SKuninori Morimoto int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
111bb4ba744SKuninori Morimoto 			   struct snd_pcm_substream *ss,
1126dc4fa17SJerome Brunet 			   struct snd_pcm_hw_params *params)
1136dc4fa17SJerome Brunet {
1146dc4fa17SJerome Brunet 	struct snd_pcm_runtime *runtime = ss->runtime;
1156dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
116864cee90SJerome Brunet 	unsigned int burst_num, period, threshold;
1176dc4fa17SJerome Brunet 	dma_addr_t end_ptr;
118864cee90SJerome Brunet 
119864cee90SJerome Brunet 	period = params_period_bytes(params);
1206dc4fa17SJerome Brunet 
1216dc4fa17SJerome Brunet 	/* Setup dma memory pointers */
1226dc4fa17SJerome Brunet 	end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
1236dc4fa17SJerome Brunet 	regmap_write(fifo->map, FIFO_START_ADDR, runtime->dma_addr);
1246dc4fa17SJerome Brunet 	regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
1256dc4fa17SJerome Brunet 
1266dc4fa17SJerome Brunet 	/* Setup interrupt periodicity */
127864cee90SJerome Brunet 	burst_num = period / AXG_FIFO_BURST;
1286dc4fa17SJerome Brunet 	regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
1296dc4fa17SJerome Brunet 
130864cee90SJerome Brunet 	/*
131864cee90SJerome Brunet 	 * Start the fifo request on the smallest of the following:
132864cee90SJerome Brunet 	 * - Half the fifo size
133864cee90SJerome Brunet 	 * - Half the period size
134864cee90SJerome Brunet 	 */
13523b89e1dSJerome Brunet 	threshold = min(period / 2, fifo->depth / 2);
136864cee90SJerome Brunet 
137864cee90SJerome Brunet 	/*
138864cee90SJerome Brunet 	 * With the threshold in bytes, register value is:
139864cee90SJerome Brunet 	 * V = (threshold / burst) - 1
140864cee90SJerome Brunet 	 */
141864cee90SJerome Brunet 	threshold /= AXG_FIFO_BURST;
142864cee90SJerome Brunet 	regmap_field_write(fifo->field_threshold,
143864cee90SJerome Brunet 			   threshold ? threshold - 1 : 0);
144864cee90SJerome Brunet 
1456dc4fa17SJerome Brunet 	/* Enable block count irq */
1466dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL0,
1476dc4fa17SJerome Brunet 			   CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
1486dc4fa17SJerome Brunet 			   CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT));
1496dc4fa17SJerome Brunet 
1506dc4fa17SJerome Brunet 	return 0;
1516dc4fa17SJerome Brunet }
152bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params);
1536dc4fa17SJerome Brunet 
154bb4ba744SKuninori Morimoto int g12a_fifo_pcm_hw_params(struct snd_soc_component *component,
155bb4ba744SKuninori Morimoto 			    struct snd_pcm_substream *ss,
1567c02509aSJerome Brunet 			    struct snd_pcm_hw_params *params)
1577c02509aSJerome Brunet {
1587c02509aSJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
1597c02509aSJerome Brunet 	struct snd_pcm_runtime *runtime = ss->runtime;
1607c02509aSJerome Brunet 	int ret;
1617c02509aSJerome Brunet 
162bb4ba744SKuninori Morimoto 	ret = axg_fifo_pcm_hw_params(component, ss, params);
1637c02509aSJerome Brunet 	if (ret)
1647c02509aSJerome Brunet 		return ret;
1657c02509aSJerome Brunet 
1667c02509aSJerome Brunet 	/* Set the initial memory address of the DMA */
1677c02509aSJerome Brunet 	regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr);
1687c02509aSJerome Brunet 
1697c02509aSJerome Brunet 	return 0;
1707c02509aSJerome Brunet }
171bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params);
1727c02509aSJerome Brunet 
173bb4ba744SKuninori Morimoto int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
174bb4ba744SKuninori Morimoto 			 struct snd_pcm_substream *ss)
1756dc4fa17SJerome Brunet {
1766dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
1776dc4fa17SJerome Brunet 
1786dc4fa17SJerome Brunet 	/* Disable the block count irq */
1796dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL0,
1806dc4fa17SJerome Brunet 			   CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
1816dc4fa17SJerome Brunet 
182bace3caaSTakashi Iwai 	return 0;
1836dc4fa17SJerome Brunet }
184bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
1856dc4fa17SJerome Brunet 
1866dc4fa17SJerome Brunet static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
1876dc4fa17SJerome Brunet {
1886dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL1,
1896dc4fa17SJerome Brunet 			   CTRL1_INT_CLR(FIFO_INT_MASK),
1906dc4fa17SJerome Brunet 			   CTRL1_INT_CLR(mask));
1916dc4fa17SJerome Brunet 
1926dc4fa17SJerome Brunet 	/* Clear must also be cleared */
1936dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL1,
1946dc4fa17SJerome Brunet 			   CTRL1_INT_CLR(FIFO_INT_MASK),
1956dc4fa17SJerome Brunet 			   0);
1966dc4fa17SJerome Brunet }
1976dc4fa17SJerome Brunet 
1986dc4fa17SJerome Brunet static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
1996dc4fa17SJerome Brunet {
2006dc4fa17SJerome Brunet 	struct snd_pcm_substream *ss = dev_id;
2016dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
2026dc4fa17SJerome Brunet 	unsigned int status;
2036dc4fa17SJerome Brunet 
2046dc4fa17SJerome Brunet 	regmap_read(fifo->map, FIFO_STATUS1, &status);
2056dc4fa17SJerome Brunet 
2066dc4fa17SJerome Brunet 	status = STATUS1_INT_STS(status) & FIFO_INT_MASK;
2076dc4fa17SJerome Brunet 	if (status & FIFO_INT_COUNT_REPEAT)
2086dc4fa17SJerome Brunet 		snd_pcm_period_elapsed(ss);
2096dc4fa17SJerome Brunet 	else
2106dc4fa17SJerome Brunet 		dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
2116dc4fa17SJerome Brunet 			status);
2126dc4fa17SJerome Brunet 
2136dc4fa17SJerome Brunet 	/* Ack irqs */
2146dc4fa17SJerome Brunet 	axg_fifo_ack_irq(fifo, status);
2156dc4fa17SJerome Brunet 
216036e4963SJerome Brunet 	return IRQ_RETVAL(status);
2176dc4fa17SJerome Brunet }
2186dc4fa17SJerome Brunet 
219bb4ba744SKuninori Morimoto int axg_fifo_pcm_open(struct snd_soc_component *component,
220bb4ba744SKuninori Morimoto 		      struct snd_pcm_substream *ss)
2216dc4fa17SJerome Brunet {
2226dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
2236dc4fa17SJerome Brunet 	struct device *dev = axg_fifo_dev(ss);
2246dc4fa17SJerome Brunet 	int ret;
2256dc4fa17SJerome Brunet 
2266dc4fa17SJerome Brunet 	snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw);
2276dc4fa17SJerome Brunet 
2286dc4fa17SJerome Brunet 	/*
2296dc4fa17SJerome Brunet 	 * Make sure the buffer and period size are multiple of the FIFO
23042b5ac83SJerome Brunet 	 * burst
2316dc4fa17SJerome Brunet 	 */
2326dc4fa17SJerome Brunet 	ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
2336dc4fa17SJerome Brunet 					 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
23442b5ac83SJerome Brunet 					 AXG_FIFO_BURST);
2356dc4fa17SJerome Brunet 	if (ret)
2366dc4fa17SJerome Brunet 		return ret;
2376dc4fa17SJerome Brunet 
2386dc4fa17SJerome Brunet 	ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
2396dc4fa17SJerome Brunet 					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
24042b5ac83SJerome Brunet 					 AXG_FIFO_BURST);
2416dc4fa17SJerome Brunet 	if (ret)
2426dc4fa17SJerome Brunet 		return ret;
2436dc4fa17SJerome Brunet 
2446dc4fa17SJerome Brunet 	ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
2456dc4fa17SJerome Brunet 			  dev_name(dev), ss);
246dadfab72SJerome Brunet 	if (ret)
247dadfab72SJerome Brunet 		return ret;
2486dc4fa17SJerome Brunet 
2496dc4fa17SJerome Brunet 	/* Enable pclk to access registers and clock the fifo ip */
2506dc4fa17SJerome Brunet 	ret = clk_prepare_enable(fifo->pclk);
2516dc4fa17SJerome Brunet 	if (ret)
252*3b8a299aSPavel Machek (CIP) 		goto free_irq;
2536dc4fa17SJerome Brunet 
2546dc4fa17SJerome Brunet 	/* Setup status2 so it reports the memory pointer */
2556dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL1,
2566dc4fa17SJerome Brunet 			   CTRL1_STATUS2_SEL_MASK,
2576dc4fa17SJerome Brunet 			   CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ));
2586dc4fa17SJerome Brunet 
2596dc4fa17SJerome Brunet 	/* Make sure the dma is initially disabled */
2606dc4fa17SJerome Brunet 	__dma_enable(fifo, false);
2616dc4fa17SJerome Brunet 
2626dc4fa17SJerome Brunet 	/* Disable irqs until params are ready */
2636dc4fa17SJerome Brunet 	regmap_update_bits(fifo->map, FIFO_CTRL0,
2646dc4fa17SJerome Brunet 			   CTRL0_INT_EN(FIFO_INT_MASK), 0);
2656dc4fa17SJerome Brunet 
2666dc4fa17SJerome Brunet 	/* Clear any pending interrupt */
2676dc4fa17SJerome Brunet 	axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
2686dc4fa17SJerome Brunet 
2696dc4fa17SJerome Brunet 	/* Take memory arbitror out of reset */
2706dc4fa17SJerome Brunet 	ret = reset_control_deassert(fifo->arb);
2716dc4fa17SJerome Brunet 	if (ret)
272*3b8a299aSPavel Machek (CIP) 		goto free_clk;
2736dc4fa17SJerome Brunet 
274*3b8a299aSPavel Machek (CIP) 	return 0;
275*3b8a299aSPavel Machek (CIP) 
276*3b8a299aSPavel Machek (CIP) free_clk:
277*3b8a299aSPavel Machek (CIP) 	clk_disable_unprepare(fifo->pclk);
278*3b8a299aSPavel Machek (CIP) free_irq:
279*3b8a299aSPavel Machek (CIP) 	free_irq(fifo->irq, ss);
2806dc4fa17SJerome Brunet 	return ret;
2816dc4fa17SJerome Brunet }
282bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_open);
2836dc4fa17SJerome Brunet 
284bb4ba744SKuninori Morimoto int axg_fifo_pcm_close(struct snd_soc_component *component,
285bb4ba744SKuninori Morimoto 		       struct snd_pcm_substream *ss)
2866dc4fa17SJerome Brunet {
2876dc4fa17SJerome Brunet 	struct axg_fifo *fifo = axg_fifo_data(ss);
2886dc4fa17SJerome Brunet 	int ret;
2896dc4fa17SJerome Brunet 
2906dc4fa17SJerome Brunet 	/* Put the memory arbitror back in reset */
2916dc4fa17SJerome Brunet 	ret = reset_control_assert(fifo->arb);
2926dc4fa17SJerome Brunet 
2936dc4fa17SJerome Brunet 	/* Disable fifo ip and register access */
2946dc4fa17SJerome Brunet 	clk_disable_unprepare(fifo->pclk);
2956dc4fa17SJerome Brunet 
2966dc4fa17SJerome Brunet 	/* remove IRQ */
2976dc4fa17SJerome Brunet 	free_irq(fifo->irq, ss);
2986dc4fa17SJerome Brunet 
2996dc4fa17SJerome Brunet 	return ret;
3006dc4fa17SJerome Brunet }
301bb4ba744SKuninori Morimoto EXPORT_SYMBOL_GPL(axg_fifo_pcm_close);
3027c02509aSJerome Brunet 
3036dc4fa17SJerome Brunet int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
3046dc4fa17SJerome Brunet {
3056dc4fa17SJerome Brunet 	struct snd_card *card = rtd->card->snd_card;
3066dc4fa17SJerome Brunet 	size_t size = axg_fifo_hw.buffer_bytes_max;
3076dc4fa17SJerome Brunet 
308bace3caaSTakashi Iwai 	snd_pcm_set_managed_buffer(rtd->pcm->streams[type].substream,
3096dc4fa17SJerome Brunet 				   SNDRV_DMA_TYPE_DEV, card->dev,
3106dc4fa17SJerome Brunet 				   size, size);
311fba3b09fSTakashi Iwai 	return 0;
3126dc4fa17SJerome Brunet }
3136dc4fa17SJerome Brunet EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
3146dc4fa17SJerome Brunet 
3156dc4fa17SJerome Brunet static const struct regmap_config axg_fifo_regmap_cfg = {
3166dc4fa17SJerome Brunet 	.reg_bits	= 32,
3176dc4fa17SJerome Brunet 	.val_bits	= 32,
3186dc4fa17SJerome Brunet 	.reg_stride	= 4,
31952dd80d8SJerome Brunet 	.max_register	= FIFO_CTRL2,
3206dc4fa17SJerome Brunet };
3216dc4fa17SJerome Brunet 
3226dc4fa17SJerome Brunet int axg_fifo_probe(struct platform_device *pdev)
3236dc4fa17SJerome Brunet {
3246dc4fa17SJerome Brunet 	struct device *dev = &pdev->dev;
3256dc4fa17SJerome Brunet 	const struct axg_fifo_match_data *data;
3266dc4fa17SJerome Brunet 	struct axg_fifo *fifo;
3276dc4fa17SJerome Brunet 	void __iomem *regs;
32823b89e1dSJerome Brunet 	int ret;
3296dc4fa17SJerome Brunet 
3306dc4fa17SJerome Brunet 	data = of_device_get_match_data(dev);
3316dc4fa17SJerome Brunet 	if (!data) {
3326dc4fa17SJerome Brunet 		dev_err(dev, "failed to match device\n");
3336dc4fa17SJerome Brunet 		return -ENODEV;
3346dc4fa17SJerome Brunet 	}
3356dc4fa17SJerome Brunet 
3366dc4fa17SJerome Brunet 	fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
3376dc4fa17SJerome Brunet 	if (!fifo)
3386dc4fa17SJerome Brunet 		return -ENOMEM;
3396dc4fa17SJerome Brunet 	platform_set_drvdata(pdev, fifo);
3406dc4fa17SJerome Brunet 
3419b208931SYueHaibing 	regs = devm_platform_ioremap_resource(pdev, 0);
3426dc4fa17SJerome Brunet 	if (IS_ERR(regs))
3436dc4fa17SJerome Brunet 		return PTR_ERR(regs);
3446dc4fa17SJerome Brunet 
3456dc4fa17SJerome Brunet 	fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg);
3466dc4fa17SJerome Brunet 	if (IS_ERR(fifo->map)) {
3476dc4fa17SJerome Brunet 		dev_err(dev, "failed to init regmap: %ld\n",
3486dc4fa17SJerome Brunet 			PTR_ERR(fifo->map));
3496dc4fa17SJerome Brunet 		return PTR_ERR(fifo->map);
3506dc4fa17SJerome Brunet 	}
3516dc4fa17SJerome Brunet 
3526dc4fa17SJerome Brunet 	fifo->pclk = devm_clk_get(dev, NULL);
3536dc4fa17SJerome Brunet 	if (IS_ERR(fifo->pclk)) {
3546dc4fa17SJerome Brunet 		if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER)
3556dc4fa17SJerome Brunet 			dev_err(dev, "failed to get pclk: %ld\n",
3566dc4fa17SJerome Brunet 				PTR_ERR(fifo->pclk));
3576dc4fa17SJerome Brunet 		return PTR_ERR(fifo->pclk);
3586dc4fa17SJerome Brunet 	}
3596dc4fa17SJerome Brunet 
3606dc4fa17SJerome Brunet 	fifo->arb = devm_reset_control_get_exclusive(dev, NULL);
3616dc4fa17SJerome Brunet 	if (IS_ERR(fifo->arb)) {
3626dc4fa17SJerome Brunet 		if (PTR_ERR(fifo->arb) != -EPROBE_DEFER)
3636dc4fa17SJerome Brunet 			dev_err(dev, "failed to get arb reset: %ld\n",
3646dc4fa17SJerome Brunet 				PTR_ERR(fifo->arb));
3656dc4fa17SJerome Brunet 		return PTR_ERR(fifo->arb);
3666dc4fa17SJerome Brunet 	}
3676dc4fa17SJerome Brunet 
3686dc4fa17SJerome Brunet 	fifo->irq = of_irq_get(dev->of_node, 0);
3696dc4fa17SJerome Brunet 	if (fifo->irq <= 0) {
3706dc4fa17SJerome Brunet 		dev_err(dev, "failed to get irq: %d\n", fifo->irq);
3716dc4fa17SJerome Brunet 		return fifo->irq;
3726dc4fa17SJerome Brunet 	}
3736dc4fa17SJerome Brunet 
374864cee90SJerome Brunet 	fifo->field_threshold =
375864cee90SJerome Brunet 		devm_regmap_field_alloc(dev, fifo->map, data->field_threshold);
376864cee90SJerome Brunet 	if (IS_ERR(fifo->field_threshold))
377864cee90SJerome Brunet 		return PTR_ERR(fifo->field_threshold);
378864cee90SJerome Brunet 
37923b89e1dSJerome Brunet 	ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth",
38023b89e1dSJerome Brunet 				   &fifo->depth);
38123b89e1dSJerome Brunet 	if (ret) {
38223b89e1dSJerome Brunet 		/* Error out for anything but a missing property */
38323b89e1dSJerome Brunet 		if (ret != -EINVAL)
38423b89e1dSJerome Brunet 			return ret;
38523b89e1dSJerome Brunet 		/*
38623b89e1dSJerome Brunet 		 * If the property is missing, it might be because of an old
38723b89e1dSJerome Brunet 		 * DT. In such case, assume the smallest known fifo depth
38823b89e1dSJerome Brunet 		 */
38923b89e1dSJerome Brunet 		fifo->depth = 256;
39023b89e1dSJerome Brunet 		dev_warn(dev, "fifo depth not found, assume %u bytes\n",
39123b89e1dSJerome Brunet 			 fifo->depth);
39223b89e1dSJerome Brunet 	}
39323b89e1dSJerome Brunet 
3946dc4fa17SJerome Brunet 	return devm_snd_soc_register_component(dev, data->component_drv,
3956dc4fa17SJerome Brunet 					       data->dai_drv, 1);
3966dc4fa17SJerome Brunet }
3976dc4fa17SJerome Brunet EXPORT_SYMBOL_GPL(axg_fifo_probe);
3986dc4fa17SJerome Brunet 
3997c02509aSJerome Brunet MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver");
4006dc4fa17SJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
4016dc4fa17SJerome Brunet MODULE_LICENSE("GPL v2");
402