1283b6124SGarlic Tseng /* 2283b6124SGarlic Tseng * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator 3283b6124SGarlic Tseng * 4283b6124SGarlic Tseng * Copyright (c) 2016 MediaTek Inc. 5283b6124SGarlic Tseng * Author: Garlic Tseng <garlic.tseng@mediatek.com> 6283b6124SGarlic Tseng * 7283b6124SGarlic Tseng * This program is free software; you can redistribute it and/or modify 8283b6124SGarlic Tseng * it under the terms of the GNU General Public License version 2 and 9283b6124SGarlic Tseng * only version 2 as published by the Free Software Foundation. 10283b6124SGarlic Tseng * 11283b6124SGarlic Tseng * This program is distributed in the hope that it will be useful, 12283b6124SGarlic Tseng * but WITHOUT ANY WARRANTY; without even the implied warranty of 13283b6124SGarlic Tseng * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14283b6124SGarlic Tseng * GNU General Public License for more details. 15283b6124SGarlic Tseng */ 16283b6124SGarlic Tseng 17283b6124SGarlic Tseng #include <linux/module.h> 18283b6124SGarlic Tseng #include <linux/pm_runtime.h> 19283b6124SGarlic Tseng #include <linux/regmap.h> 20283b6124SGarlic Tseng #include <sound/soc.h> 21f1b5bf07SKuninori Morimoto #include "mtk-afe-platform-driver.h" 22283b6124SGarlic Tseng #include "mtk-afe-fe-dai.h" 23283b6124SGarlic Tseng #include "mtk-base-afe.h" 24283b6124SGarlic Tseng 25283b6124SGarlic Tseng #define AFE_BASE_END_OFFSET 8 26283b6124SGarlic Tseng 2722e76614SBaoyou Xie static int mtk_regmap_update_bits(struct regmap *map, int reg, 2822e76614SBaoyou Xie unsigned int mask, 29283b6124SGarlic Tseng unsigned int val) 30283b6124SGarlic Tseng { 31283b6124SGarlic Tseng if (reg < 0) 32283b6124SGarlic Tseng return 0; 33283b6124SGarlic Tseng return regmap_update_bits(map, reg, mask, val); 34283b6124SGarlic Tseng } 35283b6124SGarlic Tseng 3622e76614SBaoyou Xie static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) 37283b6124SGarlic Tseng { 38283b6124SGarlic Tseng if (reg < 0) 39283b6124SGarlic Tseng return 0; 40283b6124SGarlic Tseng return regmap_write(map, reg, val); 41283b6124SGarlic Tseng } 42283b6124SGarlic Tseng 43283b6124SGarlic Tseng int mtk_afe_fe_startup(struct snd_pcm_substream *substream, 44283b6124SGarlic Tseng struct snd_soc_dai *dai) 45283b6124SGarlic Tseng { 46283b6124SGarlic Tseng struct snd_soc_pcm_runtime *rtd = substream->private_data; 47f1b5bf07SKuninori Morimoto struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 48f1b5bf07SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 49283b6124SGarlic Tseng struct snd_pcm_runtime *runtime = substream->runtime; 50283b6124SGarlic Tseng int memif_num = rtd->cpu_dai->id; 51283b6124SGarlic Tseng struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; 52283b6124SGarlic Tseng const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; 53283b6124SGarlic Tseng int ret; 54283b6124SGarlic Tseng 55283b6124SGarlic Tseng memif->substream = substream; 56283b6124SGarlic Tseng 57283b6124SGarlic Tseng snd_pcm_hw_constraint_step(substream->runtime, 0, 58283b6124SGarlic Tseng SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); 59283b6124SGarlic Tseng /* enable agent */ 60283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 61283b6124SGarlic Tseng 1 << memif->data->agent_disable_shift, 62283b6124SGarlic Tseng 0 << memif->data->agent_disable_shift); 63283b6124SGarlic Tseng 64283b6124SGarlic Tseng snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); 65283b6124SGarlic Tseng 66283b6124SGarlic Tseng /* 67283b6124SGarlic Tseng * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be 68283b6124SGarlic Tseng * smaller than period_size due to AFE's internal buffer. 69283b6124SGarlic Tseng * This easily leads to overrun when avail_min is period_size. 70283b6124SGarlic Tseng * One more period can hold the possible unread buffer. 71283b6124SGarlic Tseng */ 72283b6124SGarlic Tseng if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 73283b6124SGarlic Tseng int periods_max = mtk_afe_hardware->periods_max; 74283b6124SGarlic Tseng 75283b6124SGarlic Tseng ret = snd_pcm_hw_constraint_minmax(runtime, 76283b6124SGarlic Tseng SNDRV_PCM_HW_PARAM_PERIODS, 77283b6124SGarlic Tseng 3, periods_max); 78283b6124SGarlic Tseng if (ret < 0) { 79283b6124SGarlic Tseng dev_err(afe->dev, "hw_constraint_minmax failed\n"); 80283b6124SGarlic Tseng return ret; 81283b6124SGarlic Tseng } 82283b6124SGarlic Tseng } 83283b6124SGarlic Tseng 84283b6124SGarlic Tseng ret = snd_pcm_hw_constraint_integer(runtime, 85283b6124SGarlic Tseng SNDRV_PCM_HW_PARAM_PERIODS); 86283b6124SGarlic Tseng if (ret < 0) 87283b6124SGarlic Tseng dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); 88283b6124SGarlic Tseng 89283b6124SGarlic Tseng /* dynamic allocate irq to memif */ 90283b6124SGarlic Tseng if (memif->irq_usage < 0) { 91283b6124SGarlic Tseng int irq_id = mtk_dynamic_irq_acquire(afe); 92283b6124SGarlic Tseng 93283b6124SGarlic Tseng if (irq_id != afe->irqs_size) { 94283b6124SGarlic Tseng /* link */ 95283b6124SGarlic Tseng memif->irq_usage = irq_id; 96283b6124SGarlic Tseng } else { 97283b6124SGarlic Tseng dev_err(afe->dev, "%s() error: no more asys irq\n", 98283b6124SGarlic Tseng __func__); 99283b6124SGarlic Tseng ret = -EBUSY; 100283b6124SGarlic Tseng } 101283b6124SGarlic Tseng } 102283b6124SGarlic Tseng return ret; 103283b6124SGarlic Tseng } 104283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_startup); 105283b6124SGarlic Tseng 106283b6124SGarlic Tseng void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, 107283b6124SGarlic Tseng struct snd_soc_dai *dai) 108283b6124SGarlic Tseng { 109283b6124SGarlic Tseng struct snd_soc_pcm_runtime *rtd = substream->private_data; 110f1b5bf07SKuninori Morimoto struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 111f1b5bf07SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 112283b6124SGarlic Tseng struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 113283b6124SGarlic Tseng int irq_id; 114283b6124SGarlic Tseng 115283b6124SGarlic Tseng irq_id = memif->irq_usage; 116283b6124SGarlic Tseng 117283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 118283b6124SGarlic Tseng 1 << memif->data->agent_disable_shift, 119283b6124SGarlic Tseng 1 << memif->data->agent_disable_shift); 120283b6124SGarlic Tseng 121283b6124SGarlic Tseng if (!memif->const_irq) { 122283b6124SGarlic Tseng mtk_dynamic_irq_release(afe, irq_id); 123283b6124SGarlic Tseng memif->irq_usage = -1; 124283b6124SGarlic Tseng memif->substream = NULL; 125283b6124SGarlic Tseng } 126283b6124SGarlic Tseng } 127283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown); 128283b6124SGarlic Tseng 129283b6124SGarlic Tseng int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, 130283b6124SGarlic Tseng struct snd_pcm_hw_params *params, 131283b6124SGarlic Tseng struct snd_soc_dai *dai) 132283b6124SGarlic Tseng { 133283b6124SGarlic Tseng struct snd_soc_pcm_runtime *rtd = substream->private_data; 134f1b5bf07SKuninori Morimoto struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 135f1b5bf07SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 136283b6124SGarlic Tseng struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 137283b6124SGarlic Tseng int msb_at_bit33 = 0; 138283b6124SGarlic Tseng int ret, fs = 0; 139283b6124SGarlic Tseng 140283b6124SGarlic Tseng ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 141283b6124SGarlic Tseng if (ret < 0) 142283b6124SGarlic Tseng return ret; 143283b6124SGarlic Tseng 144283b6124SGarlic Tseng msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0; 145283b6124SGarlic Tseng memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); 146283b6124SGarlic Tseng memif->buffer_size = substream->runtime->dma_bytes; 147283b6124SGarlic Tseng 148283b6124SGarlic Tseng /* start */ 149283b6124SGarlic Tseng mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base, 150283b6124SGarlic Tseng memif->phys_buf_addr); 151283b6124SGarlic Tseng /* end */ 152283b6124SGarlic Tseng mtk_regmap_write(afe->regmap, 153283b6124SGarlic Tseng memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, 154283b6124SGarlic Tseng memif->phys_buf_addr + memif->buffer_size - 1); 155283b6124SGarlic Tseng 156283b6124SGarlic Tseng /* set MSB to 33-bit */ 157283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 158283b6124SGarlic Tseng 1 << memif->data->msb_shift, 159283b6124SGarlic Tseng msb_at_bit33 << memif->data->msb_shift); 160283b6124SGarlic Tseng 161283b6124SGarlic Tseng /* set channel */ 162283b6124SGarlic Tseng if (memif->data->mono_shift >= 0) { 163283b6124SGarlic Tseng unsigned int mono = (params_channels(params) == 1) ? 1 : 0; 164283b6124SGarlic Tseng 165283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 166283b6124SGarlic Tseng 1 << memif->data->mono_shift, 167283b6124SGarlic Tseng mono << memif->data->mono_shift); 168283b6124SGarlic Tseng } 169283b6124SGarlic Tseng 170283b6124SGarlic Tseng /* set rate */ 171283b6124SGarlic Tseng if (memif->data->fs_shift < 0) 172283b6124SGarlic Tseng return 0; 173283b6124SGarlic Tseng 174283b6124SGarlic Tseng fs = afe->memif_fs(substream, params_rate(params)); 175283b6124SGarlic Tseng 176283b6124SGarlic Tseng if (fs < 0) 177283b6124SGarlic Tseng return -EINVAL; 178283b6124SGarlic Tseng 179283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, 180283b6124SGarlic Tseng memif->data->fs_maskbit << memif->data->fs_shift, 181283b6124SGarlic Tseng fs << memif->data->fs_shift); 182283b6124SGarlic Tseng 183283b6124SGarlic Tseng return 0; 184283b6124SGarlic Tseng } 185283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params); 186283b6124SGarlic Tseng 187283b6124SGarlic Tseng int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, 188283b6124SGarlic Tseng struct snd_soc_dai *dai) 189283b6124SGarlic Tseng { 190283b6124SGarlic Tseng return snd_pcm_lib_free_pages(substream); 191283b6124SGarlic Tseng } 192283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); 193283b6124SGarlic Tseng 194283b6124SGarlic Tseng int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, 195283b6124SGarlic Tseng struct snd_soc_dai *dai) 196283b6124SGarlic Tseng { 197283b6124SGarlic Tseng struct snd_soc_pcm_runtime *rtd = substream->private_data; 198283b6124SGarlic Tseng struct snd_pcm_runtime * const runtime = substream->runtime; 199f1b5bf07SKuninori Morimoto struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 200f1b5bf07SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 201283b6124SGarlic Tseng struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 202283b6124SGarlic Tseng struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; 203283b6124SGarlic Tseng const struct mtk_base_irq_data *irq_data = irqs->irq_data; 204283b6124SGarlic Tseng unsigned int counter = runtime->period_size; 205283b6124SGarlic Tseng int fs; 206283b6124SGarlic Tseng 207283b6124SGarlic Tseng dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); 208283b6124SGarlic Tseng 209283b6124SGarlic Tseng switch (cmd) { 210283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_START: 211283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_RESUME: 212283b6124SGarlic Tseng if (memif->data->enable_shift >= 0) 213283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, 214283b6124SGarlic Tseng memif->data->enable_reg, 215283b6124SGarlic Tseng 1 << memif->data->enable_shift, 216283b6124SGarlic Tseng 1 << memif->data->enable_shift); 217283b6124SGarlic Tseng 218283b6124SGarlic Tseng /* set irq counter */ 219283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, 220283b6124SGarlic Tseng irq_data->irq_cnt_maskbit 221283b6124SGarlic Tseng << irq_data->irq_cnt_shift, 222283b6124SGarlic Tseng counter << irq_data->irq_cnt_shift); 223283b6124SGarlic Tseng 224283b6124SGarlic Tseng /* set irq fs */ 225283b6124SGarlic Tseng fs = afe->irq_fs(substream, runtime->rate); 226283b6124SGarlic Tseng 227283b6124SGarlic Tseng if (fs < 0) 228283b6124SGarlic Tseng return -EINVAL; 229283b6124SGarlic Tseng 230283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, 231283b6124SGarlic Tseng irq_data->irq_fs_maskbit 232283b6124SGarlic Tseng << irq_data->irq_fs_shift, 233283b6124SGarlic Tseng fs << irq_data->irq_fs_shift); 234283b6124SGarlic Tseng 235283b6124SGarlic Tseng /* enable interrupt */ 236283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 237283b6124SGarlic Tseng 1 << irq_data->irq_en_shift, 238283b6124SGarlic Tseng 1 << irq_data->irq_en_shift); 239283b6124SGarlic Tseng 240283b6124SGarlic Tseng return 0; 241283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_STOP: 242283b6124SGarlic Tseng case SNDRV_PCM_TRIGGER_SUSPEND: 243283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 244283b6124SGarlic Tseng 1 << memif->data->enable_shift, 0); 245283b6124SGarlic Tseng /* disable interrupt */ 246283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 247283b6124SGarlic Tseng 1 << irq_data->irq_en_shift, 248283b6124SGarlic Tseng 0 << irq_data->irq_en_shift); 249283b6124SGarlic Tseng /* and clear pending IRQ */ 250283b6124SGarlic Tseng mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, 251283b6124SGarlic Tseng 1 << irq_data->irq_clr_shift); 252283b6124SGarlic Tseng return 0; 253283b6124SGarlic Tseng default: 254283b6124SGarlic Tseng return -EINVAL; 255283b6124SGarlic Tseng } 256283b6124SGarlic Tseng } 257283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); 258283b6124SGarlic Tseng 259283b6124SGarlic Tseng int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, 260283b6124SGarlic Tseng struct snd_soc_dai *dai) 261283b6124SGarlic Tseng { 262283b6124SGarlic Tseng struct snd_soc_pcm_runtime *rtd = substream->private_data; 263f1b5bf07SKuninori Morimoto struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 264f1b5bf07SKuninori Morimoto struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 265283b6124SGarlic Tseng struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 266283b6124SGarlic Tseng int hd_audio = 0; 267283b6124SGarlic Tseng 268283b6124SGarlic Tseng /* set hd mode */ 269283b6124SGarlic Tseng switch (substream->runtime->format) { 270283b6124SGarlic Tseng case SNDRV_PCM_FORMAT_S16_LE: 271283b6124SGarlic Tseng hd_audio = 0; 272283b6124SGarlic Tseng break; 273283b6124SGarlic Tseng case SNDRV_PCM_FORMAT_S32_LE: 274283b6124SGarlic Tseng hd_audio = 1; 275283b6124SGarlic Tseng break; 276283b6124SGarlic Tseng case SNDRV_PCM_FORMAT_S24_LE: 277283b6124SGarlic Tseng hd_audio = 1; 278283b6124SGarlic Tseng break; 279283b6124SGarlic Tseng default: 280283b6124SGarlic Tseng dev_err(afe->dev, "%s() error: unsupported format %d\n", 281283b6124SGarlic Tseng __func__, substream->runtime->format); 282283b6124SGarlic Tseng break; 283283b6124SGarlic Tseng } 284283b6124SGarlic Tseng 285283b6124SGarlic Tseng mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 286283b6124SGarlic Tseng 1 << memif->data->hd_shift, 287283b6124SGarlic Tseng hd_audio << memif->data->hd_shift); 288283b6124SGarlic Tseng 289283b6124SGarlic Tseng return 0; 290283b6124SGarlic Tseng } 291283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); 292283b6124SGarlic Tseng 293283b6124SGarlic Tseng const struct snd_soc_dai_ops mtk_afe_fe_ops = { 294283b6124SGarlic Tseng .startup = mtk_afe_fe_startup, 295283b6124SGarlic Tseng .shutdown = mtk_afe_fe_shutdown, 296283b6124SGarlic Tseng .hw_params = mtk_afe_fe_hw_params, 297283b6124SGarlic Tseng .hw_free = mtk_afe_fe_hw_free, 298283b6124SGarlic Tseng .prepare = mtk_afe_fe_prepare, 299283b6124SGarlic Tseng .trigger = mtk_afe_fe_trigger, 300283b6124SGarlic Tseng }; 301283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); 302283b6124SGarlic Tseng 303283b6124SGarlic Tseng static DEFINE_MUTEX(irqs_lock); 304283b6124SGarlic Tseng int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) 305283b6124SGarlic Tseng { 306283b6124SGarlic Tseng int i; 307283b6124SGarlic Tseng 308283b6124SGarlic Tseng mutex_lock(&afe->irq_alloc_lock); 309283b6124SGarlic Tseng for (i = 0; i < afe->irqs_size; ++i) { 310283b6124SGarlic Tseng if (afe->irqs[i].irq_occupyed == 0) { 311283b6124SGarlic Tseng afe->irqs[i].irq_occupyed = 1; 312283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 313283b6124SGarlic Tseng return i; 314283b6124SGarlic Tseng } 315283b6124SGarlic Tseng } 316283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 317283b6124SGarlic Tseng return afe->irqs_size; 318283b6124SGarlic Tseng } 319283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire); 320283b6124SGarlic Tseng 321283b6124SGarlic Tseng int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id) 322283b6124SGarlic Tseng { 323283b6124SGarlic Tseng mutex_lock(&afe->irq_alloc_lock); 324283b6124SGarlic Tseng if (irq_id >= 0 && irq_id < afe->irqs_size) { 325283b6124SGarlic Tseng afe->irqs[irq_id].irq_occupyed = 0; 326283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 327283b6124SGarlic Tseng return 0; 328283b6124SGarlic Tseng } 329283b6124SGarlic Tseng mutex_unlock(&afe->irq_alloc_lock); 330283b6124SGarlic Tseng return -EINVAL; 331283b6124SGarlic Tseng } 332283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release); 333283b6124SGarlic Tseng 334283b6124SGarlic Tseng int mtk_afe_dai_suspend(struct snd_soc_dai *dai) 335283b6124SGarlic Tseng { 336283b6124SGarlic Tseng struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); 337283b6124SGarlic Tseng struct device *dev = afe->dev; 338283b6124SGarlic Tseng struct regmap *regmap = afe->regmap; 339283b6124SGarlic Tseng int i; 340283b6124SGarlic Tseng 341283b6124SGarlic Tseng if (pm_runtime_status_suspended(dev) || afe->suspended) 342283b6124SGarlic Tseng return 0; 343283b6124SGarlic Tseng 344283b6124SGarlic Tseng if (!afe->reg_back_up) 345283b6124SGarlic Tseng afe->reg_back_up = 346283b6124SGarlic Tseng devm_kcalloc(dev, afe->reg_back_up_list_num, 347283b6124SGarlic Tseng sizeof(unsigned int), GFP_KERNEL); 348283b6124SGarlic Tseng 349283b6124SGarlic Tseng for (i = 0; i < afe->reg_back_up_list_num; i++) 350283b6124SGarlic Tseng regmap_read(regmap, afe->reg_back_up_list[i], 351283b6124SGarlic Tseng &afe->reg_back_up[i]); 352283b6124SGarlic Tseng 353283b6124SGarlic Tseng afe->suspended = true; 354283b6124SGarlic Tseng afe->runtime_suspend(dev); 355283b6124SGarlic Tseng return 0; 356283b6124SGarlic Tseng } 357283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend); 358283b6124SGarlic Tseng 359283b6124SGarlic Tseng int mtk_afe_dai_resume(struct snd_soc_dai *dai) 360283b6124SGarlic Tseng { 361283b6124SGarlic Tseng struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); 362283b6124SGarlic Tseng struct device *dev = afe->dev; 363283b6124SGarlic Tseng struct regmap *regmap = afe->regmap; 364283b6124SGarlic Tseng int i = 0; 365283b6124SGarlic Tseng 366283b6124SGarlic Tseng if (pm_runtime_status_suspended(dev) || !afe->suspended) 367283b6124SGarlic Tseng return 0; 368283b6124SGarlic Tseng 369283b6124SGarlic Tseng afe->runtime_resume(dev); 370283b6124SGarlic Tseng 371283b6124SGarlic Tseng if (!afe->reg_back_up) 372283b6124SGarlic Tseng dev_dbg(dev, "%s no reg_backup\n", __func__); 373283b6124SGarlic Tseng 374283b6124SGarlic Tseng for (i = 0; i < afe->reg_back_up_list_num; i++) 375283b6124SGarlic Tseng mtk_regmap_write(regmap, afe->reg_back_up_list[i], 376283b6124SGarlic Tseng afe->reg_back_up[i]); 377283b6124SGarlic Tseng 378283b6124SGarlic Tseng afe->suspended = false; 379283b6124SGarlic Tseng return 0; 380283b6124SGarlic Tseng } 381283b6124SGarlic Tseng EXPORT_SYMBOL_GPL(mtk_afe_dai_resume); 382283b6124SGarlic Tseng 383283b6124SGarlic Tseng MODULE_DESCRIPTION("Mediatek simple fe dai operator"); 384283b6124SGarlic Tseng MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 385283b6124SGarlic Tseng MODULE_LICENSE("GPL v2"); 386283b6124SGarlic Tseng 387