// SPDX-License-Identifier: GPL-2.0
//
// CS42L43 CODEC driver
//
// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/build_bug.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/bitmap.h>
#include <linux/gcd.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/jiffies.h>
#include <linux/mfd/cs42l43.h>
#include <linux/mfd/cs42l43-regs.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <sound/control.h>
#include <sound/cs42l43.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-component.h>
#include <sound/soc-dapm.h>
#include <sound/soc-dai.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include "cs42l43.h"
#define CS42L43_DECL_MUX(name, reg) \
static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_## name## _enum , reg, \
0, CS42L43_MIXER_SRC_MASK, \
cs42l43_mixer_texts, cs42l43_mixer_values); \
static const struct snd_kcontrol_new cs42l43_## name## _mux = \
SOC_DAPM_ENUM("Route" , cs42l43_## name## _enum )
#define CS42L43_DECL_MIXER(name, reg) \
CS42L43_DECL_MUX(name## _in1, reg); \
CS42L43_DECL_MUX(name## _in2, reg + 0x4); \
CS42L43_DECL_MUX(name## _in3, reg + 0x8); \
CS42L43_DECL_MUX(name## _in4, reg + 0xC)
#define CS42L43_DAPM_MUX(name_str, name) \
SND_SOC_DAPM_MUX(name_str " Input" , SND_SOC_NOPM, 0, 0, &cs42l43_## name## _mux)
#define CS42L43_DAPM_MIXER(name_str, name) \
SND_SOC_DAPM_MUX(name_str " Input 1" , SND_SOC_NOPM, 0, 0, &cs42l43_## name## _in1_mux), \
SND_SOC_DAPM_MUX(name_str " Input 2" , SND_SOC_NOPM, 0, 0, &cs42l43_## name## _in2_mux), \
SND_SOC_DAPM_MUX(name_str " Input 3" , SND_SOC_NOPM, 0, 0, &cs42l43_## name## _in3_mux), \
SND_SOC_DAPM_MUX(name_str " Input 4" , SND_SOC_NOPM, 0, 0, &cs42l43_## name## _in4_mux), \
SND_SOC_DAPM_MIXER(name_str " Mixer" , SND_SOC_NOPM, 0, 0, NULL, 0)
#define CS42L43_BASE_ROUTES(name_str) \
{ name_str, "Tone Generator 1" , "Tone 1" }, \
{ name_str, "Tone Generator 2" , "Tone 2" }, \
{ name_str, "Decimator 1" , "Decimator 1" }, \
{ name_str, "Decimator 2" , "Decimator 2" }, \
{ name_str, "Decimator 3" , "Decimator 3" }, \
{ name_str, "Decimator 4" , "Decimator 4" }, \
{ name_str, "ASPRX1" , "ASPRX1" }, \
{ name_str, "ASPRX2" , "ASPRX2" }, \
{ name_str, "ASPRX3" , "ASPRX3" }, \
{ name_str, "ASPRX4" , "ASPRX4" }, \
{ name_str, "ASPRX5" , "ASPRX5" }, \
{ name_str, "ASPRX6" , "ASPRX6" }, \
{ name_str, "DP5RX1" , "DP5RX1" }, \
{ name_str, "DP5RX2" , "DP5RX2" }, \
{ name_str, "DP6RX1" , "DP6RX1" }, \
{ name_str, "DP6RX2" , "DP6RX2" }, \
{ name_str, "DP7RX1" , "DP7RX1" }, \
{ name_str, "DP7RX2" , "DP7RX2" }, \
{ name_str, "ASRC INT1" , "ASRC_INT1" }, \
{ name_str, "ASRC INT2" , "ASRC_INT2" }, \
{ name_str, "ASRC INT3" , "ASRC_INT3" }, \
{ name_str, "ASRC INT4" , "ASRC_INT4" }, \
{ name_str, "ASRC DEC1" , "ASRC_DEC1" }, \
{ name_str, "ASRC DEC2" , "ASRC_DEC2" }, \
{ name_str, "ASRC DEC3" , "ASRC_DEC3" }, \
{ name_str, "ASRC DEC4" , "ASRC_DEC4" }, \
{ name_str, "ISRC1 INT1" , "ISRC1INT1" }, \
{ name_str, "ISRC1 INT2" , "ISRC1INT2" }, \
{ name_str, "ISRC1 DEC1" , "ISRC1DEC1" }, \
{ name_str, "ISRC1 DEC2" , "ISRC1DEC2" }, \
{ name_str, "ISRC2 INT1" , "ISRC2INT1" }, \
{ name_str, "ISRC2 INT2" , "ISRC2INT2" }, \
{ name_str, "ISRC2 DEC1" , "ISRC2DEC1" }, \
{ name_str, "ISRC2 DEC2" , "ISRC2DEC2" }, \
{ name_str, "EQ1" , "EQ" }, \
{ name_str, "EQ2" , "EQ" }
#define CS42L43_MUX_ROUTES(name_str, widget) \
{ widget, NULL, name_str " Input" }, \
{ name_str " Input" , NULL, "Mixer Core" }, \
CS42L43_BASE_ROUTES(name_str " Input" )
#define CS42L43_MIXER_ROUTES(name_str, widget) \
{ name_str " Mixer" , NULL, name_str " Input 1" }, \
{ name_str " Mixer" , NULL, name_str " Input 2" }, \
{ name_str " Mixer" , NULL, name_str " Input 3" }, \
{ name_str " Mixer" , NULL, name_str " Input 4" }, \
{ widget, NULL, name_str " Mixer" }, \
{ name_str " Mixer" , NULL, "Mixer Core" }, \
CS42L43_BASE_ROUTES(name_str " Input 1" ), \
CS42L43_BASE_ROUTES(name_str " Input 2" ), \
CS42L43_BASE_ROUTES(name_str " Input 3" ), \
CS42L43_BASE_ROUTES(name_str " Input 4" )
#define CS42L43_MIXER_VOLUMES(name_str, base) \
SOC_SINGLE_RANGE_TLV(name_str " Input 1 Volume" , base, \
CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
cs42l43_mixer_tlv), \
SOC_SINGLE_RANGE_TLV(name_str " Input 2 Volume" , base + 4, \
CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
cs42l43_mixer_tlv), \
SOC_SINGLE_RANGE_TLV(name_str " Input 3 Volume" , base + 8, \
CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
cs42l43_mixer_tlv), \
SOC_SINGLE_RANGE_TLV(name_str " Input 4 Volume" , base + 12, \
CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
cs42l43_mixer_tlv)
#define CS42L43_IRQ_ERROR(name) \
static irqreturn_t cs42l43_## name(int irq, void *data) \
{ \
struct cs42l43_codec *priv = data; \
dev_err(priv->dev, "Error " #name " IRQ\n" ); \
return IRQ_HANDLED; \
}
CS42L43_IRQ_ERROR(pll_lost_lock)
CS42L43_IRQ_ERROR(spkr_clock_stop)
CS42L43_IRQ_ERROR(spkl_clock_stop)
CS42L43_IRQ_ERROR(spkr_brown_out)
CS42L43_IRQ_ERROR(spkl_brown_out)
CS42L43_IRQ_ERROR(spkr_therm_shutdown)
CS42L43_IRQ_ERROR(spkl_therm_shutdown)
CS42L43_IRQ_ERROR(spkr_therm_warm)
CS42L43_IRQ_ERROR(spkl_therm_warm)
CS42L43_IRQ_ERROR(spkr_sc_detect)
CS42L43_IRQ_ERROR(spkl_sc_detect)
static void cs42l43_hp_ilimit_clear_work(struct work_struct *work)
{
struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
hp_ilimit_clear_work.work);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(priv->component);
snd_soc_dapm_mutex_lock(dapm);
priv->hp_ilimit_count--;
if (priv->hp_ilimit_count)
queue_delayed_work(system_wq, &priv->hp_ilimit_clear_work,
msecs_to_jiffies(CS42L43_HP_ILIMIT_DECAY_MS));
snd_soc_dapm_mutex_unlock(dapm);
}
static irqreturn_t cs42l43_hp_ilimit(int irq, void *data)
{
struct cs42l43_codec *priv = data;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(priv->component);
struct cs42l43 *cs42l43 = priv->core;
dev_dbg(priv->dev, "headphone ilimit IRQ\n" );
snd_soc_dapm_mutex_lock(dapm);
if (priv->hp_ilimit_count < CS42L43_HP_ILIMIT_MAX_COUNT) {
if (!priv->hp_ilimit_count)
queue_delayed_work(system_wq, &priv->hp_ilimit_clear_work,
msecs_to_jiffies(CS42L43_HP_ILIMIT_DECAY_MS));
priv->hp_ilimit_count++;
snd_soc_dapm_mutex_unlock(dapm);
return IRQ_HANDLED;
}
dev_err(priv->dev, "Disabling headphone for %dmS, due to frequent current limit\n" ,
CS42L43_HP_ILIMIT_BACKOFF_MS);
priv->hp_ilimited = true ;
// No need to wait for disable, as just disabling for a period of time
regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
CS42L43_HP_EN_MASK, 0);
snd_soc_dapm_mutex_unlock(dapm);
msleep(CS42L43_HP_ILIMIT_BACKOFF_MS);
snd_soc_dapm_mutex_lock(dapm);
if (priv->hp_ena && !priv->load_detect_running) {
unsigned long time_left;
reinit_completion(&priv->hp_startup);
regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
CS42L43_HP_EN_MASK, priv->hp_ena);
time_left = wait_for_completion_timeout(&priv->hp_startup,
msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
if (!time_left)
dev_err(priv->dev, "ilimit HP restore timed out\n" );
}
priv->hp_ilimited = false ;
snd_soc_dapm_mutex_unlock(dapm);
return IRQ_HANDLED;
}
#define CS42L43_IRQ_COMPLETE(name) \
static irqreturn_t cs42l43_## name(int irq, void *data) \
{ \
struct cs42l43_codec *priv = data; \
dev_dbg(priv->dev, #name " completed\n" ); \
complete(&priv->name); \
return IRQ_HANDLED; \
}
CS42L43_IRQ_COMPLETE(pll_ready)
CS42L43_IRQ_COMPLETE(hp_startup)
CS42L43_IRQ_COMPLETE(hp_shutdown)
CS42L43_IRQ_COMPLETE(type_detect)
CS42L43_IRQ_COMPLETE(spkr_shutdown)
CS42L43_IRQ_COMPLETE(spkl_shutdown)
CS42L43_IRQ_COMPLETE(spkr_startup)
CS42L43_IRQ_COMPLETE(spkl_startup)
CS42L43_IRQ_COMPLETE(load_detect)
static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
{
struct cs42l43_codec *priv = data;
struct snd_soc_component *component = priv->component;
int i;
dev_dbg(priv->dev, "Microphone shutter changed\n" );
if (!component)
return IRQ_NONE;
for (i = 1; i < ARRAY_SIZE(priv->kctl); i++) {
if (!priv->kctl[i])
return IRQ_NONE;
snd_ctl_notify(component->card->snd_card,
SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[i]->id);
}
return IRQ_HANDLED;
}
static irqreturn_t cs42l43_spk_shutter(int irq, void *data)
{
struct cs42l43_codec *priv = data;
struct snd_soc_component *component = priv->component;
dev_dbg(priv->dev, "Speaker shutter changed\n" );
if (!component)
return IRQ_NONE;
if (!priv->kctl[0])
return IRQ_NONE;
snd_ctl_notify(component->card->snd_card,
SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[0]->id);
return IRQ_HANDLED;
}
static const unsigned int cs42l43_sample_rates[] = {
8000, 16000, 24000, 32000, 44100, 48000, 96000, 192000,
};
#define CS42L43_CONSUMER_RATE_MASK 0xFF
#define CS42L43_PROVIDER_RATE_MASK 0xEF // 44.1k only supported as consumer
static const struct snd_pcm_hw_constraint_list cs42l43_constraint = {
.count = ARRAY_SIZE(cs42l43_sample_rates),
.list = cs42l43_sample_rates,
};
static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
int provider = !dai->id || !!regmap_test_bits(cs42l43->regmap,
CS42L43_ASP_CLK_CONFIG2,
CS42L43_ASP_MASTER_MODE_MASK);
if (provider)
priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK;
else
priv->constraint.mask = CS42L43_CONSUMER_RATE_MASK;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&priv->constraint);
}
static int cs42l43_convert_sample_rate(unsigned int rate)
{
switch (rate) {
case 8000:
return 0x11;
case 16000:
return 0x12;
case 24000:
return 0x02;
case 32000:
return 0x13;
case 44100:
return 0x0B;
case 48000:
return 0x03;
case 96000:
return 0x04;
case 192000:
return 0x05;
default :
return -EINVAL;
}
}
static int cs42l43_set_sample_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
struct cs42l43 *cs42l43 = priv->core;
int ret;
ret = cs42l43_convert_sample_rate(params_rate(params));
if (ret < 0) {
dev_err(priv->dev, "Failed to convert sample rate: %d\n" , ret);
return ret;
}
//FIXME: For now lets just set sample rate 1, this needs expanded in the future
regmap_update_bits(cs42l43->regmap, CS42L43_SAMPLE_RATE1,
CS42L43_SAMPLE_RATE_MASK, ret);
return 0;
}
static int cs42l43_asp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
struct cs42l43 *cs42l43 = priv->core;
int dsp_mode = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CTRL,
CS42L43_ASP_FSYNC_MODE_MASK);
int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
CS42L43_ASP_MASTER_MODE_MASK);
int n_chans = params_channels(params);
int data_width = params_width(params);
int n_slots = n_chans;
int slot_width = data_width;
int frame, bclk_target, i;
unsigned int reg;
int *slots;
if (priv->n_slots) {
n_slots = priv->n_slots;
slot_width = priv->slot_width;
}
if (!dsp_mode && (n_slots & 0x1)) {
dev_dbg(priv->dev, "Forcing balanced channels on ASP\n" );
n_slots++;
}
frame = n_slots * slot_width;
bclk_target = params_rate(params) * frame;
if (provider) {
unsigned int gcd_nm = gcd(bclk_target, CS42L43_INTERNAL_SYSCLK);
int n = bclk_target / gcd_nm;
int m = CS42L43_INTERNAL_SYSCLK / gcd_nm;
if (n > (CS42L43_ASP_BCLK_N_MASK >> CS42L43_ASP_BCLK_N_SHIFT) ||
m > CS42L43_ASP_BCLK_M_MASK) {
dev_err(priv->dev, "Can't produce %dHz bclk\n" , bclk_target);
return -EINVAL;
}
dev_dbg(priv->dev, "bclk %d/%d = %dHz, with %dx%d frame\n" ,
n, m, bclk_target, n_slots, slot_width);
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG1,
CS42L43_ASP_BCLK_N_MASK | CS42L43_ASP_BCLK_M_MASK,
n << CS42L43_ASP_BCLK_N_SHIFT |
m << CS42L43_ASP_BCLK_M_SHIFT);
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL1,
CS42L43_ASP_FSYNC_M_MASK, frame);
}
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL4,
CS42L43_ASP_NUM_BCLKS_PER_FSYNC_MASK,
frame << CS42L43_ASP_NUM_BCLKS_PER_FSYNC_SHIFT);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
reg = CS42L43_ASP_TX_CH1_CTRL;
slots = priv->tx_slots;
} else {
reg = CS42L43_ASP_RX_CH1_CTRL;
slots = priv->rx_slots;
}
for (i = 0; i < n_chans; i++, reg += 4) {
int slot_phase = dsp_mode | (i & CS42L43_ASP_CH_SLOT_PHASE_MASK);
int slot_pos;
if (dsp_mode)
slot_pos = slots[i] * slot_width;
else
slot_pos = (slots[i] / 2) * slot_width;
dev_dbg(priv->dev, "Configure channel %d at slot %d (%d,%d)\n" ,
i, slots[i], slot_pos, slot_phase);
regmap_update_bits(cs42l43->regmap, reg,
CS42L43_ASP_CH_WIDTH_MASK |
CS42L43_ASP_CH_SLOT_MASK |
CS42L43_ASP_CH_SLOT_PHASE_MASK,
((data_width - 1) << CS42L43_ASP_CH_WIDTH_SHIFT) |
(slot_pos << CS42L43_ASP_CH_SLOT_SHIFT) |
slot_phase);
}
return cs42l43_set_sample_rate(substream, params, dai);
}
static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
int provider = regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
CS42L43_ASP_MASTER_MODE_MASK);
struct snd_soc_dapm_route routes[] = {
{ "BCLK" , NULL, "FSYNC" },
};
unsigned int asp_ctrl = 0;
unsigned int data_ctrl = 0;
unsigned int fsync_ctrl = 0;
unsigned int clk_config = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT;
fallthrough;
case SND_SOC_DAIFMT_DSP_B:
asp_ctrl |= CS42L43_ASP_FSYNC_MODE_MASK;
data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK;
break ;
case SND_SOC_DAIFMT_I2S:
data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT;
break ;
case SND_SOC_DAIFMT_LEFT_J:
data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK;
break ;
default :
dev_err(priv->dev, "Unsupported DAI format 0x%x\n" ,
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
if (provider)
snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
break ;
case SND_SOC_DAIFMT_CBP_CFP:
if (!provider)
snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
clk_config |= CS42L43_ASP_MASTER_MODE_MASK;
break ;
default :
dev_err(priv->dev, "Unsupported ASP mode 0x%x\n" ,
fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
clk_config |= CS42L43_ASP_BCLK_INV_MASK; /* Yes BCLK_INV = NB */
break ;
case SND_SOC_DAIFMT_IB_NF:
break ;
case SND_SOC_DAIFMT_NB_IF:
clk_config |= CS42L43_ASP_BCLK_INV_MASK;
fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK |
CS42L43_ASP_FSYNC_OUT_INV_MASK;
break ;
case SND_SOC_DAIFMT_IB_IF:
fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK |
CS42L43_ASP_FSYNC_OUT_INV_MASK;
break ;
default :
dev_err(priv->dev, "Unsupported invert mode 0x%x\n" ,
fmt & SND_SOC_DAIFMT_INV_MASK);
return -EINVAL;
}
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CTRL,
CS42L43_ASP_FSYNC_MODE_MASK,
asp_ctrl);
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_DATA_CTRL,
CS42L43_ASP_FSYNC_FRAME_START_DLY_MASK |
CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK,
data_ctrl);
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
CS42L43_ASP_MASTER_MODE_MASK |
CS42L43_ASP_BCLK_INV_MASK,
clk_config);
regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL3,
CS42L43_ASP_FSYNC_IN_INV_MASK |
CS42L43_ASP_FSYNC_OUT_INV_MASK,
fsync_ctrl);
return 0;
}
static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned long mask,
int *slots, unsigned int nslots)
{
int i = 0;
int slot;
for_each_set_bit(slot, &mask, BITS_PER_TYPE(mask)) {
if (i == nslots) {
dev_warn(priv->dev, "Too many channels in TDM mask: %lx\n" ,
mask);
return ;
}
slots[i++] = slot;
}
}
static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
struct snd_soc_component *component = dai->component;
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
priv->n_slots = slots;
priv->slot_width = slot_width;
if (!slots) {
tx_mask = CS42L43_DEFAULT_SLOTS;
rx_mask = CS42L43_DEFAULT_SLOTS;
}
cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots,
ARRAY_SIZE(priv->tx_slots));
cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots,
ARRAY_SIZE(priv->rx_slots));
return 0;
}
static int cs42l43_dai_probe(struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
static const char * const controls[] = {
"Speaker Digital Switch" ,
"Decimator 1 Switch" ,
"Decimator 2 Switch" ,
"Decimator 3 Switch" ,
"Decimator 4 Switch" ,
};
int i;
static_assert(ARRAY_SIZE(controls) == ARRAY_SIZE(priv->kctl));
for (i = 0; i < ARRAY_SIZE(controls); i++) {
if (priv->kctl[i])
continue ;
priv->kctl[i] = snd_soc_component_get_kcontrol(component, controls[i]);
}
return 0;
}
static int cs42l43_dai_remove(struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int i;
for (i = 0; i < ARRAY_SIZE(priv->kctl); i++)
priv->kctl[i] = NULL;
return 0;
}
static const struct snd_soc_dai_ops cs42l43_asp_ops = {
.probe = cs42l43_dai_probe,
.remove = cs42l43_dai_remove,
.startup = cs42l43_startup,
.hw_params = cs42l43_asp_hw_params,
.set_fmt = cs42l43_asp_set_fmt,
.set_tdm_slot = cs42l43_asp_set_tdm_slot,
};
static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
int ret;
ret = cs42l43_sdw_add_peripheral(substream, params, dai);
if (ret)
return ret;
return cs42l43_set_sample_rate(substream, params, dai);
}
static const struct snd_soc_dai_ops cs42l43_sdw_ops = {
.probe = cs42l43_dai_probe,
.remove = cs42l43_dai_remove,
.startup = cs42l43_startup,
.set_stream = cs42l43_sdw_set_stream,
.hw_params = cs42l43_sdw_hw_params,
.hw_free = cs42l43_sdw_remove_peripheral,
};
#define CS42L43_ASP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define CS42L43_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver cs42l43_dais[] = {
{
.name = "cs42l43-asp" ,
.ops = &cs42l43_asp_ops,
.symmetric_rate = 1,
.capture = {
.stream_name = "ASP Capture" ,
.channels_min = 1,
.channels_max = CS42L43_ASP_MAX_CHANNELS,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_ASP_FORMATS,
},
.playback = {
.stream_name = "ASP Playback" ,
.channels_min = 1,
.channels_max = CS42L43_ASP_MAX_CHANNELS,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_ASP_FORMATS,
},
},
{
.name = "cs42l43-dp1" ,
.id = 1,
.ops = &cs42l43_sdw_ops,
.capture = {
.stream_name = "DP1 Capture" ,
.channels_min = 1,
.channels_max = 4,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
{
.name = "cs42l43-dp2" ,
.id = 2,
.ops = &cs42l43_sdw_ops,
.capture = {
.stream_name = "DP2 Capture" ,
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
{
.name = "cs42l43-dp3" ,
.id = 3,
.ops = &cs42l43_sdw_ops,
.capture = {
.stream_name = "DP3 Capture" ,
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
{
.name = "cs42l43-dp4" ,
.id = 4,
.ops = &cs42l43_sdw_ops,
.capture = {
.stream_name = "DP4 Capture" ,
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
{
.name = "cs42l43-dp5" ,
.id = 5,
.ops = &cs42l43_sdw_ops,
.playback = {
.stream_name = "DP5 Playback" ,
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
{
.name = "cs42l43-dp6" ,
.id = 6,
.ops = &cs42l43_sdw_ops,
.playback = {
.stream_name = "DP6 Playback" ,
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
{
.name = "cs42l43-dp7" ,
.id = 7,
.ops = &cs42l43_sdw_ops,
.playback = {
.stream_name = "DP7 Playback" ,
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L43_SDW_FORMATS,
},
},
};
static const DECLARE_TLV_DB_SCALE(cs42l43_mixer_tlv, -3200, 100, 0);
static const char * const cs42l43_ramp_text[] = {
"0ms/6dB" , "0.5ms/6dB" , "1ms/6dB" , "2ms/6dB" , "4ms/6dB" , "8ms/6dB" ,
"15ms/6dB" , "30ms/6dB" ,
};
static const char * const cs42l43_adc1_input_text[] = { "IN1" , "IN2" };
static SOC_ENUM_SINGLE_DECL(cs42l43_adc1_input, CS42L43_ADC_B_CTRL1,
CS42L43_ADC_AIN_SEL_SHIFT,
cs42l43_adc1_input_text);
static const struct snd_kcontrol_new cs42l43_adc1_input_ctl =
SOC_DAPM_ENUM("ADC1 Input" , cs42l43_adc1_input);
static const char * const cs42l43_dec_mode_text[] = { "ADC" , "PDM" };
static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec1_mode, cs42l43_dec_mode_text);
static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec2_mode, cs42l43_dec_mode_text);
static const struct snd_kcontrol_new cs42l43_dec_mode_ctl[] = {
SOC_DAPM_ENUM("Decimator 1 Mode" , cs42l43_dec1_mode),
SOC_DAPM_ENUM("Decimator 2 Mode" , cs42l43_dec2_mode),
};
static const char * const cs42l43_pdm_clk_text[] = {
"3.072MHz" , "1.536MHz" , "768kHz" ,
};
static SOC_ENUM_SINGLE_DECL(cs42l43_pdm1_clk, CS42L43_PDM_CONTROL,
CS42L43_PDM1_CLK_DIV_SHIFT, cs42l43_pdm_clk_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_pdm2_clk, CS42L43_PDM_CONTROL,
CS42L43_PDM2_CLK_DIV_SHIFT, cs42l43_pdm_clk_text);
static DECLARE_TLV_DB_SCALE(cs42l43_adc_tlv, -600, 600, 0);
static DECLARE_TLV_DB_SCALE(cs42l43_dec_tlv, -6400, 50, 0);
static const char * const cs42l43_wnf_corner_text[] = {
"160Hz" , "180Hz" , "200Hz" , "220Hz" , "240Hz" , "260Hz" , "280Hz" , "300Hz" ,
};
static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL1,
CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL2,
CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL3,
CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
static const char * const cs42l43_hpf_corner_text[] = {
"3Hz" , "12Hz" , "48Hz" , "96Hz" ,
};
static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL1,
CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL2,
CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL3,
CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM1_VD_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM2_VI_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM2_VD_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM3_VI_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM3_VD_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM4_VI_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text);
static DECLARE_TLV_DB_SCALE(cs42l43_speaker_tlv, -6400, 50, 0);
static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_up, CS42L43_AMP1_2_VOL_RAMP,
CS42L43_AMP1_2_VI_RAMP_SHIFT, cs42l43_ramp_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_down, CS42L43_AMP1_2_VOL_RAMP,
CS42L43_AMP1_2_VD_RAMP_SHIFT, cs42l43_ramp_text);
static DECLARE_TLV_DB_SCALE(cs42l43_headphone_tlv, -11450, 50, 1);
static const char * const cs42l43_headphone_ramp_text[] = {
"1" , "2" , "4" , "6" , "8" , "11" , "12" , "16" , "22" , "24" , "33" , "36" , "44" ,
"48" , "66" , "72" ,
};
static SOC_ENUM_SINGLE_DECL(cs42l43_headphone_ramp, CS42L43_PGAVOL,
CS42L43_HP_PATH_VOL_RAMP_SHIFT,
cs42l43_headphone_ramp_text);
static const char * const cs42l43_tone_freq_text[] = {
"1kHz" , "2kHz" , "4kHz" , "6kHz" , "8kHz" ,
};
static SOC_ENUM_SINGLE_DECL(cs42l43_tone1_freq, CS42L43_TONE_CH1_CTRL,
CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text);
static SOC_ENUM_SINGLE_DECL(cs42l43_tone2_freq, CS42L43_TONE_CH2_CTRL,
CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text);
static const char * const cs42l43_mixer_texts[] = {
"None" ,
"Tone Generator 1" , "Tone Generator 2" ,
"Decimator 1" , "Decimator 2" , "Decimator 3" , "Decimator 4" ,
"ASPRX1" , "ASPRX2" , "ASPRX3" , "ASPRX4" , "ASPRX5" , "ASPRX6" ,
"DP5RX1" , "DP5RX2" , "DP6RX1" , "DP6RX2" , "DP7RX1" , "DP7RX2" ,
"ASRC INT1" , "ASRC INT2" , "ASRC INT3" , "ASRC INT4" ,
"ASRC DEC1" , "ASRC DEC2" , "ASRC DEC3" , "ASRC DEC4" ,
"ISRC1 INT1" , "ISRC1 INT2" ,
"ISRC1 DEC1" , "ISRC1 DEC2" ,
"ISRC2 INT1" , "ISRC2 INT2" ,
"ISRC2 DEC1" , "ISRC2 DEC2" ,
"EQ1" , "EQ2" ,
};
static const unsigned int cs42l43_mixer_values[] = {
0x00, // None
0x04, 0x05, // Tone Generator 1, 2
0x10, 0x11, 0x12, 0x13, // Decimator 1, 2, 3, 4
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, // ASPRX1,2,3,4,5,6
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // DP5, 6, 7RX1, 2
0x40, 0x41, 0x42, 0x43, // ASRC INT1, 2, 3, 4
0x44, 0x45, 0x46, 0x47, // ASRC DEC1, 2, 3, 4
0x50, 0x51, // ISRC1 INT1, 2
0x52, 0x53, // ISRC1 DEC1, 2
0x54, 0x55, // ISRC2 INT1, 2
0x56, 0x57, // ISRC2 DEC1, 2
0x58, 0x59, // EQ1, 2
};
CS42L43_DECL_MUX(asptx1, CS42L43_ASPTX1_INPUT);
CS42L43_DECL_MUX(asptx2, CS42L43_ASPTX2_INPUT);
CS42L43_DECL_MUX(asptx3, CS42L43_ASPTX3_INPUT);
CS42L43_DECL_MUX(asptx4, CS42L43_ASPTX4_INPUT);
CS42L43_DECL_MUX(asptx5, CS42L43_ASPTX5_INPUT);
CS42L43_DECL_MUX(asptx6, CS42L43_ASPTX6_INPUT);
CS42L43_DECL_MUX(dp1tx1, CS42L43_SWIRE_DP1_CH1_INPUT);
CS42L43_DECL_MUX(dp1tx2, CS42L43_SWIRE_DP1_CH2_INPUT);
CS42L43_DECL_MUX(dp1tx3, CS42L43_SWIRE_DP1_CH3_INPUT);
CS42L43_DECL_MUX(dp1tx4, CS42L43_SWIRE_DP1_CH4_INPUT);
CS42L43_DECL_MUX(dp2tx1, CS42L43_SWIRE_DP2_CH1_INPUT);
CS42L43_DECL_MUX(dp2tx2, CS42L43_SWIRE_DP2_CH2_INPUT);
CS42L43_DECL_MUX(dp3tx1, CS42L43_SWIRE_DP3_CH1_INPUT);
CS42L43_DECL_MUX(dp3tx2, CS42L43_SWIRE_DP3_CH2_INPUT);
CS42L43_DECL_MUX(dp4tx1, CS42L43_SWIRE_DP4_CH1_INPUT);
CS42L43_DECL_MUX(dp4tx2, CS42L43_SWIRE_DP4_CH2_INPUT);
CS42L43_DECL_MUX(asrcint1, CS42L43_ASRC_INT1_INPUT1);
CS42L43_DECL_MUX(asrcint2, CS42L43_ASRC_INT2_INPUT1);
CS42L43_DECL_MUX(asrcint3, CS42L43_ASRC_INT3_INPUT1);
CS42L43_DECL_MUX(asrcint4, CS42L43_ASRC_INT4_INPUT1);
CS42L43_DECL_MUX(asrcdec1, CS42L43_ASRC_DEC1_INPUT1);
CS42L43_DECL_MUX(asrcdec2, CS42L43_ASRC_DEC2_INPUT1);
CS42L43_DECL_MUX(asrcdec3, CS42L43_ASRC_DEC3_INPUT1);
CS42L43_DECL_MUX(asrcdec4, CS42L43_ASRC_DEC4_INPUT1);
CS42L43_DECL_MUX(isrc1int1, CS42L43_ISRC1INT1_INPUT1);
CS42L43_DECL_MUX(isrc1int2, CS42L43_ISRC1INT2_INPUT1);
CS42L43_DECL_MUX(isrc1dec1, CS42L43_ISRC1DEC1_INPUT1);
CS42L43_DECL_MUX(isrc1dec2, CS42L43_ISRC1DEC2_INPUT1);
CS42L43_DECL_MUX(isrc2int1, CS42L43_ISRC2INT1_INPUT1);
CS42L43_DECL_MUX(isrc2int2, CS42L43_ISRC2INT2_INPUT1);
CS42L43_DECL_MUX(isrc2dec1, CS42L43_ISRC2DEC1_INPUT1);
CS42L43_DECL_MUX(isrc2dec2, CS42L43_ISRC2DEC2_INPUT1);
CS42L43_DECL_MUX(spdif1, CS42L43_SPDIF1_INPUT1);
CS42L43_DECL_MUX(spdif2, CS42L43_SPDIF2_INPUT1);
CS42L43_DECL_MIXER(eq1, CS42L43_EQ1MIX_INPUT1);
CS42L43_DECL_MIXER(eq2, CS42L43_EQ2MIX_INPUT1);
CS42L43_DECL_MIXER(amp1, CS42L43_AMP1MIX_INPUT1);
CS42L43_DECL_MIXER(amp2, CS42L43_AMP2MIX_INPUT1);
CS42L43_DECL_MIXER(amp3, CS42L43_AMP3MIX_INPUT1);
CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1);
static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_get_volsw(kcontrol, ucontrol);
snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_put_volsw(kcontrol, ucontrol);
snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_get_enum_double(kcontrol, ucontrol);
snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
snd_soc_dapm_mutex_lock(dapm);
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
snd_soc_dapm_mutex_unlock(dapm);
return ret;
}
static int cs42l43_eq_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
memcpy(ucontrol->value.integer.value, priv->eq_coeffs, sizeof (priv->eq_coeffs));
return 0;
}
static int cs42l43_eq_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
snd_soc_dapm_mutex_lock(dapm);
memcpy(priv->eq_coeffs, ucontrol->value.integer.value, sizeof (priv->eq_coeffs));
snd_soc_dapm_mutex_unlock(dapm);
return 0;
}
static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv)
{
struct cs42l43 *cs42l43 = priv->core;
mutex_lock(&priv->spk_vu_lock);
regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK);
regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
CS42L43_AMP1_2_VU_MASK, 0);
mutex_unlock(&priv->spk_vu_lock);
}
static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift)
{
struct cs42l43 *cs42l43 = priv->core;
unsigned int val;
int ret;
ret = pm_runtime_resume_and_get(priv->dev);
if (ret) {
dev_err(priv->dev, "Failed to resume for shutters: %d\n" , ret);
return ret;
}
/*
* SHUTTER_CONTROL is a mix of volatile and non-volatile bits, so must
* be cached for the non-volatiles, so drop it from the cache here so
* we force a read.
*/
ret = regcache_drop_region(cs42l43->regmap, CS42L43_SHUTTER_CONTROL,
CS42L43_SHUTTER_CONTROL);
if (ret) {
dev_err(priv->dev, "Failed to drop shutter from cache: %d\n" , ret);
goto error;
}
ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val);
if (ret) {
dev_err(priv->dev, "Failed to check shutter status: %d\n" , ret);
goto error;
}
ret = !(val & BIT(shift));
dev_dbg(priv->dev, "%s shutter is %s\n" ,
BIT(shift) == CS42L43_STATUS_MIC_SHUTTER_MUTE_MASK ? "Mic" : "Speaker" ,
ret ? "open" : "closed" );
error:
pm_runtime_put_autosuspend(priv->dev);
return ret;
}
static int cs42l43_decim_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int ret;
ret = cs42l43_shutter_get(priv, CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT);
if (ret > 0)
ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol);
else if (!ret)
ucontrol->value.integer.value[0] = ret;
return ret;
}
static int cs42l43_spk_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int ret;
ret = cs42l43_shutter_get(priv, CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT);
if (ret > 0)
ret = snd_soc_get_volsw(kcontrol, ucontrol);
else if (!ret)
ucontrol->value.integer.value[0] = ret;
return ret;
}
static int cs42l43_spk_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
int ret;
ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret > 0)
cs42l43_spk_vu_sync(priv);
return ret;
}
static const struct snd_kcontrol_new cs42l43_controls[] = {
SOC_ENUM_EXT("Jack Override" , cs42l43_jack_enum,
cs42l43_jack_get, cs42l43_jack_put),
SOC_DOUBLE_R_SX_TLV("ADC Volume" , CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2,
CS42L43_ADC_PGA_GAIN_SHIFT,
0xF, 4, cs42l43_adc_tlv),
SOC_DOUBLE("PDM1 Invert Switch" , CS42L43_DMIC_PDM_CTRL,
CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0),
SOC_DOUBLE("PDM2 Invert Switch" , CS42L43_DMIC_PDM_CTRL,
CS42L43_PDM2L_INV_SHIFT, CS42L43_PDM2R_INV_SHIFT, 1, 0),
SOC_ENUM("PDM1 Clock" , cs42l43_pdm1_clk),
SOC_ENUM("PDM2 Clock" , cs42l43_pdm2_clk),
SOC_SINGLE("Decimator 1 WNF Switch" , CS42L43_DECIM_HPF_WNF_CTRL1,
CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
SOC_SINGLE("Decimator 2 WNF Switch" , CS42L43_DECIM_HPF_WNF_CTRL2,
CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
SOC_SINGLE("Decimator 3 WNF Switch" , CS42L43_DECIM_HPF_WNF_CTRL3,
CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
SOC_SINGLE("Decimator 4 WNF Switch" , CS42L43_DECIM_HPF_WNF_CTRL4,
CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
SOC_ENUM("Decimator 1 WNF Corner Frequency" , cs42l43_dec1_wnf_corner),
SOC_ENUM("Decimator 2 WNF Corner Frequency" , cs42l43_dec2_wnf_corner),
SOC_ENUM("Decimator 3 WNF Corner Frequency" , cs42l43_dec3_wnf_corner),
SOC_ENUM("Decimator 4 WNF Corner Frequency" , cs42l43_dec4_wnf_corner),
SOC_SINGLE("Decimator 1 HPF Switch" , CS42L43_DECIM_HPF_WNF_CTRL1,
CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
SOC_SINGLE("Decimator 2 HPF Switch" , CS42L43_DECIM_HPF_WNF_CTRL2,
CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
SOC_SINGLE("Decimator 3 HPF Switch" , CS42L43_DECIM_HPF_WNF_CTRL3,
CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
SOC_SINGLE("Decimator 4 HPF Switch" , CS42L43_DECIM_HPF_WNF_CTRL4,
CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
SOC_ENUM("Decimator 1 HPF Corner Frequency" , cs42l43_dec1_hpf_corner),
SOC_ENUM("Decimator 2 HPF Corner Frequency" , cs42l43_dec2_hpf_corner),
SOC_ENUM("Decimator 3 HPF Corner Frequency" , cs42l43_dec3_hpf_corner),
SOC_ENUM("Decimator 4 HPF Corner Frequency" , cs42l43_dec4_hpf_corner),
SOC_SINGLE_TLV("Decimator 1 Volume" , CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
SOC_SINGLE_EXT("Decimator 1 Switch" , CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM1_MUTE_SHIFT, 1, 1,
cs42l43_decim_get, cs42l43_dapm_put_volsw),
SOC_SINGLE_TLV("Decimator 2 Volume" , CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
SOC_SINGLE_EXT("Decimator 2 Switch" , CS42L43_DECIM_VOL_CTRL_CH1_CH2,
CS42L43_DECIM2_MUTE_SHIFT, 1, 1,
cs42l43_decim_get, cs42l43_dapm_put_volsw),
SOC_SINGLE_TLV("Decimator 3 Volume" , CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
SOC_SINGLE_EXT("Decimator 3 Switch" , CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM3_MUTE_SHIFT, 1, 1,
cs42l43_decim_get, cs42l43_dapm_put_volsw),
SOC_SINGLE_TLV("Decimator 4 Volume" , CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
SOC_SINGLE_EXT("Decimator 4 Switch" , CS42L43_DECIM_VOL_CTRL_CH3_CH4,
CS42L43_DECIM4_MUTE_SHIFT, 1, 1,
cs42l43_decim_get, cs42l43_dapm_put_volsw),
SOC_ENUM_EXT("Decimator 1 Ramp Up" , cs42l43_dec1_ramp_up,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 1 Ramp Down" , cs42l43_dec1_ramp_down,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 2 Ramp Up" , cs42l43_dec2_ramp_up,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 2 Ramp Down" , cs42l43_dec2_ramp_down,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 3 Ramp Up" , cs42l43_dec3_ramp_up,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 3 Ramp Down" , cs42l43_dec3_ramp_down,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 4 Ramp Up" , cs42l43_dec4_ramp_up,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_ENUM_EXT("Decimator 4 Ramp Down" , cs42l43_dec4_ramp_down,
cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
SOC_DOUBLE_R_EXT("Speaker Digital Switch" ,
CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
CS42L43_AMP_MUTE_SHIFT, 1, 1,
cs42l43_spk_get, cs42l43_spk_put),
SOC_DOUBLE_R_EXT_TLV("Speaker Digital Volume" ,
CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
CS42L43_AMP_VOL_SHIFT,
0xBF, 0, snd_soc_get_volsw, cs42l43_spk_put,
cs42l43_speaker_tlv),
SOC_ENUM("Speaker Ramp Up" , cs42l43_speaker_ramp_up),
SOC_ENUM("Speaker Ramp Down" , cs42l43_speaker_ramp_down),
CS42L43_MIXER_VOLUMES("Speaker L" , CS42L43_AMP1MIX_INPUT1),
CS42L43_MIXER_VOLUMES("Speaker R" , CS42L43_AMP2MIX_INPUT1),
SOC_DOUBLE_SX_TLV("Headphone Digital Volume" , CS42L43_HPPATHVOL,
CS42L43_AMP3_PATH_VOL_SHIFT, CS42L43_AMP4_PATH_VOL_SHIFT,
0x11B, 229, cs42l43_headphone_tlv),
SOC_DOUBLE("Headphone Invert Switch" , CS42L43_DACCNFG1,
CS42L43_AMP3_INV_SHIFT, CS42L43_AMP4_INV_SHIFT, 1, 0),
SOC_SINGLE("Headphone Zero Cross Switch" , CS42L43_PGAVOL,
CS42L43_HP_PATH_VOL_ZC_SHIFT, 1, 0),
SOC_SINGLE("Headphone Ramp Switch" , CS42L43_PGAVOL,
CS42L43_HP_PATH_VOL_SFT_SHIFT, 1, 0),
SOC_ENUM("Headphone Ramp Rate" , cs42l43_headphone_ramp),
CS42L43_MIXER_VOLUMES("Headphone L" , CS42L43_AMP3MIX_INPUT1),
CS42L43_MIXER_VOLUMES("Headphone R" , CS42L43_AMP4MIX_INPUT1),
SOC_ENUM("Tone 1 Frequency" , cs42l43_tone1_freq),
SOC_ENUM("Tone 2 Frequency" , cs42l43_tone2_freq),
SOC_DOUBLE_EXT("EQ Switch" ,
CS42L43_MUTE_EQ_IN0, CS42L43_MUTE_EQ_CH1_SHIFT,
CS42L43_MUTE_EQ_CH2_SHIFT, 1, 1,
cs42l43_dapm_get_volsw, cs42l43_dapm_put_volsw),
SND_SOC_BYTES_E("EQ Coefficients" , 0, CS42L43_N_EQ_COEFFS,
cs42l43_eq_get, cs42l43_eq_put),
CS42L43_MIXER_VOLUMES("EQ1" , CS42L43_EQ1MIX_INPUT1),
CS42L43_MIXER_VOLUMES("EQ2" , CS42L43_EQ2MIX_INPUT1),
};
static int cs42l43_eq_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
unsigned int val;
int i, ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0,
CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK,
CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK);
regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0,
CS42L43_WRITE_MODE_MASK, CS42L43_WRITE_MODE_MASK);
for (i = 0; i < CS42L43_N_EQ_COEFFS; i++)
regmap_write(cs42l43->regmap, CS42L43_COEFF_DATA_IN0,
priv->eq_coeffs[i]);
regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0,
CS42L43_WRITE_MODE_MASK, 0);
return 0;
case SND_SOC_DAPM_POST_PMU:
ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_INIT_DONE0,
val, (val & CS42L43_INITIALIZE_DONE_MASK),
2000, 10000);
if (ret)
dev_err(priv->dev, "Failed to start EQs: %d\n" , ret);
regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0,
CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, 0);
return ret;
default :
return 0;
}
}
struct cs42l43_pll_config {
unsigned int freq;
unsigned int div;
unsigned int mode;
unsigned int cal;
};
static const struct cs42l43_pll_config cs42l43_pll_configs[] = {
{ 2400000, 0x50000000, 0x1, 0xA4 },
{ 3000000, 0x40000000, 0x1, 0x83 },
{ 3072000, 0x40000000, 0x3, 0x80 },
};
static int cs42l43_set_pll(struct cs42l43_codec *priv, unsigned int src,
unsigned int freq)
{
struct cs42l43 *cs42l43 = priv->core;
lockdep_assert_held(&cs42l43->pll_lock);
if (priv->refclk_src == src && priv->refclk_freq == freq)
return 0;
if (regmap_test_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK)) {
dev_err(priv->dev, "PLL active, can't change configuration\n" );
return -EBUSY;
}
switch (src) {
case CS42L43_SYSCLK_MCLK:
case CS42L43_SYSCLK_SDW:
dev_dbg(priv->dev, "Source PLL from %s at %uHz\n" ,
src ? "SoundWire" : "MCLK" , freq);
priv->refclk_src = src;
priv->refclk_freq = freq;
return 0;
default :
dev_err(priv->dev, "Invalid PLL source: 0x%x\n" , src);
return -EINVAL;
}
}
static int cs42l43_enable_pll(struct cs42l43_codec *priv)
{
static const struct reg_sequence enable_seq[] = {
{ CS42L43_OSC_DIV_SEL, 0x0, },
{ CS42L43_MCLK_SRC_SEL, CS42L43_OSC_PLL_MCLK_SEL_MASK, 5, },
};
struct cs42l43 *cs42l43 = priv->core;
const struct cs42l43_pll_config *config = NULL;
unsigned int div = 0;
unsigned int freq = priv->refclk_freq;
unsigned long time_left;
lockdep_assert_held(&cs42l43->pll_lock);
if (priv->refclk_src == CS42L43_SYSCLK_SDW) {
if (!freq)
freq = cs42l43->sdw_freq;
else if (!cs42l43->sdw_freq)
cs42l43->sdw_freq = freq;
}
dev_dbg(priv->dev, "Enabling PLL at %uHz\n" , freq);
div = fls(freq) -
fls(cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq);
freq >>= div;
if (div <= CS42L43_PLL_REFCLK_DIV_MASK) {
int i;
for (i = 0; i < ARRAY_SIZE(cs42l43_pll_configs); i++) {
if (freq == cs42l43_pll_configs[i].freq) {
config = &cs42l43_pll_configs[i];
break ;
}
}
}
if (!config) {
dev_err(priv->dev, "No suitable PLL config: 0x%x, %uHz\n" , div, freq);
return -EINVAL;
}
regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
CS42L43_PLL_REFCLK_DIV_MASK | CS42L43_PLL_REFCLK_SRC_MASK,
div << CS42L43_PLL_REFCLK_DIV_SHIFT |
priv->refclk_src << CS42L43_PLL_REFCLK_SRC_SHIFT);
regmap_write(cs42l43->regmap, CS42L43_FDIV_FRAC, config->div);
regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
CS42L43_PLL_MODE_BYPASS_500_MASK |
CS42L43_PLL_MODE_BYPASS_1029_MASK,
config->mode << CS42L43_PLL_MODE_BYPASS_1029_SHIFT);
regmap_update_bits(cs42l43->regmap, CS42L43_CAL_RATIO,
CS42L43_PLL_CAL_RATIO_MASK, config->cal);
regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
CS42L43_PLL_REFCLK_EN_MASK, CS42L43_PLL_REFCLK_EN_MASK);
reinit_completion(&priv->pll_ready);
regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
CS42L43_PLL_EN_MASK, CS42L43_PLL_EN_MASK);
time_left = wait_for_completion_timeout(&priv->pll_ready,
msecs_to_jiffies(CS42L43_PLL_TIMEOUT_MS));
if (!time_left) {
regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
CS42L43_PLL_EN_MASK, 0);
regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
CS42L43_PLL_REFCLK_EN_MASK, 0);
dev_err(priv->dev, "Timeout out waiting for PLL\n" );
return -ETIMEDOUT;
}
if (priv->refclk_src == CS42L43_SYSCLK_SDW)
cs42l43->sdw_pll_active = true ;
dev_dbg(priv->dev, "PLL locked in %ums\n" , 200 - jiffies_to_msecs(time_left));
/*
* Reads are not allowed over Soundwire without OSC_DIV2_EN or the PLL,
* but you can not change to PLL with OSC_DIV2_EN set. So ensure the whole
* change over happens under the regmap lock to prevent any reads.
*/
regmap_multi_reg_write(cs42l43->regmap, enable_seq, ARRAY_SIZE(enable_seq));
return 0;
}
static int cs42l43_disable_pll(struct cs42l43_codec *priv)
{
static const struct reg_sequence disable_seq[] = {
{ CS42L43_MCLK_SRC_SEL, 0x0, 5, },
{ CS42L43_OSC_DIV_SEL, CS42L43_OSC_DIV2_EN_MASK, },
};
struct cs42l43 *cs42l43 = priv->core;
dev_dbg(priv->dev, "Disabling PLL\n" );
lockdep_assert_held(&cs42l43->pll_lock);
regmap_multi_reg_write(cs42l43->regmap, disable_seq, ARRAY_SIZE(disable_seq));
regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK, 0);
regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
CS42L43_PLL_REFCLK_EN_MASK, 0);
cs42l43->sdw_pll_active = false ;
return 0;
}
static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
int ret;
mutex_lock(&cs42l43->pll_lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (priv->refclk_src == CS42L43_SYSCLK_MCLK) {
ret = clk_prepare_enable(priv->mclk);
if (ret) {
dev_err(priv->dev, "Failed to enable MCLK: %d\n" , ret);
break ;
}
}
ret = cs42l43_enable_pll(priv);
break ;
case SND_SOC_DAPM_POST_PMD:
ret = cs42l43_disable_pll(priv);
if (priv->refclk_src == CS42L43_SYSCLK_MCLK)
clk_disable_unprepare(priv->mclk);
break ;
default :
ret = 0;
break ;
}
mutex_unlock(&cs42l43->pll_lock);
return ret;
}
static int cs42l43_dapm_wait_completion(struct completion *pmu, struct completion *pmd,
int event, int timeout_ms)
{
unsigned long time_left;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
reinit_completion(pmu);
return 0;
case SND_SOC_DAPM_PRE_PMD:
reinit_completion(pmd);
return 0;
case SND_SOC_DAPM_POST_PMU:
time_left = wait_for_completion_timeout(pmu, msecs_to_jiffies(timeout_ms));
break ;
case SND_SOC_DAPM_POST_PMD:
time_left = wait_for_completion_timeout(pmd, msecs_to_jiffies(timeout_ms));
break ;
default :
return 0;
}
if (!time_left)
return -ETIMEDOUT;
else
return 0;
}
static int cs42l43_spkr_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
return cs42l43_dapm_wait_completion(&priv->spkr_startup,
&priv->spkr_shutdown, event,
CS42L43_SPK_TIMEOUT_MS);
}
static int cs42l43_spkl_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
return cs42l43_dapm_wait_completion(&priv->spkl_startup,
&priv->spkl_shutdown, event,
CS42L43_SPK_TIMEOUT_MS);
}
static int cs42l43_hp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
unsigned int mask = 1 << w->shift;
unsigned int val = 0;
int ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
val = mask;
fallthrough;
case SND_SOC_DAPM_PRE_PMD:
priv->hp_ena &= ~mask;
priv->hp_ena |= val;
ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
&priv->hp_shutdown, event,
CS42L43_HP_TIMEOUT_MS);
if (ret)
return ret;
if (!priv->load_detect_running && !priv->hp_ilimited)
regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
mask, val);
break ;
case SND_SOC_DAPM_POST_PMU:
case SND_SOC_DAPM_POST_PMD:
if (priv->load_detect_running || priv->hp_ilimited)
break ;
ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
&priv->hp_shutdown, event,
CS42L43_HP_TIMEOUT_MS);
if (ret)
return ret;
break ;
default :
break ;
}
return 0;
}
static int cs42l43_mic_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
unsigned int reg, ramp, mute;
unsigned int *val;
int ret;
switch (w->shift) {
case CS42L43_ADC1_EN_SHIFT:
case CS42L43_PDM1_DIN_L_EN_SHIFT:
reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
ramp = CS42L43_DECIM1_VD_RAMP_MASK;
mute = CS42L43_DECIM1_MUTE_MASK;
val = &priv->decim_cache[0];
break ;
case CS42L43_ADC2_EN_SHIFT:
case CS42L43_PDM1_DIN_R_EN_SHIFT:
reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
ramp = CS42L43_DECIM2_VD_RAMP_MASK;
mute = CS42L43_DECIM2_MUTE_MASK;
val = &priv->decim_cache[1];
break ;
case CS42L43_PDM2_DIN_L_EN_SHIFT:
reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
ramp = CS42L43_DECIM3_VD_RAMP_MASK;
mute = CS42L43_DECIM3_MUTE_MASK;
val = &priv->decim_cache[2];
break ;
case CS42L43_PDM2_DIN_R_EN_SHIFT:
reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
ramp = CS42L43_DECIM4_VD_RAMP_MASK;
mute = CS42L43_DECIM4_MUTE_MASK;
val = &priv->decim_cache[3];
break ;
default :
dev_err(priv->dev, "Invalid microphone shift: %d\n" , w->shift);
return -EINVAL;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
ret = regmap_read(cs42l43->regmap, reg, val);
if (ret) {
dev_err(priv->dev,
"Failed to cache decimator settings: %d\n" ,
ret);
return ret;
}
regmap_update_bits(cs42l43->regmap, reg, mute | ramp, mute);
break ;
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(cs42l43->regmap, reg, mute | ramp, *val);
break ;
default :
break ;
}
return 0;
}
static int cs42l43_adc_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
unsigned int mask = 1 << w->shift;
unsigned int val = 0;
int ret;
ret = cs42l43_mic_ev(w, kcontrol, event);
if (ret)
return ret;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
val = mask;
fallthrough;
case SND_SOC_DAPM_PRE_PMD:
priv->adc_ena &= ~mask;
priv->adc_ena |= val;
if (!priv->load_detect_running)
regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
mask, val);
fallthrough;
default :
return 0;
}
}
static const struct snd_soc_dapm_widget cs42l43_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL" , SND_SOC_NOPM, 0, 0, cs42l43_pll_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("ADC1_IN1_P" ),
SND_SOC_DAPM_INPUT("ADC1_IN1_N" ),
SND_SOC_DAPM_INPUT("ADC1_IN2_P" ),
SND_SOC_DAPM_INPUT("ADC1_IN2_N" ),
SND_SOC_DAPM_INPUT("ADC2_IN_P" ),
SND_SOC_DAPM_INPUT("ADC2_IN_N" ),
SND_SOC_DAPM_INPUT("PDM1_DIN" ),
SND_SOC_DAPM_INPUT("PDM2_DIN" ),
SND_SOC_DAPM_MUX("ADC1 Input" , SND_SOC_NOPM, 0, 0, &cs42l43_adc1_input_ctl),
SND_SOC_DAPM_PGA_E("ADC1" , SND_SOC_NOPM, CS42L43_ADC1_EN_SHIFT, 0, NULL, 0,
cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA_E("ADC2" , SND_SOC_NOPM, CS42L43_ADC2_EN_SHIFT, 0, NULL, 0,
cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA_E("PDM1L" , CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_L_EN_SHIFT,
0, NULL, 0, cs42l43_mic_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("PDM1R" , CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_R_EN_SHIFT,
0, NULL, 0, cs42l43_mic_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("PDM2L" , CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_L_EN_SHIFT,
0, NULL, 0, cs42l43_mic_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("PDM2R" , CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_R_EN_SHIFT,
0, NULL, 0, cs42l43_mic_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MUX("Decimator 1 Mode" , SND_SOC_NOPM, 0, 0,
&cs42l43_dec_mode_ctl[0]),
SND_SOC_DAPM_MUX("Decimator 2 Mode" , SND_SOC_NOPM, 0, 0,
&cs42l43_dec_mode_ctl[1]),
SND_SOC_DAPM_PGA("Decimator 1" , SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Decimator 2" , SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Decimator 3" , SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Decimator 4" , SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("FSYNC" , 0, CS42L43_ASP_CTRL, CS42L43_ASP_FSYNC_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("BCLK" , 1, CS42L43_ASP_CTRL, CS42L43_ASP_BCLK_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_AIF_OUT("ASPTX1" , NULL, 0,
CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH1_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("ASPTX2" , NULL, 1,
CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH2_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("ASPTX3" , NULL, 2,
CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH3_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("ASPTX4" , NULL, 3,
CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH4_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("ASPTX5" , NULL, 4,
CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH5_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("ASPTX6" , NULL, 5,
CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH6_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASPRX1" , NULL, 0,
CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH1_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASPRX2" , NULL, 1,
CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH2_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASPRX3" , NULL, 2,
CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH3_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASPRX4" , NULL, 3,
CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH4_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASPRX5" , NULL, 4,
CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH5_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("ASPRX6" , NULL, 5,
CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH6_EN_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("DP1TX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP1TX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP1TX3" , NULL, 2, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP1TX4" , NULL, 3, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP2TX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP2TX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP3TX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP3TX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP4TX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DP4TX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DP5RX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DP5RX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DP6RX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DP6RX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DP7RX1" , NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DP7RX2" , NULL, 1, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-amp" , 0, 0),
SND_SOC_DAPM_PGA_E("AMP1" , CS42L43_BLOCK_EN10, CS42L43_AMP1_EN_SHIFT, 0, NULL, 0,
cs42l43_spkl_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("AMP2" , CS42L43_BLOCK_EN10, CS42L43_AMP2_EN_SHIFT, 0, NULL, 0,
cs42l43_spkr_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("AMP1_OUT_P" ),
SND_SOC_DAPM_OUTPUT("AMP1_OUT_N" ),
SND_SOC_DAPM_OUTPUT("AMP2_OUT_P" ),
SND_SOC_DAPM_OUTPUT("AMP2_OUT_N" ),
SND_SOC_DAPM_PGA("SPDIF" , CS42L43_BLOCK_EN11, CS42L43_SPDIF_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_OUTPUT("SPDIF_TX" ),
SND_SOC_DAPM_PGA_E("HP" , SND_SOC_NOPM, CS42L43_HP_EN_SHIFT, 0, NULL, 0,
cs42l43_hp_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("AMP3_OUT" ),
SND_SOC_DAPM_OUTPUT("AMP4_OUT" ),
SND_SOC_DAPM_SIGGEN("Tone" ),
SND_SOC_DAPM_SUPPLY("Tone Generator" , CS42L43_BLOCK_EN9, CS42L43_TONE_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 1" , CS42L43_TONE_CH1_CTRL,
CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 2" , CS42L43_TONE_CH2_CTRL,
CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0),
SND_SOC_DAPM_SUPPLY("ISRC1" , CS42L43_BLOCK_EN5, CS42L43_ISRC1_BANK_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ISRC2" , CS42L43_BLOCK_EN5, CS42L43_ISRC2_BANK_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT2" , CS42L43_ISRC1_CTRL,
CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1INT1" , CS42L43_ISRC1_CTRL,
CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC2" , CS42L43_ISRC1_CTRL,
CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC1DEC1" , CS42L43_ISRC1_CTRL,
CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT2" , CS42L43_ISRC2_CTRL,
CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2INT1" , CS42L43_ISRC2_CTRL,
CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC2" , CS42L43_ISRC2_CTRL,
CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ISRC2DEC1" , CS42L43_ISRC2_CTRL,
CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASRC_INT" , CS42L43_BLOCK_EN4,
CS42L43_ASRC_INT_BANK_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("ASRC_DEC" , CS42L43_BLOCK_EN4,
CS42L43_ASRC_DEC_BANK_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_INT1" , CS42L43_ASRC_INT_ENABLES,
CS42L43_ASRC_INT1_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_INT2" , CS42L43_ASRC_INT_ENABLES,
CS42L43_ASRC_INT2_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_INT3" , CS42L43_ASRC_INT_ENABLES,
CS42L43_ASRC_INT3_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_INT4" , CS42L43_ASRC_INT_ENABLES,
CS42L43_ASRC_INT4_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_DEC1" , CS42L43_ASRC_DEC_ENABLES,
CS42L43_ASRC_DEC1_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_DEC2" , CS42L43_ASRC_DEC_ENABLES,
CS42L43_ASRC_DEC2_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_DEC3" , CS42L43_ASRC_DEC_ENABLES,
CS42L43_ASRC_DEC3_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASRC_DEC4" , CS42L43_ASRC_DEC_ENABLES,
CS42L43_ASRC_DEC4_EN_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("EQ Clock" , CS42L43_BLOCK_EN7, CS42L43_EQ_EN_SHIFT,
0, NULL, 0),
SND_SOC_DAPM_PGA_E("EQ" , CS42L43_START_EQZ0, CS42L43_START_FILTER_SHIFT,
0, NULL, 0, cs42l43_eq_ev,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("Mixer Core" , CS42L43_BLOCK_EN6, CS42L43_MIXER_EN_SHIFT,
0, NULL, 0),
CS42L43_DAPM_MUX("ASPTX1" , asptx1),
CS42L43_DAPM_MUX("ASPTX2" , asptx2),
CS42L43_DAPM_MUX("ASPTX3" , asptx3),
CS42L43_DAPM_MUX("ASPTX4" , asptx4),
CS42L43_DAPM_MUX("ASPTX5" , asptx5),
CS42L43_DAPM_MUX("ASPTX6" , asptx6),
CS42L43_DAPM_MUX("DP1TX1" , dp1tx1),
CS42L43_DAPM_MUX("DP1TX2" , dp1tx2),
CS42L43_DAPM_MUX("DP1TX3" , dp1tx3),
CS42L43_DAPM_MUX("DP1TX4" , dp1tx4),
CS42L43_DAPM_MUX("DP2TX1" , dp2tx1),
CS42L43_DAPM_MUX("DP2TX2" , dp2tx2),
CS42L43_DAPM_MUX("DP3TX1" , dp3tx1),
CS42L43_DAPM_MUX("DP3TX2" , dp3tx2),
CS42L43_DAPM_MUX("DP4TX1" , dp4tx1),
CS42L43_DAPM_MUX("DP4TX2" , dp4tx2),
CS42L43_DAPM_MUX("ASRC INT1" , asrcint1),
CS42L43_DAPM_MUX("ASRC INT2" , asrcint2),
CS42L43_DAPM_MUX("ASRC INT3" , asrcint3),
CS42L43_DAPM_MUX("ASRC INT4" , asrcint4),
CS42L43_DAPM_MUX("ASRC DEC1" , asrcdec1),
CS42L43_DAPM_MUX("ASRC DEC2" , asrcdec2),
CS42L43_DAPM_MUX("ASRC DEC3" , asrcdec3),
CS42L43_DAPM_MUX("ASRC DEC4" , asrcdec4),
CS42L43_DAPM_MUX("ISRC1INT1" , isrc1int1),
CS42L43_DAPM_MUX("ISRC1INT2" , isrc1int2),
CS42L43_DAPM_MUX("ISRC1DEC1" , isrc1dec1),
CS42L43_DAPM_MUX("ISRC1DEC2" , isrc1dec2),
CS42L43_DAPM_MUX("ISRC2INT1" , isrc2int1),
CS42L43_DAPM_MUX("ISRC2INT2" , isrc2int2),
CS42L43_DAPM_MUX("ISRC2DEC1" , isrc2dec1),
CS42L43_DAPM_MUX("ISRC2DEC2" , isrc2dec2),
CS42L43_DAPM_MUX("SPDIF1" , spdif1),
CS42L43_DAPM_MUX("SPDIF2" , spdif2),
CS42L43_DAPM_MIXER("EQ1" , eq1),
CS42L43_DAPM_MIXER("EQ2" , eq2),
CS42L43_DAPM_MIXER("Speaker L" , amp1),
CS42L43_DAPM_MIXER("Speaker R" , amp2),
CS42L43_DAPM_MIXER("Headphone L" , amp3),
CS42L43_DAPM_MIXER("Headphone R" , amp4),
};
static const struct snd_soc_dapm_route cs42l43_routes[] = {
{ "ADC1_IN1_P" , NULL, "PLL" },
{ "ADC1_IN1_N" , NULL, "PLL" },
{ "ADC1_IN2_P" , NULL, "PLL" },
{ "ADC1_IN2_N" , NULL, "PLL" },
{ "ADC2_IN_P" , NULL, "PLL" },
{ "ADC2_IN_N" , NULL, "PLL" },
{ "PDM1_DIN" , NULL, "PLL" },
{ "PDM2_DIN" , NULL, "PLL" },
{ "AMP1_OUT_P" , NULL, "PLL" },
{ "AMP1_OUT_N" , NULL, "PLL" },
{ "AMP2_OUT_P" , NULL, "PLL" },
{ "AMP2_OUT_N" , NULL, "PLL" },
{ "SPDIF_TX" , NULL, "PLL" },
{ "HP" , NULL, "PLL" },
{ "AMP3_OUT" , NULL, "PLL" },
{ "AMP4_OUT" , NULL, "PLL" },
{ "Tone 1" , NULL, "PLL" },
{ "Tone 2" , NULL, "PLL" },
{ "ASP Playback" , NULL, "PLL" },
{ "ASP Capture" , NULL, "PLL" },
{ "DP1 Capture" , NULL, "PLL" },
{ "DP2 Capture" , NULL, "PLL" },
{ "DP3 Capture" , NULL, "PLL" },
{ "DP4 Capture" , NULL, "PLL" },
{ "DP5 Playback" , NULL, "PLL" },
{ "DP6 Playback" , NULL, "PLL" },
{ "DP7 Playback" , NULL, "PLL" },
{ "ADC1 Input" , "IN1" , "ADC1_IN1_P" },
{ "ADC1 Input" , "IN1" , "ADC1_IN1_N" },
{ "ADC1 Input" , "IN2" , "ADC1_IN2_P" },
{ "ADC1 Input" , "IN2" , "ADC1_IN2_N" },
{ "ADC1" , NULL, "ADC1 Input" },
{ "ADC2" , NULL, "ADC2_IN_P" },
{ "ADC2" , NULL, "ADC2_IN_N" },
{ "PDM1L" , NULL, "PDM1_DIN" },
{ "PDM1R" , NULL, "PDM1_DIN" },
{ "PDM2L" , NULL, "PDM2_DIN" },
{ "PDM2R" , NULL, "PDM2_DIN" },
{ "Decimator 1 Mode" , "PDM" , "PDM1L" },
{ "Decimator 1 Mode" , "ADC" , "ADC1" },
{ "Decimator 2 Mode" , "PDM" , "PDM1R" },
{ "Decimator 2 Mode" , "ADC" , "ADC2" },
{ "Decimator 1" , NULL, "Decimator 1 Mode" },
{ "Decimator 2" , NULL, "Decimator 2 Mode" },
{ "Decimator 3" , NULL, "PDM2L" },
{ "Decimator 4" , NULL, "PDM2R" },
{ "ASP Capture" , NULL, "ASPTX1" },
{ "ASP Capture" , NULL, "ASPTX2" },
{ "ASP Capture" , NULL, "ASPTX3" },
{ "ASP Capture" , NULL, "ASPTX4" },
{ "ASP Capture" , NULL, "ASPTX5" },
{ "ASP Capture" , NULL, "ASPTX6" },
{ "ASPTX1" , NULL, "BCLK" },
{ "ASPTX2" , NULL, "BCLK" },
{ "ASPTX3" , NULL, "BCLK" },
{ "ASPTX4" , NULL, "BCLK" },
{ "ASPTX5" , NULL, "BCLK" },
{ "ASPTX6" , NULL, "BCLK" },
{ "ASPRX1" , NULL, "ASP Playback" },
{ "ASPRX2" , NULL, "ASP Playback" },
{ "ASPRX3" , NULL, "ASP Playback" },
{ "ASPRX4" , NULL, "ASP Playback" },
{ "ASPRX5" , NULL, "ASP Playback" },
{ "ASPRX6" , NULL, "ASP Playback" },
{ "ASPRX1" , NULL, "BCLK" },
{ "ASPRX2" , NULL, "BCLK" },
{ "ASPRX3" , NULL, "BCLK" },
{ "ASPRX4" , NULL, "BCLK" },
{ "ASPRX5" , NULL, "BCLK" },
{ "ASPRX6" , NULL, "BCLK" },
{ "DP1 Capture" , NULL, "DP1TX1" },
{ "DP1 Capture" , NULL, "DP1TX2" },
{ "DP1 Capture" , NULL, "DP1TX3" },
{ "DP1 Capture" , NULL, "DP1TX4" },
{ "DP2 Capture" , NULL, "DP2TX1" },
{ "DP2 Capture" , NULL, "DP2TX2" },
{ "DP3 Capture" , NULL, "DP3TX1" },
{ "DP3 Capture" , NULL, "DP3TX2" },
{ "DP4 Capture" , NULL, "DP4TX1" },
{ "DP4 Capture" , NULL, "DP4TX2" },
{ "DP5RX1" , NULL, "DP5 Playback" },
{ "DP5RX2" , NULL, "DP5 Playback" },
{ "DP6RX1" , NULL, "DP6 Playback" },
{ "DP6RX2" , NULL, "DP6 Playback" },
{ "DP7RX1" , NULL, "DP7 Playback" },
{ "DP7RX2" , NULL, "DP7 Playback" },
{ "AMP1" , NULL, "vdd-amp" },
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=96 H=95 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland