Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/mellanox/mlx5/core/diag/   (Linux Kernel Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  mix.c

  Sprache: C
 

// SPDX-License-Identifier: GPL-2.0
//
// mix.c
//
// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

/*
 *     CTUn MIXn
 *     +------+ +------+
 * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| ->
 * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| ->
 * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| ->
 * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| ->
 *     +------+ +------+
 *
 * ex)
 * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
 * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
 *
 * MIX Volume
 * amixer set "MIX",0  100%  // DAI0 Volume
 * amixer set "MIX",1  100%  // DAI1 Volume
 *
 * Volume Ramp
 * amixer set "MIX Ramp Up Rate"   "0.125 dB/1 step"
 * amixer set "MIX Ramp Down Rate" "4 dB/1 step"
 * amixer set "MIX Ramp" on
 * aplay xxx.wav &
 * amixer set "MIX",0  80%  // DAI0 Volume Down
 * amixer set "MIX",1 100%  // DAI1 Volume Up
 */


#include "rsnd.h"

#define MIX_NAME_SIZE 16
#define MIX_NAME "mix"

struct rsnd_mix {
 struct rsnd_mod mod;
 struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
 struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
 struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
 struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
 struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
 struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
 struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */
 u32 flags;
};

#define ONCE_KCTRL_INITIALIZED  (1 << 0)
#define HAS_VOLA   (1 << 1)
#define HAS_VOLB   (1 << 2)
#define HAS_VOLC   (1 << 3)
#define HAS_VOLD   (1 << 4)

#define VOL_MAX    0x3ff

#define rsnd_mod_to_mix(_mod) \
 container_of((_mod), struct rsnd_mix, mod)

#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
#define rsnd_mix_nr(priv) ((priv)->mix_nr)
#define for_each_rsnd_mix(pos, priv, i)     \
 for ((i) = 0;       \
      ((i) < rsnd_mix_nr(priv)) &&    \
       ((pos) = (struct rsnd_mix *)(priv)->mix + i); \
      i++)

static void rsnd_mix_activation(struct rsnd_mod *mod)
{
 rsnd_mod_write(mod, MIX_SWRSR, 0);
 rsnd_mod_write(mod, MIX_SWRSR, 1);
}

static void rsnd_mix_halt(struct rsnd_mod *mod)
{
 rsnd_mod_write(mod, MIX_MIXIR, 1);
 rsnd_mod_write(mod, MIX_SWRSR, 0);
}

#define rsnd_mix_get_vol(mix, X) \
 rsnd_flags_has(mix, HAS_VOL##X) ? \
  (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
          struct rsnd_mod *mod)
{
 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 struct device *dev = rsnd_priv_to_dev(priv);
 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
 u32 volA = rsnd_mix_get_vol(mix, A);
 u32 volB = rsnd_mix_get_vol(mix, B);
 u32 volC = rsnd_mix_get_vol(mix, C);
 u32 volD = rsnd_mix_get_vol(mix, D);

 dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
  volA, volB, volC, volD);

 rsnd_mod_write(mod, MIX_MDBAR, volA);
 rsnd_mod_write(mod, MIX_MDBBR, volB);
 rsnd_mod_write(mod, MIX_MDBCR, volC);
 rsnd_mod_write(mod, MIX_MDBDR, volD);
}

static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
     struct rsnd_mod *mod)
{
 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);

 rsnd_mod_write(mod, MIX_MIXIR, 1);

 /* General Information */
 rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));

 /* volume step */
 rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
 rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
           rsnd_kctrl_vals(mix->rdw));

 /* common volume parameter */
 rsnd_mix_volume_parameter(io, mod);

 rsnd_mod_write(mod, MIX_MIXIR, 0);
}

static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
      struct rsnd_mod *mod)
{
 /* Disable MIX dB setting */
 rsnd_mod_write(mod, MIX_MDBER, 0);

 /* common volume parameter */
 rsnd_mix_volume_parameter(io, mod);

 /* Enable MIX dB setting */
 rsnd_mod_write(mod, MIX_MDBER, 1);
}

static int rsnd_mix_probe_(struct rsnd_mod *mod,
      struct rsnd_dai_stream *io,
      struct rsnd_priv *priv)
{
 return rsnd_cmd_attach(io, rsnd_mod_id(mod));
}

static int rsnd_mix_init(struct rsnd_mod *mod,
    struct rsnd_dai_stream *io,
    struct rsnd_priv *priv)
{
 int ret;

 ret = rsnd_mod_power_on(mod);
 if (ret < 0)
  return ret;

 rsnd_mix_activation(mod);

 rsnd_mix_volume_init(io, mod);

 rsnd_mix_volume_update(io, mod);

 return 0;
}

static int rsnd_mix_quit(struct rsnd_mod *mod,
    struct rsnd_dai_stream *io,
    struct rsnd_priv *priv)
{
 rsnd_mix_halt(mod);

 rsnd_mod_power_off(mod);

 return 0;
}

static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
       struct rsnd_dai_stream *io,
       struct snd_soc_pcm_runtime *rtd)
{
 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 struct device *dev = rsnd_priv_to_dev(priv);
 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
 struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
 struct rsnd_kctrl_cfg_s *volume;
 int ret;

 switch (rsnd_mod_id(src_mod)) {
 case 3:
 case 6/* MDBAR */
  volume = &mix->volumeA;
  rsnd_flags_set(mix, HAS_VOLA);
  break;
 case 4:
 case 9/* MDBBR */
  volume = &mix->volumeB;
  rsnd_flags_set(mix, HAS_VOLB);
  break;
 case 0:
 case 1/* MDBCR */
  volume = &mix->volumeC;
  rsnd_flags_set(mix, HAS_VOLC);
  break;
 case 2:
 case 5/* MDBDR */
  volume = &mix->volumeD;
  rsnd_flags_set(mix, HAS_VOLD);
  break;
 default:
  dev_err(dev, "unknown SRC is connected\n");
  return -EINVAL;
 }

 /* Volume */
 ret = rsnd_kctrl_new_s(mod, io, rtd,
          "MIX Playback Volume",
          rsnd_kctrl_accept_anytime,
          rsnd_mix_volume_update,
          volume, VOL_MAX);
 if (ret < 0)
  return ret;
 rsnd_kctrl_vals(*volume) = VOL_MAX;

 if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
  return ret;

 /* Ramp */
 ret = rsnd_kctrl_new_s(mod, io, rtd,
          "MIX Ramp Switch",
          rsnd_kctrl_accept_anytime,
          rsnd_mix_volume_update,
          &mix->ren, 1);
 if (ret < 0)
  return ret;

 ret = rsnd_kctrl_new_e(mod, io, rtd,
          "MIX Ramp Up Rate",
          rsnd_kctrl_accept_anytime,
          rsnd_mix_volume_update,
          &mix->rup,
          volume_ramp_rate,
          VOLUME_RAMP_MAX_MIX);
 if (ret < 0)
  return ret;

 ret = rsnd_kctrl_new_e(mod, io, rtd,
          "MIX Ramp Down Rate",
          rsnd_kctrl_accept_anytime,
          rsnd_mix_volume_update,
          &mix->rdw,
          volume_ramp_rate,
          VOLUME_RAMP_MAX_MIX);

 rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);

 return ret;
}

#ifdef CONFIG_DEBUG_FS
static void rsnd_mix_debug_info(struct seq_file *m,
    struct rsnd_dai_stream *io,
    struct rsnd_mod *mod)
{
 rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
      0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
}
#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
#else
#define DEBUG_INFO
#endif

static struct rsnd_mod_ops rsnd_mix_ops = {
 .name  = MIX_NAME,
 .probe  = rsnd_mix_probe_,
 .init  = rsnd_mix_init,
 .quit  = rsnd_mix_quit,
 .pcm_new = rsnd_mix_pcm_new,
 .get_status = rsnd_mod_get_status,
 DEBUG_INFO
};

struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
{
 if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
  id = 0;

 return rsnd_mod_get(rsnd_mix_get(priv, id));
}

int rsnd_mix_probe(struct rsnd_priv *priv)
{
 struct device_node *node;
 struct device *dev = rsnd_priv_to_dev(priv);
 struct rsnd_mix *mix;
 struct clk *clk;
 char name[MIX_NAME_SIZE];
 int i, nr, ret;

 node = rsnd_mix_of_node(priv);
 if (!node)
  return 0/* not used is not error */

 nr = of_get_child_count(node);
 if (!nr) {
  ret = -EINVAL;
  goto rsnd_mix_probe_done;
 }

 mix = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL);
 if (!mix) {
  ret = -ENOMEM;
  goto rsnd_mix_probe_done;
 }

 priv->mix_nr = nr;
 priv->mix = mix;

 i = 0;
 ret = 0;
 for_each_child_of_node_scoped(node, np) {
  mix = rsnd_mix_get(priv, i);

  snprintf(name, MIX_NAME_SIZE, "%s.%d",
    MIX_NAME, i);

  clk = devm_clk_get(dev, name);
  if (IS_ERR(clk)) {
   ret = PTR_ERR(clk);
   goto rsnd_mix_probe_done;
  }

  ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
        clk, RSND_MOD_MIX, i);
  if (ret)
   goto rsnd_mix_probe_done;

  i++;
 }

rsnd_mix_probe_done:
 of_node_put(node);

 return ret;
}

void rsnd_mix_remove(struct rsnd_priv *priv)
{
 struct rsnd_mix *mix;
 int i;

 for_each_rsnd_mix(mix, priv, i) {
  rsnd_mod_quit(rsnd_mod_get(mix));
 }
}

Messung V0.5 in Prozent
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-06-07) ¤

*© Formatika GbR, Deutschland






Wurzel

Bemerkung:

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders