18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 MediaTek Inc. 68c2ecf20Sopenharmony_ci * Author: Garlic Tseng <garlic.tseng@mediatek.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <sound/soc.h> 148c2ecf20Sopenharmony_ci#include "mtk-afe-platform-driver.h" 158c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 168c2ecf20Sopenharmony_ci#include "mtk-afe-fe-dai.h" 178c2ecf20Sopenharmony_ci#include "mtk-base-afe.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define AFE_BASE_END_OFFSET 8 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int mtk_regmap_update_bits(struct regmap *map, int reg, 228c2ecf20Sopenharmony_ci unsigned int mask, 238c2ecf20Sopenharmony_ci unsigned int val, int shift) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (reg < 0 || WARN_ON_ONCE(shift < 0)) 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci return regmap_update_bits(map, reg, mask << shift, val << shift); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci if (reg < 0) 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci return regmap_write(map, reg, val); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciint mtk_afe_fe_startup(struct snd_pcm_substream *substream, 388c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 418c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 428c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 438c2ecf20Sopenharmony_ci int memif_num = asoc_rtd_to_cpu(rtd, 0)->id; 448c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; 458c2ecf20Sopenharmony_ci const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; 468c2ecf20Sopenharmony_ci int ret; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci memif->substream = substream; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(substream->runtime, 0, 518c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); 528c2ecf20Sopenharmony_ci /* enable agent */ 538c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 548c2ecf20Sopenharmony_ci 1, 0, memif->data->agent_disable_shift); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be 608c2ecf20Sopenharmony_ci * smaller than period_size due to AFE's internal buffer. 618c2ecf20Sopenharmony_ci * This easily leads to overrun when avail_min is period_size. 628c2ecf20Sopenharmony_ci * One more period can hold the possible unread buffer. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 658c2ecf20Sopenharmony_ci int periods_max = mtk_afe_hardware->periods_max; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_minmax(runtime, 688c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS, 698c2ecf20Sopenharmony_ci 3, periods_max); 708c2ecf20Sopenharmony_ci if (ret < 0) { 718c2ecf20Sopenharmony_ci dev_err(afe->dev, "hw_constraint_minmax failed\n"); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_integer(runtime, 778c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 788c2ecf20Sopenharmony_ci if (ret < 0) 798c2ecf20Sopenharmony_ci dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* dynamic allocate irq to memif */ 828c2ecf20Sopenharmony_ci if (memif->irq_usage < 0) { 838c2ecf20Sopenharmony_ci int irq_id = mtk_dynamic_irq_acquire(afe); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (irq_id != afe->irqs_size) { 868c2ecf20Sopenharmony_ci /* link */ 878c2ecf20Sopenharmony_ci memif->irq_usage = irq_id; 888c2ecf20Sopenharmony_ci } else { 898c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s() error: no more asys irq\n", 908c2ecf20Sopenharmony_ci __func__); 918c2ecf20Sopenharmony_ci ret = -EBUSY; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci return ret; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_startup); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_civoid mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, 998c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1028c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 1038c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; 1048c2ecf20Sopenharmony_ci int irq_id; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci irq_id = memif->irq_usage; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 1098c2ecf20Sopenharmony_ci 1, 1, memif->data->agent_disable_shift); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!memif->const_irq) { 1128c2ecf20Sopenharmony_ci mtk_dynamic_irq_release(afe, irq_id); 1138c2ecf20Sopenharmony_ci memif->irq_usage = -1; 1148c2ecf20Sopenharmony_ci memif->substream = NULL; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciint mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, 1208c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 1218c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1248c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 1258c2ecf20Sopenharmony_ci int id = asoc_rtd_to_cpu(rtd, 0)->id; 1268c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 1278c2ecf20Sopenharmony_ci int ret; 1288c2ecf20Sopenharmony_ci unsigned int channels = params_channels(params); 1298c2ecf20Sopenharmony_ci unsigned int rate = params_rate(params); 1308c2ecf20Sopenharmony_ci snd_pcm_format_t format = params_format(params); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (afe->request_dram_resource) 1338c2ecf20Sopenharmony_ci afe->request_dram_resource(afe->dev); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n", 1368c2ecf20Sopenharmony_ci __func__, memif->data->name, 1378c2ecf20Sopenharmony_ci channels, rate, format, 1388c2ecf20Sopenharmony_ci &substream->runtime->dma_addr, 1398c2ecf20Sopenharmony_ci substream->runtime->dma_area, 1408c2ecf20Sopenharmony_ci substream->runtime->dma_bytes); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci memset_io(substream->runtime->dma_area, 0, 1438c2ecf20Sopenharmony_ci substream->runtime->dma_bytes); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* set addr */ 1468c2ecf20Sopenharmony_ci ret = mtk_memif_set_addr(afe, id, 1478c2ecf20Sopenharmony_ci substream->runtime->dma_area, 1488c2ecf20Sopenharmony_ci substream->runtime->dma_addr, 1498c2ecf20Sopenharmony_ci substream->runtime->dma_bytes); 1508c2ecf20Sopenharmony_ci if (ret) { 1518c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n", 1528c2ecf20Sopenharmony_ci __func__, id, ret); 1538c2ecf20Sopenharmony_ci return ret; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* set channel */ 1578c2ecf20Sopenharmony_ci ret = mtk_memif_set_channel(afe, id, channels); 1588c2ecf20Sopenharmony_ci if (ret) { 1598c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n", 1608c2ecf20Sopenharmony_ci __func__, id, channels, ret); 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* set rate */ 1658c2ecf20Sopenharmony_ci ret = mtk_memif_set_rate_substream(substream, id, rate); 1668c2ecf20Sopenharmony_ci if (ret) { 1678c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n", 1688c2ecf20Sopenharmony_ci __func__, id, rate, ret); 1698c2ecf20Sopenharmony_ci return ret; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* set format */ 1738c2ecf20Sopenharmony_ci ret = mtk_memif_set_format(afe, id, format); 1748c2ecf20Sopenharmony_ci if (ret) { 1758c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n", 1768c2ecf20Sopenharmony_ci __func__, id, format, ret); 1778c2ecf20Sopenharmony_ci return ret; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciint mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, 1858c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (afe->release_dram_resource) 1908c2ecf20Sopenharmony_ci afe->release_dram_resource(afe->dev); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ciint mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, 1978c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2008c2ecf20Sopenharmony_ci struct snd_pcm_runtime * const runtime = substream->runtime; 2018c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 2028c2ecf20Sopenharmony_ci int id = asoc_rtd_to_cpu(rtd, 0)->id; 2038c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 2048c2ecf20Sopenharmony_ci struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; 2058c2ecf20Sopenharmony_ci const struct mtk_base_irq_data *irq_data = irqs->irq_data; 2068c2ecf20Sopenharmony_ci unsigned int counter = runtime->period_size; 2078c2ecf20Sopenharmony_ci int fs; 2088c2ecf20Sopenharmony_ci int ret; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci switch (cmd) { 2138c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2148c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2158c2ecf20Sopenharmony_ci ret = mtk_memif_set_enable(afe, id); 2168c2ecf20Sopenharmony_ci if (ret) { 2178c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", 2188c2ecf20Sopenharmony_ci __func__, id, ret); 2198c2ecf20Sopenharmony_ci return ret; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* set irq counter */ 2238c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, 2248c2ecf20Sopenharmony_ci irq_data->irq_cnt_maskbit, counter, 2258c2ecf20Sopenharmony_ci irq_data->irq_cnt_shift); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* set irq fs */ 2288c2ecf20Sopenharmony_ci fs = afe->irq_fs(substream, runtime->rate); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (fs < 0) 2318c2ecf20Sopenharmony_ci return -EINVAL; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, 2348c2ecf20Sopenharmony_ci irq_data->irq_fs_maskbit, fs, 2358c2ecf20Sopenharmony_ci irq_data->irq_fs_shift); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* enable interrupt */ 2388c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 2398c2ecf20Sopenharmony_ci 1, 1, irq_data->irq_en_shift); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2438c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 2448c2ecf20Sopenharmony_ci ret = mtk_memif_set_disable(afe, id); 2458c2ecf20Sopenharmony_ci if (ret) { 2468c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", 2478c2ecf20Sopenharmony_ci __func__, id, ret); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* disable interrupt */ 2518c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 2528c2ecf20Sopenharmony_ci 1, 0, irq_data->irq_en_shift); 2538c2ecf20Sopenharmony_ci /* and clear pending IRQ */ 2548c2ecf20Sopenharmony_ci mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, 2558c2ecf20Sopenharmony_ci 1 << irq_data->irq_clr_shift); 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci default: 2588c2ecf20Sopenharmony_ci return -EINVAL; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ciint mtk_afe_fe_prepare(struct snd_pcm_substream *substream, 2648c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2678c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 2688c2ecf20Sopenharmony_ci int id = asoc_rtd_to_cpu(rtd, 0)->id; 2698c2ecf20Sopenharmony_ci int pbuf_size; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 2728c2ecf20Sopenharmony_ci if (afe->get_memif_pbuf_size) { 2738c2ecf20Sopenharmony_ci pbuf_size = afe->get_memif_pbuf_size(substream); 2748c2ecf20Sopenharmony_ci mtk_memif_set_pbuf_size(afe, id, pbuf_size); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ciconst struct snd_soc_dai_ops mtk_afe_fe_ops = { 2828c2ecf20Sopenharmony_ci .startup = mtk_afe_fe_startup, 2838c2ecf20Sopenharmony_ci .shutdown = mtk_afe_fe_shutdown, 2848c2ecf20Sopenharmony_ci .hw_params = mtk_afe_fe_hw_params, 2858c2ecf20Sopenharmony_ci .hw_free = mtk_afe_fe_hw_free, 2868c2ecf20Sopenharmony_ci .prepare = mtk_afe_fe_prepare, 2878c2ecf20Sopenharmony_ci .trigger = mtk_afe_fe_trigger, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_ops); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(irqs_lock); 2928c2ecf20Sopenharmony_ciint mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci int i; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci mutex_lock(&afe->irq_alloc_lock); 2978c2ecf20Sopenharmony_ci for (i = 0; i < afe->irqs_size; ++i) { 2988c2ecf20Sopenharmony_ci if (afe->irqs[i].irq_occupyed == 0) { 2998c2ecf20Sopenharmony_ci afe->irqs[i].irq_occupyed = 1; 3008c2ecf20Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 3018c2ecf20Sopenharmony_ci return i; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 3058c2ecf20Sopenharmony_ci return afe->irqs_size; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciint mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci mutex_lock(&afe->irq_alloc_lock); 3128c2ecf20Sopenharmony_ci if (irq_id >= 0 && irq_id < afe->irqs_size) { 3138c2ecf20Sopenharmony_ci afe->irqs[irq_id].irq_occupyed = 0; 3148c2ecf20Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 3188c2ecf20Sopenharmony_ci return -EINVAL; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_dynamic_irq_release); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciint mtk_afe_suspend(struct snd_soc_component *component) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 3258c2ecf20Sopenharmony_ci struct device *dev = afe->dev; 3268c2ecf20Sopenharmony_ci struct regmap *regmap = afe->regmap; 3278c2ecf20Sopenharmony_ci int i; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (pm_runtime_status_suspended(dev) || afe->suspended) 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (!afe->reg_back_up) 3338c2ecf20Sopenharmony_ci afe->reg_back_up = 3348c2ecf20Sopenharmony_ci devm_kcalloc(dev, afe->reg_back_up_list_num, 3358c2ecf20Sopenharmony_ci sizeof(unsigned int), GFP_KERNEL); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci for (i = 0; i < afe->reg_back_up_list_num; i++) 3388c2ecf20Sopenharmony_ci regmap_read(regmap, afe->reg_back_up_list[i], 3398c2ecf20Sopenharmony_ci &afe->reg_back_up[i]); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci afe->suspended = true; 3428c2ecf20Sopenharmony_ci afe->runtime_suspend(dev); 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_suspend); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciint mtk_afe_resume(struct snd_soc_component *component) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 3508c2ecf20Sopenharmony_ci struct device *dev = afe->dev; 3518c2ecf20Sopenharmony_ci struct regmap *regmap = afe->regmap; 3528c2ecf20Sopenharmony_ci int i = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (pm_runtime_status_suspended(dev) || !afe->suspended) 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci afe->runtime_resume(dev); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (!afe->reg_back_up) 3608c2ecf20Sopenharmony_ci dev_dbg(dev, "%s no reg_backup\n", __func__); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci for (i = 0; i < afe->reg_back_up_list_num; i++) 3638c2ecf20Sopenharmony_ci mtk_regmap_write(regmap, afe->reg_back_up_list[i], 3648c2ecf20Sopenharmony_ci afe->reg_back_up[i]); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci afe->suspended = false; 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_resume); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ciint mtk_memif_set_enable(struct mtk_base_afe *afe, int id) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (memif->data->enable_shift < 0) { 3768c2ecf20Sopenharmony_ci dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n", 3778c2ecf20Sopenharmony_ci __func__, id); 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 3818c2ecf20Sopenharmony_ci 1, 1, memif->data->enable_shift); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_enable); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ciint mtk_memif_set_disable(struct mtk_base_afe *afe, int id) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (memif->data->enable_shift < 0) { 3908c2ecf20Sopenharmony_ci dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n", 3918c2ecf20Sopenharmony_ci __func__, id); 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 3958c2ecf20Sopenharmony_ci 1, 0, memif->data->enable_shift); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_disable); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ciint mtk_memif_set_addr(struct mtk_base_afe *afe, int id, 4008c2ecf20Sopenharmony_ci unsigned char *dma_area, 4018c2ecf20Sopenharmony_ci dma_addr_t dma_addr, 4028c2ecf20Sopenharmony_ci size_t dma_bytes) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 4058c2ecf20Sopenharmony_ci int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0; 4068c2ecf20Sopenharmony_ci unsigned int phys_buf_addr = lower_32_bits(dma_addr); 4078c2ecf20Sopenharmony_ci unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci memif->dma_area = dma_area; 4108c2ecf20Sopenharmony_ci memif->dma_addr = dma_addr; 4118c2ecf20Sopenharmony_ci memif->dma_bytes = dma_bytes; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* start */ 4148c2ecf20Sopenharmony_ci mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base, 4158c2ecf20Sopenharmony_ci phys_buf_addr); 4168c2ecf20Sopenharmony_ci /* end */ 4178c2ecf20Sopenharmony_ci if (memif->data->reg_ofs_end) 4188c2ecf20Sopenharmony_ci mtk_regmap_write(afe->regmap, 4198c2ecf20Sopenharmony_ci memif->data->reg_ofs_end, 4208c2ecf20Sopenharmony_ci phys_buf_addr + dma_bytes - 1); 4218c2ecf20Sopenharmony_ci else 4228c2ecf20Sopenharmony_ci mtk_regmap_write(afe->regmap, 4238c2ecf20Sopenharmony_ci memif->data->reg_ofs_base + 4248c2ecf20Sopenharmony_ci AFE_BASE_END_OFFSET, 4258c2ecf20Sopenharmony_ci phys_buf_addr + dma_bytes - 1); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* set start, end, upper 32 bits */ 4288c2ecf20Sopenharmony_ci if (memif->data->reg_ofs_base_msb) { 4298c2ecf20Sopenharmony_ci mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb, 4308c2ecf20Sopenharmony_ci phys_buf_addr_upper_32); 4318c2ecf20Sopenharmony_ci mtk_regmap_write(afe->regmap, 4328c2ecf20Sopenharmony_ci memif->data->reg_ofs_end_msb, 4338c2ecf20Sopenharmony_ci phys_buf_addr_upper_32); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* set MSB to 33-bit */ 4378c2ecf20Sopenharmony_ci if (memif->data->msb_reg >= 0) 4388c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 4398c2ecf20Sopenharmony_ci 1, msb_at_bit33, memif->data->msb_shift); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_addr); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciint mtk_memif_set_channel(struct mtk_base_afe *afe, 4468c2ecf20Sopenharmony_ci int id, unsigned int channel) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 4498c2ecf20Sopenharmony_ci unsigned int mono; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (memif->data->mono_shift < 0) 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (memif->data->quad_ch_mask) { 4558c2ecf20Sopenharmony_ci unsigned int quad_ch = (channel == 4) ? 1 : 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg, 4588c2ecf20Sopenharmony_ci memif->data->quad_ch_mask, 4598c2ecf20Sopenharmony_ci quad_ch, memif->data->quad_ch_shift); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (memif->data->mono_invert) 4638c2ecf20Sopenharmony_ci mono = (channel == 1) ? 0 : 1; 4648c2ecf20Sopenharmony_ci else 4658c2ecf20Sopenharmony_ci mono = (channel == 1) ? 1 : 0; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 4688c2ecf20Sopenharmony_ci 1, mono, memif->data->mono_shift); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_channel); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int mtk_memif_set_rate_fs(struct mtk_base_afe *afe, 4738c2ecf20Sopenharmony_ci int id, int fs) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (memif->data->fs_shift >= 0) 4788c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, 4798c2ecf20Sopenharmony_ci memif->data->fs_maskbit, 4808c2ecf20Sopenharmony_ci fs, memif->data->fs_shift); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ciint mtk_memif_set_rate(struct mtk_base_afe *afe, 4868c2ecf20Sopenharmony_ci int id, unsigned int rate) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int fs = 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!afe->get_dai_fs) { 4918c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n", 4928c2ecf20Sopenharmony_ci __func__); 4938c2ecf20Sopenharmony_ci return -EINVAL; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci fs = afe->get_dai_fs(afe, id, rate); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (fs < 0) 4998c2ecf20Sopenharmony_ci return -EINVAL; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return mtk_memif_set_rate_fs(afe, id, fs); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_rate); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ciint mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, 5068c2ecf20Sopenharmony_ci int id, unsigned int rate) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 5098c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5108c2ecf20Sopenharmony_ci snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 5118c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci int fs = 0; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (!afe->memif_fs) { 5168c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n", 5178c2ecf20Sopenharmony_ci __func__); 5188c2ecf20Sopenharmony_ci return -EINVAL; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci fs = afe->memif_fs(substream, rate); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (fs < 0) 5248c2ecf20Sopenharmony_ci return -EINVAL; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return mtk_memif_set_rate_fs(afe, id, fs); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciint mtk_memif_set_format(struct mtk_base_afe *afe, 5318c2ecf20Sopenharmony_ci int id, snd_pcm_format_t format) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 5348c2ecf20Sopenharmony_ci int hd_audio = 0; 5358c2ecf20Sopenharmony_ci int hd_align = 0; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* set hd mode */ 5388c2ecf20Sopenharmony_ci switch (format) { 5398c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 5408c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U16_LE: 5418c2ecf20Sopenharmony_ci hd_audio = 0; 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 5448c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U32_LE: 5458c2ecf20Sopenharmony_ci hd_audio = 1; 5468c2ecf20Sopenharmony_ci hd_align = 1; 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 5498c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_LE: 5508c2ecf20Sopenharmony_ci hd_audio = 1; 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci default: 5538c2ecf20Sopenharmony_ci dev_err(afe->dev, "%s() error: unsupported format %d\n", 5548c2ecf20Sopenharmony_ci __func__, format); 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 5598c2ecf20Sopenharmony_ci 1, hd_audio, memif->data->hd_shift); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, 5628c2ecf20Sopenharmony_ci 1, hd_align, memif->data->hd_align_mshift); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_format); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ciint mtk_memif_set_pbuf_size(struct mtk_base_afe *afe, 5698c2ecf20Sopenharmony_ci int id, int pbuf_size) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci const struct mtk_base_memif_data *memif_data = afe->memif[id].data; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0) 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg, 5778c2ecf20Sopenharmony_ci memif_data->pbuf_mask, 5788c2ecf20Sopenharmony_ci pbuf_size, memif_data->pbuf_shift); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg, 5818c2ecf20Sopenharmony_ci memif_data->minlen_mask, 5828c2ecf20Sopenharmony_ci pbuf_size, memif_data->minlen_shift); 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mediatek simple fe dai operator"); 5888c2ecf20Sopenharmony_ciMODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 5898c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 590