linux/sound/soc/codecs/da9055.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * DA9055 ALSA Soc codec driver
 *
 * Copyright (c) 2012 Dialog Semiconductor
 *
 * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
 * Written by David Chen <[email protected]> and
 * Ashish Chavan <[email protected]>
 */

#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/da9055.h>

/* DA9055 register space */

/* Status Registers */
#define DA9055_STATUS1
#define DA9055_PLL_STATUS
#define DA9055_AUX_L_GAIN_STATUS
#define DA9055_AUX_R_GAIN_STATUS
#define DA9055_MIC_L_GAIN_STATUS
#define DA9055_MIC_R_GAIN_STATUS
#define DA9055_MIXIN_L_GAIN_STATUS
#define DA9055_MIXIN_R_GAIN_STATUS
#define DA9055_ADC_L_GAIN_STATUS
#define DA9055_ADC_R_GAIN_STATUS
#define DA9055_DAC_L_GAIN_STATUS
#define DA9055_DAC_R_GAIN_STATUS
#define DA9055_HP_L_GAIN_STATUS
#define DA9055_HP_R_GAIN_STATUS
#define DA9055_LINE_GAIN_STATUS

/* System Initialisation Registers */
#define DA9055_CIF_CTRL
#define DA9055_DIG_ROUTING_AIF
#define DA9055_SR
#define DA9055_REFERENCES
#define DA9055_PLL_FRAC_TOP
#define DA9055_PLL_FRAC_BOT
#define DA9055_PLL_INTEGER
#define DA9055_PLL_CTRL
#define DA9055_AIF_CLK_MODE
#define DA9055_AIF_CTRL
#define DA9055_DIG_ROUTING_DAC
#define DA9055_ALC_CTRL1

/* Input - Gain, Select and Filter Registers */
#define DA9055_AUX_L_GAIN
#define DA9055_AUX_R_GAIN
#define DA9055_MIXIN_L_SELECT
#define DA9055_MIXIN_R_SELECT
#define DA9055_MIXIN_L_GAIN
#define DA9055_MIXIN_R_GAIN
#define DA9055_ADC_L_GAIN
#define DA9055_ADC_R_GAIN
#define DA9055_ADC_FILTERS1
#define DA9055_MIC_L_GAIN
#define DA9055_MIC_R_GAIN

/* Output - Gain, Select and Filter Registers */
#define DA9055_DAC_FILTERS5
#define DA9055_DAC_FILTERS2
#define DA9055_DAC_FILTERS3
#define DA9055_DAC_FILTERS4
#define DA9055_DAC_FILTERS1
#define DA9055_DAC_L_GAIN
#define DA9055_DAC_R_GAIN
#define DA9055_CP_CTRL
#define DA9055_HP_L_GAIN
#define DA9055_HP_R_GAIN
#define DA9055_LINE_GAIN
#define DA9055_MIXOUT_L_SELECT
#define DA9055_MIXOUT_R_SELECT

/* System Controller Registers */
#define DA9055_SYSTEM_MODES_INPUT
#define DA9055_SYSTEM_MODES_OUTPUT

/* Control Registers */
#define DA9055_AUX_L_CTRL
#define DA9055_AUX_R_CTRL
#define DA9055_MIC_BIAS_CTRL
#define DA9055_MIC_L_CTRL
#define DA9055_MIC_R_CTRL
#define DA9055_MIXIN_L_CTRL
#define DA9055_MIXIN_R_CTRL
#define DA9055_ADC_L_CTRL
#define DA9055_ADC_R_CTRL
#define DA9055_DAC_L_CTRL
#define DA9055_DAC_R_CTRL
#define DA9055_HP_L_CTRL
#define DA9055_HP_R_CTRL
#define DA9055_LINE_CTRL
#define DA9055_MIXOUT_L_CTRL
#define DA9055_MIXOUT_R_CTRL

/* Configuration Registers */
#define DA9055_LDO_CTRL
#define DA9055_IO_CTRL
#define DA9055_GAIN_RAMP_CTRL
#define DA9055_MIC_CONFIG
#define DA9055_PC_COUNT
#define DA9055_CP_VOL_THRESHOLD1
#define DA9055_CP_DELAY
#define DA9055_CP_DETECTOR
#define DA9055_AIF_OFFSET
#define DA9055_DIG_CTRL
#define DA9055_ALC_CTRL2
#define DA9055_ALC_CTRL3
#define DA9055_ALC_NOISE
#define DA9055_ALC_TARGET_MIN
#define DA9055_ALC_TARGET_MAX
#define DA9055_ALC_GAIN_LIMITS
#define DA9055_ALC_ANA_GAIN_LIMITS
#define DA9055_ALC_ANTICLIP_CTRL
#define DA9055_ALC_ANTICLIP_LEVEL
#define DA9055_ALC_OFFSET_OP2M_L
#define DA9055_ALC_OFFSET_OP2U_L
#define DA9055_ALC_OFFSET_OP2M_R
#define DA9055_ALC_OFFSET_OP2U_R
#define DA9055_ALC_CIC_OP_LVL_CTRL
#define DA9055_ALC_CIC_OP_LVL_DATA
#define DA9055_DAC_NG_SETUP_TIME
#define DA9055_DAC_NG_OFF_THRESHOLD
#define DA9055_DAC_NG_ON_THRESHOLD
#define DA9055_DAC_NG_CTRL

/* SR bit fields */
#define DA9055_SR_8000
#define DA9055_SR_11025
#define DA9055_SR_12000
#define DA9055_SR_16000
#define DA9055_SR_22050
#define DA9055_SR_24000
#define DA9055_SR_32000
#define DA9055_SR_44100
#define DA9055_SR_48000
#define DA9055_SR_88200
#define DA9055_SR_96000

/* REFERENCES bit fields */
#define DA9055_BIAS_EN
#define DA9055_VMID_EN

/* PLL_CTRL bit fields */
#define DA9055_PLL_INDIV_10_20_MHZ
#define DA9055_PLL_SRM_EN
#define DA9055_PLL_EN

/* AIF_CLK_MODE bit fields */
#define DA9055_AIF_BCLKS_PER_WCLK_32
#define DA9055_AIF_BCLKS_PER_WCLK_64
#define DA9055_AIF_BCLKS_PER_WCLK_128
#define DA9055_AIF_BCLKS_PER_WCLK_256
#define DA9055_AIF_CLK_EN_SLAVE_MODE
#define DA9055_AIF_CLK_EN_MASTER_MODE

/* AIF_CTRL bit fields */
#define DA9055_AIF_FORMAT_I2S_MODE
#define DA9055_AIF_FORMAT_LEFT_J
#define DA9055_AIF_FORMAT_RIGHT_J
#define DA9055_AIF_FORMAT_DSP
#define DA9055_AIF_WORD_S16_LE
#define DA9055_AIF_WORD_S20_3LE
#define DA9055_AIF_WORD_S24_LE
#define DA9055_AIF_WORD_S32_LE

/* MIC_L_CTRL bit fields */
#define DA9055_MIC_L_MUTE_EN

/* MIC_R_CTRL bit fields */
#define DA9055_MIC_R_MUTE_EN

/* MIXIN_L_CTRL bit fields */
#define DA9055_MIXIN_L_MIX_EN

/* MIXIN_R_CTRL bit fields */
#define DA9055_MIXIN_R_MIX_EN

/* ADC_L_CTRL bit fields */
#define DA9055_ADC_L_EN

/* ADC_R_CTRL bit fields */
#define DA9055_ADC_R_EN

/* DAC_L_CTRL bit fields */
#define DA9055_DAC_L_MUTE_EN

/* DAC_R_CTRL bit fields */
#define DA9055_DAC_R_MUTE_EN

/* HP_L_CTRL bit fields */
#define DA9055_HP_L_AMP_OE

/* HP_R_CTRL bit fields */
#define DA9055_HP_R_AMP_OE

/* LINE_CTRL bit fields */
#define DA9055_LINE_AMP_OE

/* MIXOUT_L_CTRL bit fields */
#define DA9055_MIXOUT_L_MIX_EN

/* MIXOUT_R_CTRL bit fields */
#define DA9055_MIXOUT_R_MIX_EN

/* MIC bias select bit fields */
#define DA9055_MICBIAS2_EN

/* ALC_CIC_OP_LEVEL_CTRL bit fields */
#define DA9055_ALC_DATA_MIDDLE
#define DA9055_ALC_DATA_TOP
#define DA9055_ALC_CIC_OP_CHANNEL_LEFT
#define DA9055_ALC_CIC_OP_CHANNEL_RIGHT

#define DA9055_AIF_BCLK_MASK
#define DA9055_AIF_CLK_MODE_MASK
#define DA9055_AIF_FORMAT_MASK
#define DA9055_AIF_WORD_LENGTH_MASK
#define DA9055_GAIN_RAMPING_EN
#define DA9055_MICBIAS_LEVEL_MASK

#define DA9055_ALC_OFFSET_15_8
#define DA9055_ALC_OFFSET_17_16
#define DA9055_ALC_AVG_ITERATIONS

struct pll_div {};

/* PLL divisor table */
static const struct pll_div da9055_pll_div[] =;

enum clk_src {};

/* Gain and Volume */

static const DECLARE_TLV_DB_RANGE(aux_vol_tlv,
	0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0),
	/* -54dB to 15dB */
	0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
);

static const DECLARE_TLV_DB_RANGE(digital_gain_tlv,
	0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
	/* -78dB to 12dB */
	0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
);

static const DECLARE_TLV_DB_RANGE(alc_analog_gain_tlv,
	0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
	/* 0dB to 36dB */
	0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
);

static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0);
static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0);
static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0);
static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0);

/* ADC and DAC high pass filter cutoff value */
static const char * const da9055_hpf_cutoff_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff,
			    DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt);

static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff,
			    DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt);

/* ADC and DAC voice mode (8kHz) high pass cutoff value */
static const char * const da9055_vf_cutoff_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff,
			    DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt);

static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff,
			    DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt);

/* Gain ramping rate value */
static const char * const da9055_gain_ramping_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate,
			    DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt);

/* DAC noise gate setup time value */
static const char * const da9055_dac_ng_setup_time_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time,
			    DA9055_DAC_NG_SETUP_TIME, 0,
			    da9055_dac_ng_setup_time_txt);

/* DAC noise gate rampup rate value */
static const char * const da9055_dac_ng_rampup_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate,
			    DA9055_DAC_NG_SETUP_TIME, 2,
			    da9055_dac_ng_rampup_txt);

/* DAC noise gate rampdown rate value */
static const char * const da9055_dac_ng_rampdown_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate,
			    DA9055_DAC_NG_SETUP_TIME, 3,
			    da9055_dac_ng_rampdown_txt);

/* DAC soft mute rate value */
static const char * const da9055_dac_soft_mute_rate_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate,
			    DA9055_DAC_FILTERS5, 4,
			    da9055_dac_soft_mute_rate_txt);

/* DAC routing select */
static const char * const da9055_dac_src_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src,
			    DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt);

static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src,
			    DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt);

/* MIC PGA Left source select */
static const char * const da9055_mic_l_src_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src,
			    DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt);

/* MIC PGA Right source select */
static const char * const da9055_mic_r_src_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src,
			    DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt);

/* ALC Input Signal Tracking rate select */
static const char * const da9055_signal_tracking_rate_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate,
			    DA9055_ALC_CTRL3, 4,
			    da9055_signal_tracking_rate_txt);

static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate,
			    DA9055_ALC_CTRL3, 6,
			    da9055_signal_tracking_rate_txt);

/* ALC Attack Rate select */
static const char * const da9055_attack_rate_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_attack_rate,
			    DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt);

/* ALC Release Rate select */
static const char * const da9055_release_rate_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_release_rate,
			    DA9055_ALC_CTRL2, 4, da9055_release_rate_txt);

/* ALC Hold Time select */
static const char * const da9055_hold_time_txt[] =;

static SOC_ENUM_SINGLE_DECL(da9055_hold_time,
			    DA9055_ALC_CTRL3, 0, da9055_hold_time_txt);

static int da9055_get_alc_data(struct snd_soc_component *component, u8 reg_val)
{}

static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{}

static const struct snd_kcontrol_new da9055_snd_controls[] =;

/* DAPM Controls */

/* Mic PGA Left Source */
static const struct snd_kcontrol_new da9055_mic_l_mux_controls =;

/* Mic PGA Right Source */
static const struct snd_kcontrol_new da9055_mic_r_mux_controls =;

/* In Mixer Left */
static const struct snd_kcontrol_new da9055_dapm_mixinl_controls[] =;

/* In Mixer Right */
static const struct snd_kcontrol_new da9055_dapm_mixinr_controls[] =;

/* DAC Left Source */
static const struct snd_kcontrol_new da9055_dac_l_mux_controls =;

/* DAC Right Source */
static const struct snd_kcontrol_new da9055_dac_r_mux_controls =;

/* Out Mixer Left */
static const struct snd_kcontrol_new da9055_dapm_mixoutl_controls[] =;

/* Out Mixer Right */
static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] =;

/* Headphone Output Enable */
static const struct snd_kcontrol_new da9055_dapm_hp_l_control =;

static const struct snd_kcontrol_new da9055_dapm_hp_r_control =;

/* Lineout Output Enable */
static const struct snd_kcontrol_new da9055_dapm_lineout_control =;

/* DAPM widgets */
static const struct snd_soc_dapm_widget da9055_dapm_widgets[] =;

/* DAPM audio route definition */
static const struct snd_soc_dapm_route da9055_audio_map[] =;

/* Codec private data */
struct da9055_priv {};

static const struct reg_default da9055_reg_defaults[] =;

static bool da9055_volatile_register(struct device *dev,
				     unsigned int reg)
{}

/* Set DAI word length */
static int da9055_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *params,
			    struct snd_soc_dai *dai)
{}

/* Set DAI mode and Format */
static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{}

static int da9055_mute(struct snd_soc_dai *dai, int mute, int direction)
{}

#define DA9055_FORMATS

static int da9055_set_dai_sysclk(struct snd_soc_dai *codec_dai,
				 int clk_id, unsigned int freq, int dir)
{}

/*
 * da9055_set_dai_pll	: Configure the codec PLL
 * @param codec_dai	: Pointer to codec DAI
 * @param pll_id	: da9055 has only one pll, so pll_id is always zero
 * @param fref		: Input MCLK frequency
 * @param fout		: FsDM value
 * @return int		: Zero for success, negative error code for error
 *
 * Note: Supported PLL input frequencies are 11.2896MHz, 12MHz, 12.288MHz,
 *	 13MHz, 13.5MHz, 14.4MHz, 19.2MHz, 19.6MHz and 19.8MHz
 */
static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
			      int source, unsigned int fref, unsigned int fout)
{}

/* DAI operations */
static const struct snd_soc_dai_ops da9055_dai_ops =;

static struct snd_soc_dai_driver da9055_dai =;

static int da9055_set_bias_level(struct snd_soc_component *component,
				 enum snd_soc_bias_level level)
{}

static int da9055_probe(struct snd_soc_component *component)
{}

static const struct snd_soc_component_driver soc_component_dev_da9055 =;

static const struct regmap_config da9055_regmap_config =;

static int da9055_i2c_probe(struct i2c_client *i2c)
{}

/*
 * DO NOT change the device Ids. The naming is intentionally specific as both
 * the CODEC and PMIC parts of this chip are instantiated separately as I2C
 * devices (both have configurable I2C addresses, and are to all intents and
 * purposes separate). As a result there are specific DA9055 Ids for CODEC
 * and PMIC, which must be different to operate together.
 */
static const struct i2c_device_id da9055_i2c_id[] =;
MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);

#ifdef CONFIG_OF
static const struct of_device_id da9055_of_match[] =;
MODULE_DEVICE_TABLE(of, da9055_of_match);
#endif

/* I2C codec control layer */
static struct i2c_driver da9055_i2c_driver =;

module_i2c_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();