root/sound/soc/meson/axg-frddr.c

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

DEFINITIONS

This source file includes following definitions.
  1. g12a_frddr_dai_prepare
  2. axg_frddr_dai_startup
  3. axg_frddr_dai_shutdown
  4. axg_frddr_pcm_new

   1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2 //
   3 // Copyright (c) 2018 BayLibre, SAS.
   4 // Author: Jerome Brunet <jbrunet@baylibre.com>
   5 
   6 /*
   7  * This driver implements the frontend playback DAI of AXG and G12A based SoCs
   8  */
   9 
  10 #include <linux/clk.h>
  11 #include <linux/regmap.h>
  12 #include <linux/module.h>
  13 #include <linux/of_platform.h>
  14 #include <sound/soc.h>
  15 #include <sound/soc-dai.h>
  16 
  17 #include "axg-fifo.h"
  18 
  19 #define CTRL0_FRDDR_PP_MODE             BIT(30)
  20 #define CTRL0_SEL1_EN_SHIFT             3
  21 #define CTRL0_SEL2_SHIFT                4
  22 #define CTRL0_SEL2_EN_SHIFT             7
  23 #define CTRL0_SEL3_SHIFT                8
  24 #define CTRL0_SEL3_EN_SHIFT             11
  25 #define CTRL1_FRDDR_FORCE_FINISH        BIT(12)
  26 #define CTRL2_SEL1_SHIFT                0
  27 #define CTRL2_SEL1_EN_SHIFT             4
  28 #define CTRL2_SEL2_SHIFT                8
  29 #define CTRL2_SEL2_EN_SHIFT             12
  30 #define CTRL2_SEL3_SHIFT                16
  31 #define CTRL2_SEL3_EN_SHIFT             20
  32 
  33 static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream,
  34                                   struct snd_soc_dai *dai)
  35 {
  36         struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
  37 
  38         /* Reset the read pointer to the FIFO_INIT_ADDR */
  39         regmap_update_bits(fifo->map, FIFO_CTRL1,
  40                            CTRL1_FRDDR_FORCE_FINISH, 0);
  41         regmap_update_bits(fifo->map, FIFO_CTRL1,
  42                            CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH);
  43         regmap_update_bits(fifo->map, FIFO_CTRL1,
  44                            CTRL1_FRDDR_FORCE_FINISH, 0);
  45 
  46         return 0;
  47 }
  48 
  49 static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
  50                                  struct snd_soc_dai *dai)
  51 {
  52         struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
  53         unsigned int fifo_depth;
  54         int ret;
  55 
  56         /* Enable pclk to access registers and clock the fifo ip */
  57         ret = clk_prepare_enable(fifo->pclk);
  58         if (ret)
  59                 return ret;
  60 
  61         /* Apply single buffer mode to the interface */
  62         regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
  63 
  64         /*
  65          * TODO: We could adapt the fifo depth and the fifo threshold
  66          * depending on the expected memory throughput and lantencies
  67          * For now, we'll just use the same values as the vendor kernel
  68          * Depth and threshold are zero based.
  69          */
  70         fifo_depth = AXG_FIFO_MIN_CNT - 1;
  71         regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
  72                            CTRL1_FRDDR_DEPTH(fifo_depth));
  73 
  74         return 0;
  75 }
  76 
  77 static void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream,
  78                                    struct snd_soc_dai *dai)
  79 {
  80         struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
  81 
  82         clk_disable_unprepare(fifo->pclk);
  83 }
  84 
  85 static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
  86                              struct snd_soc_dai *dai)
  87 {
  88         return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK);
  89 }
  90 
  91 static const struct snd_soc_dai_ops axg_frddr_ops = {
  92         .startup        = axg_frddr_dai_startup,
  93         .shutdown       = axg_frddr_dai_shutdown,
  94 };
  95 
  96 static struct snd_soc_dai_driver axg_frddr_dai_drv = {
  97         .name = "FRDDR",
  98         .playback = {
  99                 .stream_name    = "Playback",
 100                 .channels_min   = 1,
 101                 .channels_max   = AXG_FIFO_CH_MAX,
 102                 .rates          = AXG_FIFO_RATES,
 103                 .formats        = AXG_FIFO_FORMATS,
 104         },
 105         .ops            = &axg_frddr_ops,
 106         .pcm_new        = axg_frddr_pcm_new,
 107 };
 108 
 109 static const char * const axg_frddr_sel_texts[] = {
 110         "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7",
 111 };
 112 
 113 static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
 114                             axg_frddr_sel_texts);
 115 
 116 static const struct snd_kcontrol_new axg_frddr_out_demux =
 117         SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum);
 118 
 119 static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = {
 120         SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0,
 121                            &axg_frddr_out_demux),
 122         SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
 123         SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
 124         SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
 125         SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
 126         SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
 127         SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
 128         SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
 129         SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
 130 };
 131 
 132 static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = {
 133         { "SINK SEL", NULL, "Playback" },
 134         { "OUT 0", "OUT 0",  "SINK SEL" },
 135         { "OUT 1", "OUT 1",  "SINK SEL" },
 136         { "OUT 2", "OUT 2",  "SINK SEL" },
 137         { "OUT 3", "OUT 3",  "SINK SEL" },
 138         { "OUT 4", "OUT 4",  "SINK SEL" },
 139         { "OUT 5", "OUT 5",  "SINK SEL" },
 140         { "OUT 6", "OUT 6",  "SINK SEL" },
 141         { "OUT 7", "OUT 7",  "SINK SEL" },
 142 };
 143 
 144 static const struct snd_soc_component_driver axg_frddr_component_drv = {
 145         .dapm_widgets           = axg_frddr_dapm_widgets,
 146         .num_dapm_widgets       = ARRAY_SIZE(axg_frddr_dapm_widgets),
 147         .dapm_routes            = axg_frddr_dapm_routes,
 148         .num_dapm_routes        = ARRAY_SIZE(axg_frddr_dapm_routes),
 149         .ops                    = &axg_fifo_pcm_ops
 150 };
 151 
 152 static const struct axg_fifo_match_data axg_frddr_match_data = {
 153         .field_threshold        = REG_FIELD(FIFO_CTRL1, 16, 23),
 154         .component_drv          = &axg_frddr_component_drv,
 155         .dai_drv                = &axg_frddr_dai_drv
 156 };
 157 
 158 static const struct snd_soc_dai_ops g12a_frddr_ops = {
 159         .prepare        = g12a_frddr_dai_prepare,
 160         .startup        = axg_frddr_dai_startup,
 161         .shutdown       = axg_frddr_dai_shutdown,
 162 };
 163 
 164 static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
 165         .name = "FRDDR",
 166         .playback = {
 167                 .stream_name    = "Playback",
 168                 .channels_min   = 1,
 169                 .channels_max   = AXG_FIFO_CH_MAX,
 170                 .rates          = AXG_FIFO_RATES,
 171                 .formats        = AXG_FIFO_FORMATS,
 172         },
 173         .ops            = &g12a_frddr_ops,
 174         .pcm_new        = axg_frddr_pcm_new,
 175 };
 176 
 177 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
 178                             axg_frddr_sel_texts);
 179 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT,
 180                             axg_frddr_sel_texts);
 181 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT,
 182                             axg_frddr_sel_texts);
 183 
 184 static const struct snd_kcontrol_new g12a_frddr_out1_demux =
 185         SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum);
 186 static const struct snd_kcontrol_new g12a_frddr_out2_demux =
 187         SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum);
 188 static const struct snd_kcontrol_new g12a_frddr_out3_demux =
 189         SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum);
 190 
 191 static const struct snd_kcontrol_new g12a_frddr_out1_enable =
 192         SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
 193                                     CTRL0_SEL1_EN_SHIFT, 1, 0);
 194 static const struct snd_kcontrol_new g12a_frddr_out2_enable =
 195         SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
 196                                     CTRL0_SEL2_EN_SHIFT, 1, 0);
 197 static const struct snd_kcontrol_new g12a_frddr_out3_enable =
 198         SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
 199                                     CTRL0_SEL3_EN_SHIFT, 1, 0);
 200 
 201 static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = {
 202         SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
 203         SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
 204         SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
 205         SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
 206                             &g12a_frddr_out1_enable),
 207         SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
 208                             &g12a_frddr_out2_enable),
 209         SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
 210                             &g12a_frddr_out3_enable),
 211         SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
 212                            &g12a_frddr_out1_demux),
 213         SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
 214                            &g12a_frddr_out2_demux),
 215         SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
 216                            &g12a_frddr_out3_demux),
 217         SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
 218         SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
 219         SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
 220         SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
 221         SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
 222         SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
 223         SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
 224         SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
 225 };
 226 
 227 static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = {
 228         { "SRC 1", NULL, "Playback" },
 229         { "SRC 2", NULL, "Playback" },
 230         { "SRC 3", NULL, "Playback" },
 231         { "SRC 1 EN", "Switch", "SRC 1" },
 232         { "SRC 2 EN", "Switch", "SRC 2" },
 233         { "SRC 3 EN", "Switch", "SRC 3" },
 234         { "SINK 1 SEL", NULL, "SRC 1 EN" },
 235         { "SINK 2 SEL", NULL, "SRC 2 EN" },
 236         { "SINK 3 SEL", NULL, "SRC 3 EN" },
 237         { "OUT 0", "OUT 0", "SINK 1 SEL" },
 238         { "OUT 1", "OUT 1", "SINK 1 SEL" },
 239         { "OUT 2", "OUT 2", "SINK 1 SEL" },
 240         { "OUT 3", "OUT 3", "SINK 1 SEL" },
 241         { "OUT 4", "OUT 4", "SINK 1 SEL" },
 242         { "OUT 5", "OUT 5", "SINK 1 SEL" },
 243         { "OUT 6", "OUT 6", "SINK 1 SEL" },
 244         { "OUT 7", "OUT 7", "SINK 1 SEL" },
 245         { "OUT 0", "OUT 0", "SINK 2 SEL" },
 246         { "OUT 1", "OUT 1", "SINK 2 SEL" },
 247         { "OUT 2", "OUT 2", "SINK 2 SEL" },
 248         { "OUT 3", "OUT 3", "SINK 2 SEL" },
 249         { "OUT 4", "OUT 4", "SINK 2 SEL" },
 250         { "OUT 5", "OUT 5", "SINK 2 SEL" },
 251         { "OUT 6", "OUT 6", "SINK 2 SEL" },
 252         { "OUT 7", "OUT 7", "SINK 2 SEL" },
 253         { "OUT 0", "OUT 0", "SINK 3 SEL" },
 254         { "OUT 1", "OUT 1", "SINK 3 SEL" },
 255         { "OUT 2", "OUT 2", "SINK 3 SEL" },
 256         { "OUT 3", "OUT 3", "SINK 3 SEL" },
 257         { "OUT 4", "OUT 4", "SINK 3 SEL" },
 258         { "OUT 5", "OUT 5", "SINK 3 SEL" },
 259         { "OUT 6", "OUT 6", "SINK 3 SEL" },
 260         { "OUT 7", "OUT 7", "SINK 3 SEL" },
 261 };
 262 
 263 static const struct snd_soc_component_driver g12a_frddr_component_drv = {
 264         .dapm_widgets           = g12a_frddr_dapm_widgets,
 265         .num_dapm_widgets       = ARRAY_SIZE(g12a_frddr_dapm_widgets),
 266         .dapm_routes            = g12a_frddr_dapm_routes,
 267         .num_dapm_routes        = ARRAY_SIZE(g12a_frddr_dapm_routes),
 268         .ops                    = &g12a_fifo_pcm_ops
 269 };
 270 
 271 static const struct axg_fifo_match_data g12a_frddr_match_data = {
 272         .field_threshold        = REG_FIELD(FIFO_CTRL1, 16, 23),
 273         .component_drv          = &g12a_frddr_component_drv,
 274         .dai_drv                = &g12a_frddr_dai_drv
 275 };
 276 
 277 /* On SM1, the output selection in on CTRL2 */
 278 static const struct snd_kcontrol_new sm1_frddr_out1_enable =
 279         SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
 280                                     CTRL2_SEL1_EN_SHIFT, 1, 0);
 281 static const struct snd_kcontrol_new sm1_frddr_out2_enable =
 282         SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
 283                                     CTRL2_SEL2_EN_SHIFT, 1, 0);
 284 static const struct snd_kcontrol_new sm1_frddr_out3_enable =
 285         SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
 286                                     CTRL2_SEL3_EN_SHIFT, 1, 0);
 287 
 288 static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT,
 289                             axg_frddr_sel_texts);
 290 static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT,
 291                             axg_frddr_sel_texts);
 292 static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT,
 293                             axg_frddr_sel_texts);
 294 
 295 static const struct snd_kcontrol_new sm1_frddr_out1_demux =
 296         SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum);
 297 static const struct snd_kcontrol_new sm1_frddr_out2_demux =
 298         SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum);
 299 static const struct snd_kcontrol_new sm1_frddr_out3_demux =
 300         SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum);
 301 
 302 static const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = {
 303         SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
 304         SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
 305         SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
 306         SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
 307                             &sm1_frddr_out1_enable),
 308         SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
 309                             &sm1_frddr_out2_enable),
 310         SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
 311                             &sm1_frddr_out3_enable),
 312         SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
 313                            &sm1_frddr_out1_demux),
 314         SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
 315                            &sm1_frddr_out2_demux),
 316         SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
 317                            &sm1_frddr_out3_demux),
 318         SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
 319         SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
 320         SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
 321         SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
 322         SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
 323         SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
 324         SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
 325         SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
 326 };
 327 
 328 static const struct snd_soc_component_driver sm1_frddr_component_drv = {
 329         .dapm_widgets           = sm1_frddr_dapm_widgets,
 330         .num_dapm_widgets       = ARRAY_SIZE(sm1_frddr_dapm_widgets),
 331         .dapm_routes            = g12a_frddr_dapm_routes,
 332         .num_dapm_routes        = ARRAY_SIZE(g12a_frddr_dapm_routes),
 333         .ops                    = &g12a_fifo_pcm_ops
 334 };
 335 
 336 static const struct axg_fifo_match_data sm1_frddr_match_data = {
 337         .field_threshold        = REG_FIELD(FIFO_CTRL1, 16, 23),
 338         .component_drv          = &sm1_frddr_component_drv,
 339         .dai_drv                = &g12a_frddr_dai_drv
 340 };
 341 
 342 static const struct of_device_id axg_frddr_of_match[] = {
 343         {
 344                 .compatible = "amlogic,axg-frddr",
 345                 .data = &axg_frddr_match_data,
 346         }, {
 347                 .compatible = "amlogic,g12a-frddr",
 348                 .data = &g12a_frddr_match_data,
 349         }, {
 350                 .compatible = "amlogic,sm1-frddr",
 351                 .data = &sm1_frddr_match_data,
 352         }, {}
 353 };
 354 MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
 355 
 356 static struct platform_driver axg_frddr_pdrv = {
 357         .probe = axg_fifo_probe,
 358         .driver = {
 359                 .name = "axg-frddr",
 360                 .of_match_table = axg_frddr_of_match,
 361         },
 362 };
 363 module_platform_driver(axg_frddr_pdrv);
 364 
 365 MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver");
 366 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 367 MODULE_LICENSE("GPL v2");

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