18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (c) 2018 BayLibre, SAS. 48c2ecf20Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 88c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/regmap.h> 118c2ecf20Sopenharmony_ci#include <linux/reset.h> 128c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 138c2ecf20Sopenharmony_ci#include <sound/soc.h> 148c2ecf20Sopenharmony_ci#include <sound/soc-dai.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "axg-fifo.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* 198c2ecf20Sopenharmony_ci * This file implements the platform operations common to the playback and 208c2ecf20Sopenharmony_ci * capture frontend DAI. The logic behind this two types of fifo is very 218c2ecf20Sopenharmony_ci * similar but some difference exist. 228c2ecf20Sopenharmony_ci * These differences are handled in the respective DAI drivers 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct snd_pcm_hardware axg_fifo_hw = { 268c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_INTERLEAVED | 278c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 288c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 298c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 308c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE), 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci .formats = AXG_FIFO_FORMATS, 338c2ecf20Sopenharmony_ci .rate_min = 5512, 348c2ecf20Sopenharmony_ci .rate_max = 192000, 358c2ecf20Sopenharmony_ci .channels_min = 1, 368c2ecf20Sopenharmony_ci .channels_max = AXG_FIFO_CH_MAX, 378c2ecf20Sopenharmony_ci .period_bytes_min = AXG_FIFO_BURST, 388c2ecf20Sopenharmony_ci .period_bytes_max = UINT_MAX, 398c2ecf20Sopenharmony_ci .periods_min = 2, 408c2ecf20Sopenharmony_ci .periods_max = UINT_MAX, 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* No real justification for this */ 438c2ecf20Sopenharmony_ci .buffer_bytes_max = 1 * 1024 * 1024, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = ss->private_data; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return asoc_rtd_to_cpu(rtd, 0); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = axg_fifo_dai(ss); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return snd_soc_dai_get_drvdata(dai); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic struct device *axg_fifo_dev(struct snd_pcm_substream *ss) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = axg_fifo_dai(ss); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return dai->dev; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void __dma_enable(struct axg_fifo *fifo, bool enable) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_DMA_EN, 708c2ecf20Sopenharmony_ci enable ? CTRL0_DMA_EN : 0); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint axg_fifo_pcm_trigger(struct snd_soc_component *component, 748c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss, int cmd) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci switch (cmd) { 798c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 808c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 818c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 828c2ecf20Sopenharmony_ci __dma_enable(fifo, true); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 858c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 868c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 878c2ecf20Sopenharmony_ci __dma_enable(fifo, false); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci default: 908c2ecf20Sopenharmony_ci return -EINVAL; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cisnd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component, 988c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 1018c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = ss->runtime; 1028c2ecf20Sopenharmony_ci unsigned int addr; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci regmap_read(fifo->map, FIFO_STATUS2, &addr); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ciint axg_fifo_pcm_hw_params(struct snd_soc_component *component, 1118c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss, 1128c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = ss->runtime; 1158c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 1168c2ecf20Sopenharmony_ci unsigned int burst_num, period, threshold; 1178c2ecf20Sopenharmony_ci dma_addr_t end_ptr; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci period = params_period_bytes(params); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Setup dma memory pointers */ 1228c2ecf20Sopenharmony_ci end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST; 1238c2ecf20Sopenharmony_ci regmap_write(fifo->map, FIFO_START_ADDR, runtime->dma_addr); 1248c2ecf20Sopenharmony_ci regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Setup interrupt periodicity */ 1278c2ecf20Sopenharmony_ci burst_num = period / AXG_FIFO_BURST; 1288c2ecf20Sopenharmony_ci regmap_write(fifo->map, FIFO_INT_ADDR, burst_num); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Start the fifo request on the smallest of the following: 1328c2ecf20Sopenharmony_ci * - Half the fifo size 1338c2ecf20Sopenharmony_ci * - Half the period size 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci threshold = min(period / 2, fifo->depth / 2); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * With the threshold in bytes, register value is: 1398c2ecf20Sopenharmony_ci * V = (threshold / burst) - 1 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci threshold /= AXG_FIFO_BURST; 1428c2ecf20Sopenharmony_ci regmap_field_write(fifo->field_threshold, 1438c2ecf20Sopenharmony_ci threshold ? threshold - 1 : 0); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Enable block count irq */ 1468c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL0, 1478c2ecf20Sopenharmony_ci CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 1488c2ecf20Sopenharmony_ci CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT)); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciint g12a_fifo_pcm_hw_params(struct snd_soc_component *component, 1558c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss, 1568c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 1598c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = ss->runtime; 1608c2ecf20Sopenharmony_ci int ret; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = axg_fifo_pcm_hw_params(component, ss, params); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Set the initial memory address of the DMA */ 1678c2ecf20Sopenharmony_ci regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciint axg_fifo_pcm_hw_free(struct snd_soc_component *component, 1748c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Disable the block count irq */ 1798c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL0, 1808c2ecf20Sopenharmony_ci CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, 1898c2ecf20Sopenharmony_ci CTRL1_INT_CLR(FIFO_INT_MASK), 1908c2ecf20Sopenharmony_ci CTRL1_INT_CLR(mask)); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Clear must also be cleared */ 1938c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, 1948c2ecf20Sopenharmony_ci CTRL1_INT_CLR(FIFO_INT_MASK), 1958c2ecf20Sopenharmony_ci 0); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss = dev_id; 2018c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 2028c2ecf20Sopenharmony_ci unsigned int status; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci regmap_read(fifo->map, FIFO_STATUS1, &status); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci status = STATUS1_INT_STS(status) & FIFO_INT_MASK; 2078c2ecf20Sopenharmony_ci if (status & FIFO_INT_COUNT_REPEAT) 2088c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ss); 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n", 2118c2ecf20Sopenharmony_ci status); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Ack irqs */ 2148c2ecf20Sopenharmony_ci axg_fifo_ack_irq(fifo, status); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return IRQ_RETVAL(status); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciint axg_fifo_pcm_open(struct snd_soc_component *component, 2208c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 2238c2ecf20Sopenharmony_ci struct device *dev = axg_fifo_dev(ss); 2248c2ecf20Sopenharmony_ci int ret; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * Make sure the buffer and period size are multiple of the FIFO 2308c2ecf20Sopenharmony_ci * burst 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_step(ss->runtime, 0, 2338c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2348c2ecf20Sopenharmony_ci AXG_FIFO_BURST); 2358c2ecf20Sopenharmony_ci if (ret) 2368c2ecf20Sopenharmony_ci return ret; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_step(ss->runtime, 0, 2398c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2408c2ecf20Sopenharmony_ci AXG_FIFO_BURST); 2418c2ecf20Sopenharmony_ci if (ret) 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0, 2458c2ecf20Sopenharmony_ci dev_name(dev), ss); 2468c2ecf20Sopenharmony_ci if (ret) 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Enable pclk to access registers and clock the fifo ip */ 2508c2ecf20Sopenharmony_ci ret = clk_prepare_enable(fifo->pclk); 2518c2ecf20Sopenharmony_ci if (ret) 2528c2ecf20Sopenharmony_ci goto free_irq; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* Setup status2 so it reports the memory pointer */ 2558c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL1, 2568c2ecf20Sopenharmony_ci CTRL1_STATUS2_SEL_MASK, 2578c2ecf20Sopenharmony_ci CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ)); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Make sure the dma is initially disabled */ 2608c2ecf20Sopenharmony_ci __dma_enable(fifo, false); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Disable irqs until params are ready */ 2638c2ecf20Sopenharmony_ci regmap_update_bits(fifo->map, FIFO_CTRL0, 2648c2ecf20Sopenharmony_ci CTRL0_INT_EN(FIFO_INT_MASK), 0); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Clear any pending interrupt */ 2678c2ecf20Sopenharmony_ci axg_fifo_ack_irq(fifo, FIFO_INT_MASK); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Take memory arbitror out of reset */ 2708c2ecf20Sopenharmony_ci ret = reset_control_deassert(fifo->arb); 2718c2ecf20Sopenharmony_ci if (ret) 2728c2ecf20Sopenharmony_ci goto free_clk; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cifree_clk: 2778c2ecf20Sopenharmony_ci clk_disable_unprepare(fifo->pclk); 2788c2ecf20Sopenharmony_cifree_irq: 2798c2ecf20Sopenharmony_ci free_irq(fifo->irq, ss); 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_open); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciint axg_fifo_pcm_close(struct snd_soc_component *component, 2858c2ecf20Sopenharmony_ci struct snd_pcm_substream *ss) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct axg_fifo *fifo = axg_fifo_data(ss); 2888c2ecf20Sopenharmony_ci int ret; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Put the memory arbitror back in reset */ 2918c2ecf20Sopenharmony_ci ret = reset_control_assert(fifo->arb); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Disable fifo ip and register access */ 2948c2ecf20Sopenharmony_ci clk_disable_unprepare(fifo->pclk); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* remove IRQ */ 2978c2ecf20Sopenharmony_ci free_irq(fifo->irq, ss); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return ret; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_close); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciint axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct snd_card *card = rtd->card->snd_card; 3068c2ecf20Sopenharmony_ci size_t size = axg_fifo_hw.buffer_bytes_max; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer(rtd->pcm->streams[type].substream, 3098c2ecf20Sopenharmony_ci SNDRV_DMA_TYPE_DEV, card->dev, 3108c2ecf20Sopenharmony_ci size, size); 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_pcm_new); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const struct regmap_config axg_fifo_regmap_cfg = { 3168c2ecf20Sopenharmony_ci .reg_bits = 32, 3178c2ecf20Sopenharmony_ci .val_bits = 32, 3188c2ecf20Sopenharmony_ci .reg_stride = 4, 3198c2ecf20Sopenharmony_ci .max_register = FIFO_CTRL2, 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciint axg_fifo_probe(struct platform_device *pdev) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3258c2ecf20Sopenharmony_ci const struct axg_fifo_match_data *data; 3268c2ecf20Sopenharmony_ci struct axg_fifo *fifo; 3278c2ecf20Sopenharmony_ci void __iomem *regs; 3288c2ecf20Sopenharmony_ci int ret; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci data = of_device_get_match_data(dev); 3318c2ecf20Sopenharmony_ci if (!data) { 3328c2ecf20Sopenharmony_ci dev_err(dev, "failed to match device\n"); 3338c2ecf20Sopenharmony_ci return -ENODEV; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL); 3378c2ecf20Sopenharmony_ci if (!fifo) 3388c2ecf20Sopenharmony_ci return -ENOMEM; 3398c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, fifo); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 3428c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 3438c2ecf20Sopenharmony_ci return PTR_ERR(regs); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg); 3468c2ecf20Sopenharmony_ci if (IS_ERR(fifo->map)) { 3478c2ecf20Sopenharmony_ci dev_err(dev, "failed to init regmap: %ld\n", 3488c2ecf20Sopenharmony_ci PTR_ERR(fifo->map)); 3498c2ecf20Sopenharmony_ci return PTR_ERR(fifo->map); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci fifo->pclk = devm_clk_get(dev, NULL); 3538c2ecf20Sopenharmony_ci if (IS_ERR(fifo->pclk)) { 3548c2ecf20Sopenharmony_ci if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER) 3558c2ecf20Sopenharmony_ci dev_err(dev, "failed to get pclk: %ld\n", 3568c2ecf20Sopenharmony_ci PTR_ERR(fifo->pclk)); 3578c2ecf20Sopenharmony_ci return PTR_ERR(fifo->pclk); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci fifo->arb = devm_reset_control_get_exclusive(dev, NULL); 3618c2ecf20Sopenharmony_ci if (IS_ERR(fifo->arb)) { 3628c2ecf20Sopenharmony_ci if (PTR_ERR(fifo->arb) != -EPROBE_DEFER) 3638c2ecf20Sopenharmony_ci dev_err(dev, "failed to get arb reset: %ld\n", 3648c2ecf20Sopenharmony_ci PTR_ERR(fifo->arb)); 3658c2ecf20Sopenharmony_ci return PTR_ERR(fifo->arb); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci fifo->irq = of_irq_get(dev->of_node, 0); 3698c2ecf20Sopenharmony_ci if (fifo->irq <= 0) { 3708c2ecf20Sopenharmony_ci dev_err(dev, "failed to get irq: %d\n", fifo->irq); 3718c2ecf20Sopenharmony_ci return fifo->irq; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci fifo->field_threshold = 3758c2ecf20Sopenharmony_ci devm_regmap_field_alloc(dev, fifo->map, data->field_threshold); 3768c2ecf20Sopenharmony_ci if (IS_ERR(fifo->field_threshold)) 3778c2ecf20Sopenharmony_ci return PTR_ERR(fifo->field_threshold); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth", 3808c2ecf20Sopenharmony_ci &fifo->depth); 3818c2ecf20Sopenharmony_ci if (ret) { 3828c2ecf20Sopenharmony_ci /* Error out for anything but a missing property */ 3838c2ecf20Sopenharmony_ci if (ret != -EINVAL) 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * If the property is missing, it might be because of an old 3878c2ecf20Sopenharmony_ci * DT. In such case, assume the smallest known fifo depth 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci fifo->depth = 256; 3908c2ecf20Sopenharmony_ci dev_warn(dev, "fifo depth not found, assume %u bytes\n", 3918c2ecf20Sopenharmony_ci fifo->depth); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(dev, data->component_drv, 3958c2ecf20Sopenharmony_ci data->dai_drv, 1); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(axg_fifo_probe); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver"); 4008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 4018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 402