linux/sound/soc/sh/rcar/mix.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// mix.c
   4//
   5// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6
   7/*
   8 *                  CTUn        MIXn
   9 *                  +------+    +------+
  10 * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| ->
  11 * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| ->
  12 * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| ->
  13 * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| ->
  14 *                  +------+    +------+
  15 *
  16 * ex)
  17 *      DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
  18 *      DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
  19 *
  20 * MIX Volume
  21 *      amixer set "MIX",0  100%  // DAI0 Volume
  22 *      amixer set "MIX",1  100%  // DAI1 Volume
  23 *
  24 * Volume Ramp
  25 *      amixer set "MIX Ramp Up Rate"   "0.125 dB/1 step"
  26 *      amixer set "MIX Ramp Down Rate" "4 dB/1 step"
  27 *      amixer set "MIX Ramp" on
  28 *      aplay xxx.wav &
  29 *      amixer set "MIX",0  80%  // DAI0 Volume Down
  30 *      amixer set "MIX",1 100%  // DAI1 Volume Up
  31 */
  32
  33#include "rsnd.h"
  34
  35#define MIX_NAME_SIZE   16
  36#define MIX_NAME "mix"
  37
  38struct rsnd_mix {
  39        struct rsnd_mod mod;
  40        struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
  41        struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
  42        struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
  43        struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
  44        struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
  45        struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
  46        struct rsnd_kctrl_cfg_s rdw;    /* Ramp Rate Down */
  47        u32 flags;
  48};
  49
  50#define ONCE_KCTRL_INITIALIZED          (1 << 0)
  51#define HAS_VOLA                        (1 << 1)
  52#define HAS_VOLB                        (1 << 2)
  53#define HAS_VOLC                        (1 << 3)
  54#define HAS_VOLD                        (1 << 4)
  55
  56#define VOL_MAX                         0x3ff
  57
  58#define rsnd_mod_to_mix(_mod)   \
  59        container_of((_mod), struct rsnd_mix, mod)
  60
  61#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
  62#define rsnd_mix_nr(priv) ((priv)->mix_nr)
  63#define for_each_rsnd_mix(pos, priv, i)                                 \
  64        for ((i) = 0;                                                   \
  65             ((i) < rsnd_mix_nr(priv)) &&                               \
  66                     ((pos) = (struct rsnd_mix *)(priv)->mix + i);      \
  67             i++)
  68
  69static void rsnd_mix_activation(struct rsnd_mod *mod)
  70{
  71        rsnd_mod_write(mod, MIX_SWRSR, 0);
  72        rsnd_mod_write(mod, MIX_SWRSR, 1);
  73}
  74
  75static void rsnd_mix_halt(struct rsnd_mod *mod)
  76{
  77        rsnd_mod_write(mod, MIX_MIXIR, 1);
  78        rsnd_mod_write(mod, MIX_SWRSR, 0);
  79}
  80
  81#define rsnd_mix_get_vol(mix, X) \
  82        rsnd_flags_has(mix, HAS_VOL##X) ? \
  83                (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
  84static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
  85                                      struct rsnd_mod *mod)
  86{
  87        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
  88        struct device *dev = rsnd_priv_to_dev(priv);
  89        struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
  90        u32 volA = rsnd_mix_get_vol(mix, A);
  91        u32 volB = rsnd_mix_get_vol(mix, B);
  92        u32 volC = rsnd_mix_get_vol(mix, C);
  93        u32 volD = rsnd_mix_get_vol(mix, D);
  94
  95        dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
  96                volA, volB, volC, volD);
  97
  98        rsnd_mod_write(mod, MIX_MDBAR, volA);
  99        rsnd_mod_write(mod, MIX_MDBBR, volB);
 100        rsnd_mod_write(mod, MIX_MDBCR, volC);
 101        rsnd_mod_write(mod, MIX_MDBDR, volD);
 102}
 103
 104static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
 105                                 struct rsnd_mod *mod)
 106{
 107        struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
 108
 109        rsnd_mod_write(mod, MIX_MIXIR, 1);
 110
 111        /* General Information */
 112        rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
 113
 114        /* volume step */
 115        rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
 116        rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
 117                                       rsnd_kctrl_vals(mix->rdw));
 118
 119        /* common volume parameter */
 120        rsnd_mix_volume_parameter(io, mod);
 121
 122        rsnd_mod_write(mod, MIX_MIXIR, 0);
 123}
 124
 125static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
 126                                  struct rsnd_mod *mod)
 127{
 128        /* Disable MIX dB setting */
 129        rsnd_mod_write(mod, MIX_MDBER, 0);
 130
 131        /* common volume parameter */
 132        rsnd_mix_volume_parameter(io, mod);
 133
 134        /* Enable MIX dB setting */
 135        rsnd_mod_write(mod, MIX_MDBER, 1);
 136}
 137
 138static int rsnd_mix_probe_(struct rsnd_mod *mod,
 139                           struct rsnd_dai_stream *io,
 140                           struct rsnd_priv *priv)
 141{
 142        return rsnd_cmd_attach(io, rsnd_mod_id(mod));
 143}
 144
 145static int rsnd_mix_init(struct rsnd_mod *mod,
 146                         struct rsnd_dai_stream *io,
 147                         struct rsnd_priv *priv)
 148{
 149        rsnd_mod_power_on(mod);
 150
 151        rsnd_mix_activation(mod);
 152
 153        rsnd_mix_volume_init(io, mod);
 154
 155        rsnd_mix_volume_update(io, mod);
 156
 157        return 0;
 158}
 159
 160static int rsnd_mix_quit(struct rsnd_mod *mod,
 161                         struct rsnd_dai_stream *io,
 162                         struct rsnd_priv *priv)
 163{
 164        rsnd_mix_halt(mod);
 165
 166        rsnd_mod_power_off(mod);
 167
 168        return 0;
 169}
 170
 171static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
 172                            struct rsnd_dai_stream *io,
 173                            struct snd_soc_pcm_runtime *rtd)
 174{
 175        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 176        struct device *dev = rsnd_priv_to_dev(priv);
 177        struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
 178        struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
 179        struct rsnd_kctrl_cfg_s *volume;
 180        int ret;
 181
 182        switch (rsnd_mod_id(src_mod)) {
 183        case 3:
 184        case 6: /* MDBAR */
 185                volume = &mix->volumeA;
 186                rsnd_flags_set(mix, HAS_VOLA);
 187                break;
 188        case 4:
 189        case 9: /* MDBBR */
 190                volume = &mix->volumeB;
 191                rsnd_flags_set(mix, HAS_VOLB);
 192                break;
 193        case 0:
 194        case 1: /* MDBCR */
 195                volume = &mix->volumeC;
 196                rsnd_flags_set(mix, HAS_VOLC);
 197                break;
 198        case 2:
 199        case 5: /* MDBDR */
 200                volume = &mix->volumeD;
 201                rsnd_flags_set(mix, HAS_VOLD);
 202                break;
 203        default:
 204                dev_err(dev, "unknown SRC is connected\n");
 205                return -EINVAL;
 206        }
 207
 208        /* Volume */
 209        ret = rsnd_kctrl_new_s(mod, io, rtd,
 210                               "MIX Playback Volume",
 211                               rsnd_kctrl_accept_anytime,
 212                               rsnd_mix_volume_update,
 213                               volume, VOL_MAX);
 214        if (ret < 0)
 215                return ret;
 216        rsnd_kctrl_vals(*volume) = VOL_MAX;
 217
 218        if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
 219                return ret;
 220
 221        /* Ramp */
 222        ret = rsnd_kctrl_new_s(mod, io, rtd,
 223                               "MIX Ramp Switch",
 224                               rsnd_kctrl_accept_anytime,
 225                               rsnd_mix_volume_update,
 226                               &mix->ren, 1);
 227        if (ret < 0)
 228                return ret;
 229
 230        ret = rsnd_kctrl_new_e(mod, io, rtd,
 231                               "MIX Ramp Up Rate",
 232                               rsnd_kctrl_accept_anytime,
 233                               rsnd_mix_volume_update,
 234                               &mix->rup,
 235                               volume_ramp_rate,
 236                               VOLUME_RAMP_MAX_MIX);
 237        if (ret < 0)
 238                return ret;
 239
 240        ret = rsnd_kctrl_new_e(mod, io, rtd,
 241                               "MIX Ramp Down Rate",
 242                               rsnd_kctrl_accept_anytime,
 243                               rsnd_mix_volume_update,
 244                               &mix->rdw,
 245                               volume_ramp_rate,
 246                               VOLUME_RAMP_MAX_MIX);
 247
 248        rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
 249
 250        return ret;
 251}
 252
 253static struct rsnd_mod_ops rsnd_mix_ops = {
 254        .name           = MIX_NAME,
 255        .probe          = rsnd_mix_probe_,
 256        .init           = rsnd_mix_init,
 257        .quit           = rsnd_mix_quit,
 258        .pcm_new        = rsnd_mix_pcm_new,
 259        .get_status     = rsnd_mod_get_status,
 260};
 261
 262struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
 263{
 264        if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
 265                id = 0;
 266
 267        return rsnd_mod_get(rsnd_mix_get(priv, id));
 268}
 269
 270int rsnd_mix_probe(struct rsnd_priv *priv)
 271{
 272        struct device_node *node;
 273        struct device_node *np;
 274        struct device *dev = rsnd_priv_to_dev(priv);
 275        struct rsnd_mix *mix;
 276        struct clk *clk;
 277        char name[MIX_NAME_SIZE];
 278        int i, nr, ret;
 279
 280        /* This driver doesn't support Gen1 at this point */
 281        if (rsnd_is_gen1(priv))
 282                return 0;
 283
 284        node = rsnd_mix_of_node(priv);
 285        if (!node)
 286                return 0; /* not used is not error */
 287
 288        nr = of_get_child_count(node);
 289        if (!nr) {
 290                ret = -EINVAL;
 291                goto rsnd_mix_probe_done;
 292        }
 293
 294        mix     = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL);
 295        if (!mix) {
 296                ret = -ENOMEM;
 297                goto rsnd_mix_probe_done;
 298        }
 299
 300        priv->mix_nr    = nr;
 301        priv->mix       = mix;
 302
 303        i = 0;
 304        ret = 0;
 305        for_each_child_of_node(node, np) {
 306                mix = rsnd_mix_get(priv, i);
 307
 308                snprintf(name, MIX_NAME_SIZE, "%s.%d",
 309                         MIX_NAME, i);
 310
 311                clk = devm_clk_get(dev, name);
 312                if (IS_ERR(clk)) {
 313                        ret = PTR_ERR(clk);
 314                        of_node_put(np);
 315                        goto rsnd_mix_probe_done;
 316                }
 317
 318                ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
 319                                    clk, RSND_MOD_MIX, i);
 320                if (ret) {
 321                        of_node_put(np);
 322                        goto rsnd_mix_probe_done;
 323                }
 324
 325                i++;
 326        }
 327
 328rsnd_mix_probe_done:
 329        of_node_put(node);
 330
 331        return ret;
 332}
 333
 334void rsnd_mix_remove(struct rsnd_priv *priv)
 335{
 336        struct rsnd_mix *mix;
 337        int i;
 338
 339        for_each_rsnd_mix(mix, priv, i) {
 340                rsnd_mod_quit(rsnd_mod_get(mix));
 341        }
 342}
 343