1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator 4 * 5 * Copyright (c) 2016 MediaTek Inc. 6 * Author: Garlic Tseng <garlic.tseng@mediatek.com> 7 */ 8 9 #include <linux/module.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/regmap.h> 12 #include <sound/soc.h> 13 #include "mtk-afe-platform-driver.h" 14 #include "mtk-afe-fe-dai.h" 15 #include "mtk-base-afe.h" 16 17 #define AFE_BASE_END_OFFSET 8 18 19 static int mtk_regmap_update_bits(struct regmap *map, int reg, 20 unsigned int mask, 21 unsigned int val, int shift) 22 { 23 if (reg < 0 || WARN_ON_ONCE(shift < 0)) 24 return 0; 25 return regmap_update_bits(map, reg, mask << shift, val << shift); 26 } 27 28 static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) 29 { 30 if (reg < 0) 31 return 0; 32 return regmap_write(map, reg, val); 33 } 34 35 int mtk_afe_fe_startup(struct snd_pcm_substream *substream, 36 struct snd_soc_dai *dai) 37 { 38 struct snd_soc_pcm_runtime *rtd = substream->private_data; 39 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 40 struct snd_pcm_runtime *runtime = substream->runtime; 41 int memif_num = rtd->cpu_dai->id; 42 struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; 43 const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; 44 int ret; 45 46 memif->substream = substream; 47 48 snd_pcm_hw_constraint_step(substream->runtime, 0, 49 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); 50 /* enable agent */ 51 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 52 1, 0, memif->data->agent_disable_shift); 53 54 snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); 55 56 /* 57 * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be 58 * smaller than period_size due to AFE's internal buffer. 59 * This easily leads to overrun when avail_min is period_size. 60 * One more period can hold the possible unread buffer. 61 */ 62 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 63 int periods_max = mtk_afe_hardware->periods_max; 64 65 ret = snd_pcm_hw_constraint_minmax(runtime, 66 SNDRV_PCM_HW_PARAM_PERIODS, 67 3, periods_max); 68 if (ret < 0) { 69 dev_err(afe->dev, "hw_constraint_minmax failed\n"); 70 return ret; 71 } 72 } 73 74 ret = snd_pcm_hw_constraint_integer(runtime, 75 SNDRV_PCM_HW_PARAM_PERIODS); 76 if (ret < 0) 77 dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); 78 79 /* dynamic allocate irq to memif */ 80 if (memif->irq_usage < 0) { 81 int irq_id = mtk_dynamic_irq_acquire(afe); 82 83 if (irq_id != afe->irqs_size) { 84 /* link */ 85 memif->irq_usage = irq_id; 86 } else { 87 dev_err(afe->dev, "%s() error: no more asys irq\n", 88 __func__); 89 ret = -EBUSY; 90 } 91 } 92 return ret; 93 } 94 EXPORT_SYMBOL_GPL(mtk_afe_fe_startup); 95 96 void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, 97 struct snd_soc_dai *dai) 98 { 99 struct snd_soc_pcm_runtime *rtd = substream->private_data; 100 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 101 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 102 int irq_id; 103 104 irq_id = memif->irq_usage; 105 106 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 107 1, 1, memif->data->agent_disable_shift); 108 109 if (!memif->const_irq) { 110 mtk_dynamic_irq_release(afe, irq_id); 111 memif->irq_usage = -1; 112 memif->substream = NULL; 113 } 114 } 115 EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown); 116 117 int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, 118 struct snd_pcm_hw_params *params, 119 struct snd_soc_dai *dai) 120 { 121 struct snd_soc_pcm_runtime *rtd = substream->private_data; 122 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 123 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 124 int msb_at_bit33 = 0; 125 int ret, fs = 0; 126 127 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 128 if (ret < 0) 129 return ret; 130 131 msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0; 132 memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); 133 memif->buffer_size = substream->runtime->dma_bytes; 134 135 /* start */ 136 mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base, 137 memif->phys_buf_addr); 138 /* end */ 139 mtk_regmap_write(afe->regmap, 140 memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, 141 memif->phys_buf_addr + memif->buffer_size - 1); 142 143 /* set MSB to 33-bit */ 144 mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 145 1, msb_at_bit33, memif->data->msb_shift); 146 147 /* set channel */ 148 if (memif->data->mono_shift >= 0) { 149 unsigned int mono = (params_channels(params) == 1) ? 1 : 0; 150 151 mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 152 1, mono, memif->data->mono_shift); 153 } 154 155 /* set rate */ 156 if (memif->data->fs_shift < 0) 157 return 0; 158 159 fs = afe->memif_fs(substream, params_rate(params)); 160 161 if (fs < 0) 162 return -EINVAL; 163 164 mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, 165 memif->data->fs_maskbit, fs, 166 memif->data->fs_shift); 167 168 return 0; 169 } 170 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params); 171 172 int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, 173 struct snd_soc_dai *dai) 174 { 175 return snd_pcm_lib_free_pages(substream); 176 } 177 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); 178 179 int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, 180 struct snd_soc_dai *dai) 181 { 182 struct snd_soc_pcm_runtime *rtd = substream->private_data; 183 struct snd_pcm_runtime * const runtime = substream->runtime; 184 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 185 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 186 struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; 187 const struct mtk_base_irq_data *irq_data = irqs->irq_data; 188 unsigned int counter = runtime->period_size; 189 int fs; 190 191 dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); 192 193 switch (cmd) { 194 case SNDRV_PCM_TRIGGER_START: 195 case SNDRV_PCM_TRIGGER_RESUME: 196 mtk_regmap_update_bits(afe->regmap, 197 memif->data->enable_reg, 198 1, 1, memif->data->enable_shift); 199 200 /* set irq counter */ 201 mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, 202 irq_data->irq_cnt_maskbit, counter, 203 irq_data->irq_cnt_shift); 204 205 /* set irq fs */ 206 fs = afe->irq_fs(substream, runtime->rate); 207 208 if (fs < 0) 209 return -EINVAL; 210 211 mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, 212 irq_data->irq_fs_maskbit, fs, 213 irq_data->irq_fs_shift); 214 215 /* enable interrupt */ 216 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 217 1, 1, irq_data->irq_en_shift); 218 219 return 0; 220 case SNDRV_PCM_TRIGGER_STOP: 221 case SNDRV_PCM_TRIGGER_SUSPEND: 222 mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 223 1, 0, memif->data->enable_shift); 224 /* disable interrupt */ 225 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 226 1, 0, irq_data->irq_en_shift); 227 /* and clear pending IRQ */ 228 mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, 229 1 << irq_data->irq_clr_shift); 230 return 0; 231 default: 232 return -EINVAL; 233 } 234 } 235 EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); 236 237 int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, 238 struct snd_soc_dai *dai) 239 { 240 struct snd_soc_pcm_runtime *rtd = substream->private_data; 241 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 242 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; 243 int hd_audio = 0; 244 int hd_align = 0; 245 246 /* set hd mode */ 247 switch (substream->runtime->format) { 248 case SNDRV_PCM_FORMAT_S16_LE: 249 hd_audio = 0; 250 break; 251 case SNDRV_PCM_FORMAT_S32_LE: 252 hd_audio = 1; 253 hd_align = 1; 254 break; 255 case SNDRV_PCM_FORMAT_S24_LE: 256 hd_audio = 1; 257 break; 258 default: 259 dev_err(afe->dev, "%s() error: unsupported format %d\n", 260 __func__, substream->runtime->format); 261 break; 262 } 263 264 mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 265 1, hd_audio, memif->data->hd_shift); 266 267 mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, 268 1, hd_align, memif->data->hd_align_mshift); 269 270 return 0; 271 } 272 EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); 273 274 const struct snd_soc_dai_ops mtk_afe_fe_ops = { 275 .startup = mtk_afe_fe_startup, 276 .shutdown = mtk_afe_fe_shutdown, 277 .hw_params = mtk_afe_fe_hw_params, 278 .hw_free = mtk_afe_fe_hw_free, 279 .prepare = mtk_afe_fe_prepare, 280 .trigger = mtk_afe_fe_trigger, 281 }; 282 EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); 283 284 static DEFINE_MUTEX(irqs_lock); 285 int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) 286 { 287 int i; 288 289 mutex_lock(&afe->irq_alloc_lock); 290 for (i = 0; i < afe->irqs_size; ++i) { 291 if (afe->irqs[i].irq_occupyed == 0) { 292 afe->irqs[i].irq_occupyed = 1; 293 mutex_unlock(&afe->irq_alloc_lock); 294 return i; 295 } 296 } 297 mutex_unlock(&afe->irq_alloc_lock); 298 return afe->irqs_size; 299 } 300 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire); 301 302 int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id) 303 { 304 mutex_lock(&afe->irq_alloc_lock); 305 if (irq_id >= 0 && irq_id < afe->irqs_size) { 306 afe->irqs[irq_id].irq_occupyed = 0; 307 mutex_unlock(&afe->irq_alloc_lock); 308 return 0; 309 } 310 mutex_unlock(&afe->irq_alloc_lock); 311 return -EINVAL; 312 } 313 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release); 314 315 int mtk_afe_dai_suspend(struct snd_soc_dai *dai) 316 { 317 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 318 struct device *dev = afe->dev; 319 struct regmap *regmap = afe->regmap; 320 int i; 321 322 if (pm_runtime_status_suspended(dev) || afe->suspended) 323 return 0; 324 325 if (!afe->reg_back_up) 326 afe->reg_back_up = 327 devm_kcalloc(dev, afe->reg_back_up_list_num, 328 sizeof(unsigned int), GFP_KERNEL); 329 330 for (i = 0; i < afe->reg_back_up_list_num; i++) 331 regmap_read(regmap, afe->reg_back_up_list[i], 332 &afe->reg_back_up[i]); 333 334 afe->suspended = true; 335 afe->runtime_suspend(dev); 336 return 0; 337 } 338 EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend); 339 340 int mtk_afe_dai_resume(struct snd_soc_dai *dai) 341 { 342 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 343 struct device *dev = afe->dev; 344 struct regmap *regmap = afe->regmap; 345 int i = 0; 346 347 if (pm_runtime_status_suspended(dev) || !afe->suspended) 348 return 0; 349 350 afe->runtime_resume(dev); 351 352 if (!afe->reg_back_up) 353 dev_dbg(dev, "%s no reg_backup\n", __func__); 354 355 for (i = 0; i < afe->reg_back_up_list_num; i++) 356 mtk_regmap_write(regmap, afe->reg_back_up_list[i], 357 afe->reg_back_up[i]); 358 359 afe->suspended = false; 360 return 0; 361 } 362 EXPORT_SYMBOL_GPL(mtk_afe_dai_resume); 363 364 MODULE_DESCRIPTION("Mediatek simple fe dai operator"); 365 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 366 MODULE_LICENSE("GPL v2"); 367