162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2016 MediaTek Inc. 662306a36Sopenharmony_ci * Author: Garlic Tseng <garlic.tseng@mediatek.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1262306a36Sopenharmony_ci#include <linux/regmap.h> 1362306a36Sopenharmony_ci#include <sound/soc.h> 1462306a36Sopenharmony_ci#include "mtk-afe-platform-driver.h" 1562306a36Sopenharmony_ci#include <sound/pcm_params.h> 1662306a36Sopenharmony_ci#include "mtk-afe-fe-dai.h" 1762306a36Sopenharmony_ci#include "mtk-base-afe.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define AFE_BASE_END_OFFSET 8 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int mtk_regmap_update_bits(struct regmap *map, int reg, 2262306a36Sopenharmony_ci unsigned int mask, 2362306a36Sopenharmony_ci unsigned int val, int shift) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci if (reg < 0 || WARN_ON_ONCE(shift < 0)) 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci return regmap_update_bits(map, reg, mask << shift, val << shift); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci if (reg < 0) 3362306a36Sopenharmony_ci return 0; 3462306a36Sopenharmony_ci return regmap_write(map, reg, val); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciint mtk_afe_fe_startup(struct snd_pcm_substream *substream, 3862306a36Sopenharmony_ci struct snd_soc_dai *dai) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 4162306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 4262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 4362306a36Sopenharmony_ci int memif_num = asoc_rtd_to_cpu(rtd, 0)->id; 4462306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; 4562306a36Sopenharmony_ci const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; 4662306a36Sopenharmony_ci int ret; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci memif->substream = substream; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci snd_pcm_hw_constraint_step(substream->runtime, 0, 5162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); 5262306a36Sopenharmony_ci /* enable agent */ 5362306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 5462306a36Sopenharmony_ci 1, 0, memif->data->agent_disable_shift); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* 5962306a36Sopenharmony_ci * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be 6062306a36Sopenharmony_ci * smaller than period_size due to AFE's internal buffer. 6162306a36Sopenharmony_ci * This easily leads to overrun when avail_min is period_size. 6262306a36Sopenharmony_ci * One more period can hold the possible unread buffer. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 6562306a36Sopenharmony_ci int periods_max = mtk_afe_hardware->periods_max; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = snd_pcm_hw_constraint_minmax(runtime, 6862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS, 6962306a36Sopenharmony_ci 3, periods_max); 7062306a36Sopenharmony_ci if (ret < 0) { 7162306a36Sopenharmony_ci dev_err(afe->dev, "hw_constraint_minmax failed\n"); 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ret = snd_pcm_hw_constraint_integer(runtime, 7762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 7862306a36Sopenharmony_ci if (ret < 0) 7962306a36Sopenharmony_ci dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* dynamic allocate irq to memif */ 8262306a36Sopenharmony_ci if (memif->irq_usage < 0) { 8362306a36Sopenharmony_ci int irq_id = mtk_dynamic_irq_acquire(afe); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (irq_id != afe->irqs_size) { 8662306a36Sopenharmony_ci /* link */ 8762306a36Sopenharmony_ci memif->irq_usage = irq_id; 8862306a36Sopenharmony_ci } else { 8962306a36Sopenharmony_ci dev_err(afe->dev, "%s() error: no more asys irq\n", 9062306a36Sopenharmony_ci __func__); 9162306a36Sopenharmony_ci ret = -EBUSY; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci return ret; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_startup); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, 9962306a36Sopenharmony_ci struct snd_soc_dai *dai) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 10262306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 10362306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; 10462306a36Sopenharmony_ci int irq_id; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci irq_id = memif->irq_usage; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 10962306a36Sopenharmony_ci 1, 1, memif->data->agent_disable_shift); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!memif->const_irq) { 11262306a36Sopenharmony_ci mtk_dynamic_irq_release(afe, irq_id); 11362306a36Sopenharmony_ci memif->irq_usage = -1; 11462306a36Sopenharmony_ci memif->substream = NULL; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciint mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, 12062306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 12162306a36Sopenharmony_ci struct snd_soc_dai *dai) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 12462306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 12562306a36Sopenharmony_ci int id = asoc_rtd_to_cpu(rtd, 0)->id; 12662306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 12762306a36Sopenharmony_ci int ret; 12862306a36Sopenharmony_ci unsigned int channels = params_channels(params); 12962306a36Sopenharmony_ci unsigned int rate = params_rate(params); 13062306a36Sopenharmony_ci snd_pcm_format_t format = params_format(params); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (afe->request_dram_resource) 13362306a36Sopenharmony_ci afe->request_dram_resource(afe->dev); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n", 13662306a36Sopenharmony_ci __func__, memif->data->name, 13762306a36Sopenharmony_ci channels, rate, format, 13862306a36Sopenharmony_ci &substream->runtime->dma_addr, 13962306a36Sopenharmony_ci substream->runtime->dma_area, 14062306a36Sopenharmony_ci substream->runtime->dma_bytes); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci memset_io((void __force __iomem *)substream->runtime->dma_area, 0, 14362306a36Sopenharmony_ci substream->runtime->dma_bytes); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* set addr */ 14662306a36Sopenharmony_ci ret = mtk_memif_set_addr(afe, id, 14762306a36Sopenharmony_ci substream->runtime->dma_area, 14862306a36Sopenharmony_ci substream->runtime->dma_addr, 14962306a36Sopenharmony_ci substream->runtime->dma_bytes); 15062306a36Sopenharmony_ci if (ret) { 15162306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n", 15262306a36Sopenharmony_ci __func__, id, ret); 15362306a36Sopenharmony_ci return ret; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* set channel */ 15762306a36Sopenharmony_ci ret = mtk_memif_set_channel(afe, id, channels); 15862306a36Sopenharmony_ci if (ret) { 15962306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n", 16062306a36Sopenharmony_ci __func__, id, channels, ret); 16162306a36Sopenharmony_ci return ret; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* set rate */ 16562306a36Sopenharmony_ci ret = mtk_memif_set_rate_substream(substream, id, rate); 16662306a36Sopenharmony_ci if (ret) { 16762306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n", 16862306a36Sopenharmony_ci __func__, id, rate, ret); 16962306a36Sopenharmony_ci return ret; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* set format */ 17362306a36Sopenharmony_ci ret = mtk_memif_set_format(afe, id, format); 17462306a36Sopenharmony_ci if (ret) { 17562306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n", 17662306a36Sopenharmony_ci __func__, id, format, ret); 17762306a36Sopenharmony_ci return ret; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciint mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, 18562306a36Sopenharmony_ci struct snd_soc_dai *dai) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (afe->release_dram_resource) 19062306a36Sopenharmony_ci afe->release_dram_resource(afe->dev); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciint mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, 19762306a36Sopenharmony_ci struct snd_soc_dai *dai) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 20062306a36Sopenharmony_ci struct snd_pcm_runtime * const runtime = substream->runtime; 20162306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 20262306a36Sopenharmony_ci int id = asoc_rtd_to_cpu(rtd, 0)->id; 20362306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 20462306a36Sopenharmony_ci struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; 20562306a36Sopenharmony_ci const struct mtk_base_irq_data *irq_data = irqs->irq_data; 20662306a36Sopenharmony_ci unsigned int counter = runtime->period_size; 20762306a36Sopenharmony_ci int fs; 20862306a36Sopenharmony_ci int ret; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci switch (cmd) { 21362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 21462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 21562306a36Sopenharmony_ci ret = mtk_memif_set_enable(afe, id); 21662306a36Sopenharmony_ci if (ret) { 21762306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", 21862306a36Sopenharmony_ci __func__, id, ret); 21962306a36Sopenharmony_ci return ret; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* set irq counter */ 22362306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, 22462306a36Sopenharmony_ci irq_data->irq_cnt_maskbit, counter, 22562306a36Sopenharmony_ci irq_data->irq_cnt_shift); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* set irq fs */ 22862306a36Sopenharmony_ci fs = afe->irq_fs(substream, runtime->rate); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (fs < 0) 23162306a36Sopenharmony_ci return -EINVAL; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, 23462306a36Sopenharmony_ci irq_data->irq_fs_maskbit, fs, 23562306a36Sopenharmony_ci irq_data->irq_fs_shift); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* enable interrupt */ 23862306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 23962306a36Sopenharmony_ci 1, 1, irq_data->irq_en_shift); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 24362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 24462306a36Sopenharmony_ci ret = mtk_memif_set_disable(afe, id); 24562306a36Sopenharmony_ci if (ret) { 24662306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", 24762306a36Sopenharmony_ci __func__, id, ret); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* disable interrupt */ 25162306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 25262306a36Sopenharmony_ci 1, 0, irq_data->irq_en_shift); 25362306a36Sopenharmony_ci /* and clear pending IRQ */ 25462306a36Sopenharmony_ci mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, 25562306a36Sopenharmony_ci 1 << irq_data->irq_clr_shift); 25662306a36Sopenharmony_ci return ret; 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci return -EINVAL; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ciint mtk_afe_fe_prepare(struct snd_pcm_substream *substream, 26462306a36Sopenharmony_ci struct snd_soc_dai *dai) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 26762306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 26862306a36Sopenharmony_ci int id = asoc_rtd_to_cpu(rtd, 0)->id; 26962306a36Sopenharmony_ci int pbuf_size; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 27262306a36Sopenharmony_ci if (afe->get_memif_pbuf_size) { 27362306a36Sopenharmony_ci pbuf_size = afe->get_memif_pbuf_size(substream); 27462306a36Sopenharmony_ci mtk_memif_set_pbuf_size(afe, id, pbuf_size); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ciconst struct snd_soc_dai_ops mtk_afe_fe_ops = { 28262306a36Sopenharmony_ci .startup = mtk_afe_fe_startup, 28362306a36Sopenharmony_ci .shutdown = mtk_afe_fe_shutdown, 28462306a36Sopenharmony_ci .hw_params = mtk_afe_fe_hw_params, 28562306a36Sopenharmony_ci .hw_free = mtk_afe_fe_hw_free, 28662306a36Sopenharmony_ci .prepare = mtk_afe_fe_prepare, 28762306a36Sopenharmony_ci .trigger = mtk_afe_fe_trigger, 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_fe_ops); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ciint mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci int i; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci mutex_lock(&afe->irq_alloc_lock); 29662306a36Sopenharmony_ci for (i = 0; i < afe->irqs_size; ++i) { 29762306a36Sopenharmony_ci if (afe->irqs[i].irq_occupyed == 0) { 29862306a36Sopenharmony_ci afe->irqs[i].irq_occupyed = 1; 29962306a36Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 30062306a36Sopenharmony_ci return i; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 30462306a36Sopenharmony_ci return afe->irqs_size; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciint mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci mutex_lock(&afe->irq_alloc_lock); 31162306a36Sopenharmony_ci if (irq_id >= 0 && irq_id < afe->irqs_size) { 31262306a36Sopenharmony_ci afe->irqs[irq_id].irq_occupyed = 0; 31362306a36Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci mutex_unlock(&afe->irq_alloc_lock); 31762306a36Sopenharmony_ci return -EINVAL; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_dynamic_irq_release); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciint mtk_afe_suspend(struct snd_soc_component *component) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 32462306a36Sopenharmony_ci struct device *dev = afe->dev; 32562306a36Sopenharmony_ci struct regmap *regmap = afe->regmap; 32662306a36Sopenharmony_ci int i; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (pm_runtime_status_suspended(dev) || afe->suspended) 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!afe->reg_back_up) 33262306a36Sopenharmony_ci afe->reg_back_up = 33362306a36Sopenharmony_ci devm_kcalloc(dev, afe->reg_back_up_list_num, 33462306a36Sopenharmony_ci sizeof(unsigned int), GFP_KERNEL); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (afe->reg_back_up) { 33762306a36Sopenharmony_ci for (i = 0; i < afe->reg_back_up_list_num; i++) 33862306a36Sopenharmony_ci regmap_read(regmap, afe->reg_back_up_list[i], 33962306a36Sopenharmony_ci &afe->reg_back_up[i]); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci afe->suspended = true; 34362306a36Sopenharmony_ci afe->runtime_suspend(dev); 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_suspend); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ciint mtk_afe_resume(struct snd_soc_component *component) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 35162306a36Sopenharmony_ci struct device *dev = afe->dev; 35262306a36Sopenharmony_ci struct regmap *regmap = afe->regmap; 35362306a36Sopenharmony_ci int i; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (pm_runtime_status_suspended(dev) || !afe->suspended) 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci afe->runtime_resume(dev); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (!afe->reg_back_up) { 36162306a36Sopenharmony_ci dev_dbg(dev, "%s no reg_backup\n", __func__); 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci for (i = 0; i < afe->reg_back_up_list_num; i++) 36462306a36Sopenharmony_ci mtk_regmap_write(regmap, afe->reg_back_up_list[i], 36562306a36Sopenharmony_ci afe->reg_back_up[i]); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci afe->suspended = false; 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_resume); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ciint mtk_memif_set_enable(struct mtk_base_afe *afe, int id) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (memif->data->enable_shift < 0) { 37862306a36Sopenharmony_ci dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n", 37962306a36Sopenharmony_ci __func__, id); 38062306a36Sopenharmony_ci return 0; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 38362306a36Sopenharmony_ci 1, 1, memif->data->enable_shift); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_enable); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ciint mtk_memif_set_disable(struct mtk_base_afe *afe, int id) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (memif->data->enable_shift < 0) { 39262306a36Sopenharmony_ci dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n", 39362306a36Sopenharmony_ci __func__, id); 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 39762306a36Sopenharmony_ci 1, 0, memif->data->enable_shift); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_disable); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciint mtk_memif_set_addr(struct mtk_base_afe *afe, int id, 40262306a36Sopenharmony_ci unsigned char *dma_area, 40362306a36Sopenharmony_ci dma_addr_t dma_addr, 40462306a36Sopenharmony_ci size_t dma_bytes) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 40762306a36Sopenharmony_ci int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0; 40862306a36Sopenharmony_ci unsigned int phys_buf_addr = lower_32_bits(dma_addr); 40962306a36Sopenharmony_ci unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci memif->dma_area = dma_area; 41262306a36Sopenharmony_ci memif->dma_addr = dma_addr; 41362306a36Sopenharmony_ci memif->dma_bytes = dma_bytes; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* start */ 41662306a36Sopenharmony_ci mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base, 41762306a36Sopenharmony_ci phys_buf_addr); 41862306a36Sopenharmony_ci /* end */ 41962306a36Sopenharmony_ci if (memif->data->reg_ofs_end) 42062306a36Sopenharmony_ci mtk_regmap_write(afe->regmap, 42162306a36Sopenharmony_ci memif->data->reg_ofs_end, 42262306a36Sopenharmony_ci phys_buf_addr + dma_bytes - 1); 42362306a36Sopenharmony_ci else 42462306a36Sopenharmony_ci mtk_regmap_write(afe->regmap, 42562306a36Sopenharmony_ci memif->data->reg_ofs_base + 42662306a36Sopenharmony_ci AFE_BASE_END_OFFSET, 42762306a36Sopenharmony_ci phys_buf_addr + dma_bytes - 1); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* set start, end, upper 32 bits */ 43062306a36Sopenharmony_ci if (memif->data->reg_ofs_base_msb) { 43162306a36Sopenharmony_ci mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb, 43262306a36Sopenharmony_ci phys_buf_addr_upper_32); 43362306a36Sopenharmony_ci mtk_regmap_write(afe->regmap, 43462306a36Sopenharmony_ci memif->data->reg_ofs_end_msb, 43562306a36Sopenharmony_ci phys_buf_addr_upper_32); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * set MSB to 33-bit, for memif address 44062306a36Sopenharmony_ci * only for memif base address, if msb_end_reg exists 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (memif->data->msb_reg) 44362306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 44462306a36Sopenharmony_ci 1, msb_at_bit33, memif->data->msb_shift); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* set MSB to 33-bit, for memif end address */ 44762306a36Sopenharmony_ci if (memif->data->msb_end_reg) 44862306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->msb_end_reg, 44962306a36Sopenharmony_ci 1, msb_at_bit33, 45062306a36Sopenharmony_ci memif->data->msb_end_shift); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_addr); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ciint mtk_memif_set_channel(struct mtk_base_afe *afe, 45762306a36Sopenharmony_ci int id, unsigned int channel) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 46062306a36Sopenharmony_ci unsigned int mono; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (memif->data->mono_shift < 0) 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (memif->data->quad_ch_mask) { 46662306a36Sopenharmony_ci unsigned int quad_ch = (channel == 4) ? 1 : 0; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg, 46962306a36Sopenharmony_ci memif->data->quad_ch_mask, 47062306a36Sopenharmony_ci quad_ch, memif->data->quad_ch_shift); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (memif->data->mono_invert) 47462306a36Sopenharmony_ci mono = (channel == 1) ? 0 : 1; 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci mono = (channel == 1) ? 1 : 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* for specific configuration of memif mono mode */ 47962306a36Sopenharmony_ci if (memif->data->int_odd_flag_reg) 48062306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, 48162306a36Sopenharmony_ci memif->data->int_odd_flag_reg, 48262306a36Sopenharmony_ci 1, mono, 48362306a36Sopenharmony_ci memif->data->int_odd_flag_shift); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 48662306a36Sopenharmony_ci 1, mono, memif->data->mono_shift); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_channel); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int mtk_memif_set_rate_fs(struct mtk_base_afe *afe, 49162306a36Sopenharmony_ci int id, int fs) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (memif->data->fs_shift >= 0) 49662306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, 49762306a36Sopenharmony_ci memif->data->fs_maskbit, 49862306a36Sopenharmony_ci fs, memif->data->fs_shift); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciint mtk_memif_set_rate(struct mtk_base_afe *afe, 50462306a36Sopenharmony_ci int id, unsigned int rate) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int fs = 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!afe->get_dai_fs) { 50962306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n", 51062306a36Sopenharmony_ci __func__); 51162306a36Sopenharmony_ci return -EINVAL; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci fs = afe->get_dai_fs(afe, id, rate); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (fs < 0) 51762306a36Sopenharmony_ci return -EINVAL; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci return mtk_memif_set_rate_fs(afe, id, fs); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_rate); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciint mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, 52462306a36Sopenharmony_ci int id, unsigned int rate) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 52762306a36Sopenharmony_ci struct snd_soc_component *component = 52862306a36Sopenharmony_ci snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 52962306a36Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci int fs = 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (!afe->memif_fs) { 53462306a36Sopenharmony_ci dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n", 53562306a36Sopenharmony_ci __func__); 53662306a36Sopenharmony_ci return -EINVAL; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci fs = afe->memif_fs(substream, rate); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (fs < 0) 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return mtk_memif_set_rate_fs(afe, id, fs); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ciint mtk_memif_set_format(struct mtk_base_afe *afe, 54962306a36Sopenharmony_ci int id, snd_pcm_format_t format) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[id]; 55262306a36Sopenharmony_ci int hd_audio = 0; 55362306a36Sopenharmony_ci int hd_align = 0; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* set hd mode */ 55662306a36Sopenharmony_ci switch (format) { 55762306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 55862306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U16_LE: 55962306a36Sopenharmony_ci hd_audio = 0; 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 56262306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U32_LE: 56362306a36Sopenharmony_ci if (afe->memif_32bit_supported) { 56462306a36Sopenharmony_ci hd_audio = 2; 56562306a36Sopenharmony_ci hd_align = 0; 56662306a36Sopenharmony_ci } else { 56762306a36Sopenharmony_ci hd_audio = 1; 56862306a36Sopenharmony_ci hd_align = 1; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 57262306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_LE: 57362306a36Sopenharmony_ci hd_audio = 1; 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci default: 57662306a36Sopenharmony_ci dev_err(afe->dev, "%s() error: unsupported format %d\n", 57762306a36Sopenharmony_ci __func__, format); 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 58262306a36Sopenharmony_ci 0x3, hd_audio, memif->data->hd_shift); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, 58562306a36Sopenharmony_ci 0x1, hd_align, memif->data->hd_align_mshift); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return 0; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_format); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ciint mtk_memif_set_pbuf_size(struct mtk_base_afe *afe, 59262306a36Sopenharmony_ci int id, int pbuf_size) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci const struct mtk_base_memif_data *memif_data = afe->memif[id].data; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0) 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg, 60062306a36Sopenharmony_ci memif_data->pbuf_mask, 60162306a36Sopenharmony_ci pbuf_size, memif_data->pbuf_shift); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg, 60462306a36Sopenharmony_ci memif_data->minlen_mask, 60562306a36Sopenharmony_ci pbuf_size, memif_data->minlen_shift); 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ciMODULE_DESCRIPTION("Mediatek simple fe dai operator"); 61162306a36Sopenharmony_ciMODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 61262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 613