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