root/sound/soc/mediatek/common/mtk-afe-fe-dai.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mtk_regmap_update_bits
  2. mtk_regmap_write
  3. mtk_afe_fe_startup
  4. mtk_afe_fe_shutdown
  5. mtk_afe_fe_hw_params
  6. mtk_afe_fe_hw_free
  7. mtk_afe_fe_trigger
  8. mtk_afe_fe_prepare
  9. mtk_dynamic_irq_acquire
  10. mtk_dynamic_irq_release
  11. mtk_afe_dai_suspend
  12. mtk_afe_dai_resume

   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");

/* [<][>][^][v][top][bottom][index][help] */