13a280ed1SRyder Lee // SPDX-License-Identifier: GPL-2.0 2283b6124SGarlic Tseng /* 3283b6124SGarlic Tseng * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator 4283b6124SGarlic Tseng * 5283b6124SGarlic Tseng * Copyright (c) 2016 MediaTek Inc. 6283b6124SGarlic Tseng * Author: Garlic Tseng <garlic.tseng@mediatek.com> 7283b6124SGarlic Tseng */ 8283b6124SGarlic Tseng 9df799b95SEason Yen #include <linux/io.h> 10283b6124SGarlic Tseng #include <linux/module.h> 11283b6124SGarlic Tseng #include <linux/pm_runtime.h> 12283b6124SGarlic Tseng #include <linux/regmap.h> 13283b6124SGarlic Tseng #include <sound/soc.h> 14f1b5bf07SKuninori Morimoto #include "mtk-afe-platform-driver.h" 15df799b95SEason Yen #include <sound/pcm_params.h> 16283b6124SGarlic Tseng #include "mtk-afe-fe-dai.h" 17283b6124SGarlic Tseng #include "mtk-base-afe.h" 18283b6124SGarlic Tseng 19283b6124SGarlic Tseng #define AFE_BASE_END_OFFSET 8 20283b6124SGarlic Tseng 2122e76614SBaoyou Xie static int mtk_regmap_update_bits(struct regmap *map, int reg, 2222e76614SBaoyou Xie unsigned int mask, 23c6839641SPi-Hsun Shih unsigned int val, int shift) 24283b6124SGarlic Tseng { 25c6839641SPi-Hsun Shih if (reg < 0 || WARN_ON_ONCE(shift < 0)) 26283b6124SGarlic Tseng return 0; 27c6839641SPi-Hsun Shih return regmap_update_bits(map, reg, mask << shift, val << shift); 28283b6124SGarlic Tseng } 29283b6124SGarlic Tseng 3022e76614SBaoyou Xie static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) 31283b6124SGarlic Tseng { 32283b6124SGarlic Tseng if (reg < 0) 33283b6124SGarlic Tseng return 0; 34283b6124SGarlic Tseng return regmap_write(map, reg, val); 35283b6124SGarlic Tseng } 36283b6124SGarlic Tseng 37283b6124SGarlic Tseng int mtk_afe_fe_startup(struct snd_pcm_substream *substream, 38283b6124SGarlic Tseng struct snd_soc_dai *dai) 39283b6124SGarlic Tseng { 400cd08b10SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 41e4b31b81SRyder Lee struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 42283b6124SGarlic Tseng struct snd_pcm_runtime *runtime = substream->runtime; 43c8ac8212SKuninori Morimoto int memif_num = asoc_rtd_to_cpu(rtd, 0)->id; 44283b6124SGarlic Tseng struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; 45283b6124SGarlic Tseng const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; 46283b6124SGarlic Tseng int ret; 47283b6124SGarlic Tseng 48283b6124SGarlic Tseng memif->substream = substream; 49283b6124SGarlic Tseng 50283b6124SGarlic Tseng snd_pcm_hw_constraint_step(substream->runtime, 0, 51283b6124SGarlic Tseng SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); 52283b6124SGarlic Tseng /* enable agent */ 53283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 54c6839641SPi-Hsun Shih 1, 0, memif->data->agent_disable_shift); 55283b6124SGarlic Tseng 56283b6124SGarlic Tseng snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); 57283b6124SGarlic Tseng 58283b6124SGarlic Tseng /* 59283b6124SGarlic Tseng * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be 60283b6124SGarlic Tseng * smaller than period_size due to AFE's internal buffer. 61283b6124SGarlic Tseng * This easily leads to overrun when avail_min is period_size. 62283b6124SGarlic Tseng * One more period can hold the possible unread buffer. 63283b6124SGarlic Tseng */ 64283b6124SGarlic Tseng if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 65283b6124SGarlic Tseng int periods_max = mtk_afe_hardware->periods_max; 66283b6124SGarlic Tseng 67283b6124SGarlic Tseng ret = snd_pcm_hw_constraint_minmax(runtime, 68283b6124SGarlic Tseng SNDRV_PCM_HW_PARAM_PERIODS, 69283b6124SGarlic Tseng 3, periods_max); 70283b6124SGarlic Tseng if (ret < 0) { 71283b6124SGarlic Tseng dev_err(afe->dev, "hw_constraint_minmax failed\n"); 72283b6124SGarlic Tseng return ret; 73283b6124SGarlic Tseng } 74283b6124SGarlic Tseng } 75283b6124SGarlic Tseng 76283b6124SGarlic Tseng ret = snd_pcm_hw_constraint_integer(runtime, 77283b6124SGarlic Tseng SNDRV_PCM_HW_PARAM_PERIODS); 78283b6124SGarlic Tseng if (ret < 0) 79283b6124SGarlic Tseng dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); 80283b6124SGarlic Tseng 81283b6124SGarlic Tseng /* dynamic allocate irq to memif */ 82283b6124SGarlic Tseng if (memif->irq_usage < 0) { 83283b6124SGarlic Tseng int irq_id = mtk_dynamic_irq_acquire(afe); 84283b6124SGarlic Tseng 85283b6124SGarlic Tseng if (irq_id != afe->irqs_size) { 86283b6124SGarlic Tseng /* link */ 87283b6124SGarlic Tseng memif->irq_usage = irq_id; 88283b6124SGarlic Tseng } else { 89283b6124SGarlic Tseng dev_err(afe->dev, "%s() error: no more asys irq\n", 90283b6124SGarlic Tseng __func__); 91283b6124SGarlic Tseng ret = -EBUSY; 92283b6124SGarlic Tseng } 93283b6124SGarlic Tseng } 94283b6124SGarlic Tseng return ret; 95283b6124SGarlic Tseng } 96283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_startup); 97283b6124SGarlic Tseng 98283b6124SGarlic Tseng void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, 99283b6124SGarlic Tseng struct snd_soc_dai *dai) 100283b6124SGarlic Tseng { 1010cd08b10SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 102e4b31b81SRyder Lee struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 103c8ac8212SKuninori Morimoto struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; 104283b6124SGarlic Tseng int irq_id; 105283b6124SGarlic Tseng 106283b6124SGarlic Tseng irq_id = memif->irq_usage; 107283b6124SGarlic Tseng 108283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 109c6839641SPi-Hsun Shih 1, 1, memif->data->agent_disable_shift); 110283b6124SGarlic Tseng 111283b6124SGarlic Tseng if (!memif->const_irq) { 112283b6124SGarlic Tseng mtk_dynamic_irq_release(afe, irq_id); 113283b6124SGarlic Tseng memif->irq_usage = -1; 114283b6124SGarlic Tseng memif->substream = NULL; 115283b6124SGarlic Tseng } 116283b6124SGarlic Tseng } 117283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown); 118283b6124SGarlic Tseng 119283b6124SGarlic Tseng int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, 120283b6124SGarlic Tseng struct snd_pcm_hw_params *params, 121283b6124SGarlic Tseng struct snd_soc_dai *dai) 122283b6124SGarlic Tseng { 1230cd08b10SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 124e4b31b81SRyder Lee struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 125c8ac8212SKuninori Morimoto int id = asoc_rtd_to_cpu(rtd, 0)->id; 126df799b95SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 127df799b95SEason Yen int ret; 128df799b95SEason Yen unsigned int channels = params_channels(params); 129df799b95SEason Yen unsigned int rate = params_rate(params); 130df799b95SEason Yen snd_pcm_format_t format = params_format(params); 131283b6124SGarlic Tseng 132df799b95SEason Yen if (afe->request_dram_resource) 133df799b95SEason Yen afe->request_dram_resource(afe->dev); 134283b6124SGarlic Tseng 135df799b95SEason Yen dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n", 136df799b95SEason Yen __func__, memif->data->name, 137df799b95SEason Yen channels, rate, format, 138df799b95SEason Yen &substream->runtime->dma_addr, 139df799b95SEason Yen substream->runtime->dma_area, 140df799b95SEason Yen substream->runtime->dma_bytes); 141283b6124SGarlic Tseng 142cab2b9e5STrevor Wu memset_io((void __force __iomem *)substream->runtime->dma_area, 0, 143df799b95SEason Yen substream->runtime->dma_bytes); 144df799b95SEason Yen 145df799b95SEason Yen /* set addr */ 146df799b95SEason Yen ret = mtk_memif_set_addr(afe, id, 147df799b95SEason Yen substream->runtime->dma_area, 148df799b95SEason Yen substream->runtime->dma_addr, 149df799b95SEason Yen substream->runtime->dma_bytes); 150df799b95SEason Yen if (ret) { 151df799b95SEason Yen dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n", 152df799b95SEason Yen __func__, id, ret); 153df799b95SEason Yen return ret; 154df799b95SEason Yen } 155283b6124SGarlic Tseng 156283b6124SGarlic Tseng /* set channel */ 157df799b95SEason Yen ret = mtk_memif_set_channel(afe, id, channels); 158df799b95SEason Yen if (ret) { 159df799b95SEason Yen dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n", 160df799b95SEason Yen __func__, id, channels, ret); 161df799b95SEason Yen return ret; 162283b6124SGarlic Tseng } 163283b6124SGarlic Tseng 164283b6124SGarlic Tseng /* set rate */ 165df799b95SEason Yen ret = mtk_memif_set_rate_substream(substream, id, rate); 166df799b95SEason Yen if (ret) { 167df799b95SEason Yen dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n", 168df799b95SEason Yen __func__, id, rate, ret); 169df799b95SEason Yen return ret; 170df799b95SEason Yen } 171283b6124SGarlic Tseng 172df799b95SEason Yen /* set format */ 173df799b95SEason Yen ret = mtk_memif_set_format(afe, id, format); 174df799b95SEason Yen if (ret) { 175df799b95SEason Yen dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n", 176df799b95SEason Yen __func__, id, format, ret); 177df799b95SEason Yen return ret; 178df799b95SEason Yen } 179283b6124SGarlic Tseng 180283b6124SGarlic Tseng return 0; 181283b6124SGarlic Tseng } 182283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params); 183283b6124SGarlic Tseng 184283b6124SGarlic Tseng int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, 185283b6124SGarlic Tseng struct snd_soc_dai *dai) 186283b6124SGarlic Tseng { 187df799b95SEason Yen struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 188df799b95SEason Yen 189df799b95SEason Yen if (afe->release_dram_resource) 190df799b95SEason Yen afe->release_dram_resource(afe->dev); 191df799b95SEason Yen 192bf523463STakashi Iwai return 0; 193283b6124SGarlic Tseng } 194283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); 195283b6124SGarlic Tseng 196283b6124SGarlic Tseng int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, 197283b6124SGarlic Tseng struct snd_soc_dai *dai) 198283b6124SGarlic Tseng { 1990cd08b10SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 200283b6124SGarlic Tseng struct snd_pcm_runtime * const runtime = substream->runtime; 201e4b31b81SRyder Lee struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 202c8ac8212SKuninori Morimoto int id = asoc_rtd_to_cpu(rtd, 0)->id; 203df799b95SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 204283b6124SGarlic Tseng struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; 205283b6124SGarlic Tseng const struct mtk_base_irq_data *irq_data = irqs->irq_data; 206283b6124SGarlic Tseng unsigned int counter = runtime->period_size; 207283b6124SGarlic Tseng int fs; 208df799b95SEason Yen int ret; 209283b6124SGarlic Tseng 210283b6124SGarlic Tseng dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); 211283b6124SGarlic Tseng 212283b6124SGarlic Tseng switch (cmd) { 213283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_START: 214283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_RESUME: 215df799b95SEason Yen ret = mtk_memif_set_enable(afe, id); 216df799b95SEason Yen if (ret) { 217df799b95SEason Yen dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", 218df799b95SEason Yen __func__, id, ret); 219df799b95SEason Yen return ret; 220df799b95SEason Yen } 221283b6124SGarlic Tseng 222283b6124SGarlic Tseng /* set irq counter */ 223283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, 224c6839641SPi-Hsun Shih irq_data->irq_cnt_maskbit, counter, 225c6839641SPi-Hsun Shih irq_data->irq_cnt_shift); 226283b6124SGarlic Tseng 227283b6124SGarlic Tseng /* set irq fs */ 228283b6124SGarlic Tseng fs = afe->irq_fs(substream, runtime->rate); 229283b6124SGarlic Tseng 230283b6124SGarlic Tseng if (fs < 0) 231283b6124SGarlic Tseng return -EINVAL; 232283b6124SGarlic Tseng 233283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, 234c6839641SPi-Hsun Shih irq_data->irq_fs_maskbit, fs, 235c6839641SPi-Hsun Shih irq_data->irq_fs_shift); 236283b6124SGarlic Tseng 237283b6124SGarlic Tseng /* enable interrupt */ 238283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 239c6839641SPi-Hsun Shih 1, 1, irq_data->irq_en_shift); 240283b6124SGarlic Tseng 241283b6124SGarlic Tseng return 0; 242283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_STOP: 243283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_SUSPEND: 244df799b95SEason Yen ret = mtk_memif_set_disable(afe, id); 245df799b95SEason Yen if (ret) { 246df799b95SEason Yen dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", 247df799b95SEason Yen __func__, id, ret); 248df799b95SEason Yen } 249df799b95SEason Yen 250283b6124SGarlic Tseng /* disable interrupt */ 251283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 252c6839641SPi-Hsun Shih 1, 0, irq_data->irq_en_shift); 253283b6124SGarlic Tseng /* and clear pending IRQ */ 254283b6124SGarlic Tseng mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, 255283b6124SGarlic Tseng 1 << irq_data->irq_clr_shift); 256df799b95SEason Yen return ret; 257283b6124SGarlic Tseng default: 258283b6124SGarlic Tseng return -EINVAL; 259283b6124SGarlic Tseng } 260283b6124SGarlic Tseng } 261283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); 262283b6124SGarlic Tseng 263283b6124SGarlic Tseng int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, 264283b6124SGarlic Tseng struct snd_soc_dai *dai) 265283b6124SGarlic Tseng { 2660cd08b10SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 267e4b31b81SRyder Lee struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 268c8ac8212SKuninori Morimoto int id = asoc_rtd_to_cpu(rtd, 0)->id; 269df799b95SEason Yen int pbuf_size; 270283b6124SGarlic Tseng 271df799b95SEason Yen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 272df799b95SEason Yen if (afe->get_memif_pbuf_size) { 273df799b95SEason Yen pbuf_size = afe->get_memif_pbuf_size(substream); 274df799b95SEason Yen mtk_memif_set_pbuf_size(afe, id, pbuf_size); 275283b6124SGarlic Tseng } 276df799b95SEason Yen } 277283b6124SGarlic Tseng return 0; 278283b6124SGarlic Tseng } 279283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); 280283b6124SGarlic Tseng 281283b6124SGarlic Tseng const struct snd_soc_dai_ops mtk_afe_fe_ops = { 282283b6124SGarlic Tseng .startup = mtk_afe_fe_startup, 283283b6124SGarlic Tseng .shutdown = mtk_afe_fe_shutdown, 284283b6124SGarlic Tseng .hw_params = mtk_afe_fe_hw_params, 285283b6124SGarlic Tseng .hw_free = mtk_afe_fe_hw_free, 286283b6124SGarlic Tseng .prepare = mtk_afe_fe_prepare, 287283b6124SGarlic Tseng .trigger = mtk_afe_fe_trigger, 288283b6124SGarlic Tseng }; 289283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); 290283b6124SGarlic Tseng 291283b6124SGarlic Tseng static DEFINE_MUTEX(irqs_lock); 292283b6124SGarlic Tseng int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) 293283b6124SGarlic Tseng { 294283b6124SGarlic Tseng int i; 295283b6124SGarlic Tseng 296283b6124SGarlic Tseng mutex_lock(&afe->irq_alloc_lock); 297283b6124SGarlic Tseng for (i = 0; i < afe->irqs_size; ++i) { 298283b6124SGarlic Tseng if (afe->irqs[i].irq_occupyed == 0) { 299283b6124SGarlic Tseng afe->irqs[i].irq_occupyed = 1; 300283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 301283b6124SGarlic Tseng return i; 302283b6124SGarlic Tseng } 303283b6124SGarlic Tseng } 304283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 305283b6124SGarlic Tseng return afe->irqs_size; 306283b6124SGarlic Tseng } 307283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire); 308283b6124SGarlic Tseng 309283b6124SGarlic Tseng int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id) 310283b6124SGarlic Tseng { 311283b6124SGarlic Tseng mutex_lock(&afe->irq_alloc_lock); 312283b6124SGarlic Tseng if (irq_id >= 0 && irq_id < afe->irqs_size) { 313283b6124SGarlic Tseng afe->irqs[irq_id].irq_occupyed = 0; 314283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 315283b6124SGarlic Tseng return 0; 316283b6124SGarlic Tseng } 317283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 318283b6124SGarlic Tseng return -EINVAL; 319283b6124SGarlic Tseng } 320283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release); 321283b6124SGarlic Tseng 3227ec6b431SKuninori Morimoto int mtk_afe_suspend(struct snd_soc_component *component) 323283b6124SGarlic Tseng { 3247ec6b431SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 325283b6124SGarlic Tseng struct device *dev = afe->dev; 326283b6124SGarlic Tseng struct regmap *regmap = afe->regmap; 327283b6124SGarlic Tseng int i; 328283b6124SGarlic Tseng 329283b6124SGarlic Tseng if (pm_runtime_status_suspended(dev) || afe->suspended) 330283b6124SGarlic Tseng return 0; 331283b6124SGarlic Tseng 332283b6124SGarlic Tseng if (!afe->reg_back_up) 333283b6124SGarlic Tseng afe->reg_back_up = 334283b6124SGarlic Tseng devm_kcalloc(dev, afe->reg_back_up_list_num, 335283b6124SGarlic Tseng sizeof(unsigned int), GFP_KERNEL); 336283b6124SGarlic Tseng 337*1dd03852STrevor Wu if (afe->reg_back_up) { 338283b6124SGarlic Tseng for (i = 0; i < afe->reg_back_up_list_num; i++) 339283b6124SGarlic Tseng regmap_read(regmap, afe->reg_back_up_list[i], 340283b6124SGarlic Tseng &afe->reg_back_up[i]); 341*1dd03852STrevor Wu } 342283b6124SGarlic Tseng 343283b6124SGarlic Tseng afe->suspended = true; 344283b6124SGarlic Tseng afe->runtime_suspend(dev); 345283b6124SGarlic Tseng return 0; 346283b6124SGarlic Tseng } 3477ec6b431SKuninori Morimoto EXPORT_SYMBOL_GPL(mtk_afe_suspend); 348283b6124SGarlic Tseng 3497ec6b431SKuninori Morimoto int mtk_afe_resume(struct snd_soc_component *component) 350283b6124SGarlic Tseng { 3517ec6b431SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 352283b6124SGarlic Tseng struct device *dev = afe->dev; 353283b6124SGarlic Tseng struct regmap *regmap = afe->regmap; 354283b6124SGarlic Tseng int i = 0; 355283b6124SGarlic Tseng 356283b6124SGarlic Tseng if (pm_runtime_status_suspended(dev) || !afe->suspended) 357283b6124SGarlic Tseng return 0; 358283b6124SGarlic Tseng 359283b6124SGarlic Tseng afe->runtime_resume(dev); 360283b6124SGarlic Tseng 361*1dd03852STrevor Wu if (!afe->reg_back_up) { 362283b6124SGarlic Tseng dev_dbg(dev, "%s no reg_backup\n", __func__); 363*1dd03852STrevor Wu } else { 364283b6124SGarlic Tseng for (i = 0; i < afe->reg_back_up_list_num; i++) 365283b6124SGarlic Tseng mtk_regmap_write(regmap, afe->reg_back_up_list[i], 366283b6124SGarlic Tseng afe->reg_back_up[i]); 367*1dd03852STrevor Wu } 368283b6124SGarlic Tseng 369283b6124SGarlic Tseng afe->suspended = false; 370283b6124SGarlic Tseng return 0; 371283b6124SGarlic Tseng } 3727ec6b431SKuninori Morimoto EXPORT_SYMBOL_GPL(mtk_afe_resume); 373283b6124SGarlic Tseng 3749cdf85a1SEason Yen int mtk_memif_set_enable(struct mtk_base_afe *afe, int id) 3759cdf85a1SEason Yen { 3769cdf85a1SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 3779cdf85a1SEason Yen 3789cdf85a1SEason Yen if (memif->data->enable_shift < 0) { 3799cdf85a1SEason Yen dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n", 3809cdf85a1SEason Yen __func__, id); 3819cdf85a1SEason Yen return 0; 3829cdf85a1SEason Yen } 3839cdf85a1SEason Yen return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 3849cdf85a1SEason Yen 1, 1, memif->data->enable_shift); 3859cdf85a1SEason Yen } 3869cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_enable); 3879cdf85a1SEason Yen 3889cdf85a1SEason Yen int mtk_memif_set_disable(struct mtk_base_afe *afe, int id) 3899cdf85a1SEason Yen { 3909cdf85a1SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 3919cdf85a1SEason Yen 3929cdf85a1SEason Yen if (memif->data->enable_shift < 0) { 3939cdf85a1SEason Yen dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n", 3949cdf85a1SEason Yen __func__, id); 3959cdf85a1SEason Yen return 0; 3969cdf85a1SEason Yen } 3979cdf85a1SEason Yen return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 3989cdf85a1SEason Yen 1, 0, memif->data->enable_shift); 3999cdf85a1SEason Yen } 4009cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_disable); 4019cdf85a1SEason Yen 4029cdf85a1SEason Yen int mtk_memif_set_addr(struct mtk_base_afe *afe, int id, 4039cdf85a1SEason Yen unsigned char *dma_area, 4049cdf85a1SEason Yen dma_addr_t dma_addr, 4059cdf85a1SEason Yen size_t dma_bytes) 4069cdf85a1SEason Yen { 4079cdf85a1SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 4089cdf85a1SEason Yen int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0; 4099cdf85a1SEason Yen unsigned int phys_buf_addr = lower_32_bits(dma_addr); 4109cdf85a1SEason Yen unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr); 4119cdf85a1SEason Yen 4129cdf85a1SEason Yen memif->dma_area = dma_area; 4139cdf85a1SEason Yen memif->dma_addr = dma_addr; 4149cdf85a1SEason Yen memif->dma_bytes = dma_bytes; 4159cdf85a1SEason Yen 4169cdf85a1SEason Yen /* start */ 4179cdf85a1SEason Yen mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base, 4189cdf85a1SEason Yen phys_buf_addr); 4199cdf85a1SEason Yen /* end */ 4209cdf85a1SEason Yen if (memif->data->reg_ofs_end) 4219cdf85a1SEason Yen mtk_regmap_write(afe->regmap, 4229cdf85a1SEason Yen memif->data->reg_ofs_end, 4239cdf85a1SEason Yen phys_buf_addr + dma_bytes - 1); 4249cdf85a1SEason Yen else 4259cdf85a1SEason Yen mtk_regmap_write(afe->regmap, 4269cdf85a1SEason Yen memif->data->reg_ofs_base + 4279cdf85a1SEason Yen AFE_BASE_END_OFFSET, 4289cdf85a1SEason Yen phys_buf_addr + dma_bytes - 1); 4299cdf85a1SEason Yen 4309cdf85a1SEason Yen /* set start, end, upper 32 bits */ 4319cdf85a1SEason Yen if (memif->data->reg_ofs_base_msb) { 4329cdf85a1SEason Yen mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb, 4339cdf85a1SEason Yen phys_buf_addr_upper_32); 4349cdf85a1SEason Yen mtk_regmap_write(afe->regmap, 4359cdf85a1SEason Yen memif->data->reg_ofs_end_msb, 4369cdf85a1SEason Yen phys_buf_addr_upper_32); 4379cdf85a1SEason Yen } 4389cdf85a1SEason Yen 439cab2b9e5STrevor Wu /* 440cab2b9e5STrevor Wu * set MSB to 33-bit, for memif address 441cab2b9e5STrevor Wu * only for memif base address, if msb_end_reg exists 442cab2b9e5STrevor Wu */ 443cab2b9e5STrevor Wu if (memif->data->msb_reg) 4449cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 4459cdf85a1SEason Yen 1, msb_at_bit33, memif->data->msb_shift); 4469cdf85a1SEason Yen 447cab2b9e5STrevor Wu /* set MSB to 33-bit, for memif end address */ 448cab2b9e5STrevor Wu if (memif->data->msb_end_reg) 449cab2b9e5STrevor Wu mtk_regmap_update_bits(afe->regmap, memif->data->msb_end_reg, 450cab2b9e5STrevor Wu 1, msb_at_bit33, 451cab2b9e5STrevor Wu memif->data->msb_end_shift); 452cab2b9e5STrevor Wu 4539cdf85a1SEason Yen return 0; 4549cdf85a1SEason Yen } 4559cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_addr); 4569cdf85a1SEason Yen 4579cdf85a1SEason Yen int mtk_memif_set_channel(struct mtk_base_afe *afe, 4589cdf85a1SEason Yen int id, unsigned int channel) 4599cdf85a1SEason Yen { 4609cdf85a1SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 4619cdf85a1SEason Yen unsigned int mono; 4629cdf85a1SEason Yen 4639cdf85a1SEason Yen if (memif->data->mono_shift < 0) 4649cdf85a1SEason Yen return 0; 4659cdf85a1SEason Yen 4669cdf85a1SEason Yen if (memif->data->quad_ch_mask) { 4679cdf85a1SEason Yen unsigned int quad_ch = (channel == 4) ? 1 : 0; 4689cdf85a1SEason Yen 4699cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg, 4709cdf85a1SEason Yen memif->data->quad_ch_mask, 4719cdf85a1SEason Yen quad_ch, memif->data->quad_ch_shift); 4729cdf85a1SEason Yen } 4739cdf85a1SEason Yen 4749cdf85a1SEason Yen if (memif->data->mono_invert) 4759cdf85a1SEason Yen mono = (channel == 1) ? 0 : 1; 4769cdf85a1SEason Yen else 4779cdf85a1SEason Yen mono = (channel == 1) ? 1 : 0; 4789cdf85a1SEason Yen 479cab2b9e5STrevor Wu /* for specific configuration of memif mono mode */ 480cab2b9e5STrevor Wu if (memif->data->int_odd_flag_reg) 481cab2b9e5STrevor Wu mtk_regmap_update_bits(afe->regmap, 482cab2b9e5STrevor Wu memif->data->int_odd_flag_reg, 483cab2b9e5STrevor Wu 1, mono, 484cab2b9e5STrevor Wu memif->data->int_odd_flag_shift); 485cab2b9e5STrevor Wu 4869cdf85a1SEason Yen return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 4879cdf85a1SEason Yen 1, mono, memif->data->mono_shift); 4889cdf85a1SEason Yen } 4899cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_channel); 4909cdf85a1SEason Yen 4919cdf85a1SEason Yen static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe, 4929cdf85a1SEason Yen int id, int fs) 4939cdf85a1SEason Yen { 4949cdf85a1SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 4959cdf85a1SEason Yen 4969cdf85a1SEason Yen if (memif->data->fs_shift >= 0) 4979cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, 4989cdf85a1SEason Yen memif->data->fs_maskbit, 4999cdf85a1SEason Yen fs, memif->data->fs_shift); 5009cdf85a1SEason Yen 5019cdf85a1SEason Yen return 0; 5029cdf85a1SEason Yen } 5039cdf85a1SEason Yen 5049cdf85a1SEason Yen int mtk_memif_set_rate(struct mtk_base_afe *afe, 5059cdf85a1SEason Yen int id, unsigned int rate) 5069cdf85a1SEason Yen { 5079cdf85a1SEason Yen int fs = 0; 5089cdf85a1SEason Yen 5099cdf85a1SEason Yen if (!afe->get_dai_fs) { 5109cdf85a1SEason Yen dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n", 5119cdf85a1SEason Yen __func__); 5129cdf85a1SEason Yen return -EINVAL; 5139cdf85a1SEason Yen } 5149cdf85a1SEason Yen 5159cdf85a1SEason Yen fs = afe->get_dai_fs(afe, id, rate); 5169cdf85a1SEason Yen 5179cdf85a1SEason Yen if (fs < 0) 5189cdf85a1SEason Yen return -EINVAL; 5199cdf85a1SEason Yen 5209cdf85a1SEason Yen return mtk_memif_set_rate_fs(afe, id, fs); 5219cdf85a1SEason Yen } 5229cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_rate); 5239cdf85a1SEason Yen 5249cdf85a1SEason Yen int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, 5259cdf85a1SEason Yen int id, unsigned int rate) 5269cdf85a1SEason Yen { 5270cd08b10SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 5289cdf85a1SEason Yen struct snd_soc_component *component = 5299cdf85a1SEason Yen snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 5309cdf85a1SEason Yen struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 5319cdf85a1SEason Yen 5329cdf85a1SEason Yen int fs = 0; 5339cdf85a1SEason Yen 5349cdf85a1SEason Yen if (!afe->memif_fs) { 5359cdf85a1SEason Yen dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n", 5369cdf85a1SEason Yen __func__); 5379cdf85a1SEason Yen return -EINVAL; 5389cdf85a1SEason Yen } 5399cdf85a1SEason Yen 5409cdf85a1SEason Yen fs = afe->memif_fs(substream, rate); 5419cdf85a1SEason Yen 5429cdf85a1SEason Yen if (fs < 0) 5439cdf85a1SEason Yen return -EINVAL; 5449cdf85a1SEason Yen 5459cdf85a1SEason Yen return mtk_memif_set_rate_fs(afe, id, fs); 5469cdf85a1SEason Yen } 5479cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream); 5489cdf85a1SEason Yen 5499cdf85a1SEason Yen int mtk_memif_set_format(struct mtk_base_afe *afe, 5509cdf85a1SEason Yen int id, snd_pcm_format_t format) 5519cdf85a1SEason Yen { 5529cdf85a1SEason Yen struct mtk_base_afe_memif *memif = &afe->memif[id]; 5539cdf85a1SEason Yen int hd_audio = 0; 5549cdf85a1SEason Yen int hd_align = 0; 5559cdf85a1SEason Yen 5569cdf85a1SEason Yen /* set hd mode */ 5579cdf85a1SEason Yen switch (format) { 5589cdf85a1SEason Yen case SNDRV_PCM_FORMAT_S16_LE: 5599cdf85a1SEason Yen case SNDRV_PCM_FORMAT_U16_LE: 5609cdf85a1SEason Yen hd_audio = 0; 5619cdf85a1SEason Yen break; 5629cdf85a1SEason Yen case SNDRV_PCM_FORMAT_S32_LE: 5639cdf85a1SEason Yen case SNDRV_PCM_FORMAT_U32_LE: 564125ab5d5SJiaxin Yu if (afe->memif_32bit_supported) { 565125ab5d5SJiaxin Yu hd_audio = 2; 566125ab5d5SJiaxin Yu hd_align = 0; 567125ab5d5SJiaxin Yu } else { 5689cdf85a1SEason Yen hd_audio = 1; 5699cdf85a1SEason Yen hd_align = 1; 570125ab5d5SJiaxin Yu } 5719cdf85a1SEason Yen break; 5729cdf85a1SEason Yen case SNDRV_PCM_FORMAT_S24_LE: 5739cdf85a1SEason Yen case SNDRV_PCM_FORMAT_U24_LE: 5749cdf85a1SEason Yen hd_audio = 1; 5759cdf85a1SEason Yen break; 5769cdf85a1SEason Yen default: 5779cdf85a1SEason Yen dev_err(afe->dev, "%s() error: unsupported format %d\n", 5789cdf85a1SEason Yen __func__, format); 5799cdf85a1SEason Yen break; 5809cdf85a1SEason Yen } 5819cdf85a1SEason Yen 5829cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 583125ab5d5SJiaxin Yu 0x3, hd_audio, memif->data->hd_shift); 5849cdf85a1SEason Yen 5859cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, 586125ab5d5SJiaxin Yu 0x1, hd_align, memif->data->hd_align_mshift); 5879cdf85a1SEason Yen 5889cdf85a1SEason Yen return 0; 5899cdf85a1SEason Yen } 5909cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_format); 5919cdf85a1SEason Yen 5929cdf85a1SEason Yen int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe, 5939cdf85a1SEason Yen int id, int pbuf_size) 5949cdf85a1SEason Yen { 5959cdf85a1SEason Yen const struct mtk_base_memif_data *memif_data = afe->memif[id].data; 5969cdf85a1SEason Yen 5979cdf85a1SEason Yen if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0) 5989cdf85a1SEason Yen return 0; 5999cdf85a1SEason Yen 6009cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg, 6019cdf85a1SEason Yen memif_data->pbuf_mask, 6029cdf85a1SEason Yen pbuf_size, memif_data->pbuf_shift); 6039cdf85a1SEason Yen 6049cdf85a1SEason Yen mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg, 6059cdf85a1SEason Yen memif_data->minlen_mask, 6069cdf85a1SEason Yen pbuf_size, memif_data->minlen_shift); 6079cdf85a1SEason Yen return 0; 6089cdf85a1SEason Yen } 6099cdf85a1SEason Yen EXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size); 6109cdf85a1SEason Yen 611283b6124SGarlic Tseng MODULE_DESCRIPTION("Mediatek simple fe dai operator"); 612283b6124SGarlic Tseng MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 613283b6124SGarlic Tseng MODULE_LICENSE("GPL v2"); 614