linux/sound/soc/codecs/cpcap.c

// SPDX-License-Identifier: GPL-2.0
/*
 * ALSA SoC CPCAP codec driver
 *
 * Copyright (C) 2017 - 2018 Sebastian Reichel <[email protected]>
 *
 * Very loosely based on original driver from Motorola:
 * Copyright (C) 2007 - 2009 Motorola, Inc.
 */

#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/mfd/motorola-cpcap.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/tlv.h>

/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
#define CPCAP_BIT_AUDIO_LOW_PWR
#define CPCAP_BIT_AUD_LOWPWR_SPEED
#define CPCAP_BIT_VAUDIOPRISTBY
#define CPCAP_BIT_VAUDIO_MODE1
#define CPCAP_BIT_VAUDIO_MODE0
#define CPCAP_BIT_V_AUDIO_EN

/* Register 513 CPCAP_REG_CC     --- CODEC */
#define CPCAP_BIT_CDC_CLK2
#define CPCAP_BIT_CDC_CLK1
#define CPCAP_BIT_CDC_CLK0
#define CPCAP_BIT_CDC_SR3
#define CPCAP_BIT_CDC_SR2
#define CPCAP_BIT_CDC_SR1
#define CPCAP_BIT_CDC_SR0
#define CPCAP_BIT_CDC_CLOCK_TREE_RESET
#define CPCAP_BIT_MIC2_CDC_EN
#define CPCAP_BIT_CDC_EN_RX
#define CPCAP_BIT_DF_RESET
#define CPCAP_BIT_MIC1_CDC_EN
#define CPCAP_BIT_AUDOHPF_1
#define CPCAP_BIT_AUDOHPF_0
#define CPCAP_BIT_AUDIHPF_1
#define CPCAP_BIT_AUDIHPF_0

/* Register 514 CPCAP_REG_CDI    --- CODEC Digital Audio Interface */
#define CPCAP_BIT_CDC_PLL_SEL
#define CPCAP_BIT_CLK_IN_SEL
#define CPCAP_BIT_DIG_AUD_IN
#define CPCAP_BIT_CDC_CLK_EN
#define CPCAP_BIT_CDC_DIG_AUD_FS1
#define CPCAP_BIT_CDC_DIG_AUD_FS0
#define CPCAP_BIT_MIC2_TIMESLOT2
#define CPCAP_BIT_MIC2_TIMESLOT1
#define CPCAP_BIT_MIC2_TIMESLOT0
#define CPCAP_BIT_MIC1_RX_TIMESLOT2
#define CPCAP_BIT_MIC1_RX_TIMESLOT1
#define CPCAP_BIT_MIC1_RX_TIMESLOT0
#define CPCAP_BIT_FS_INV
#define CPCAP_BIT_CLK_INV
#define CPCAP_BIT_SMB_CDC

/* Register 515 CPCAP_REG_SDAC   --- Stereo DAC */
#define CPCAP_BIT_FSYNC_CLK_IN_COMMON
#define CPCAP_BIT_SLAVE_PLL_CLK_INPUT
#define CPCAP_BIT_ST_CLOCK_TREE_RESET
#define CPCAP_BIT_DF_RESET_ST_DAC
#define CPCAP_BIT_ST_SR3
#define CPCAP_BIT_ST_SR2
#define CPCAP_BIT_ST_SR1
#define CPCAP_BIT_ST_SR0
#define CPCAP_BIT_ST_DAC_CLK2
#define CPCAP_BIT_ST_DAC_CLK1
#define CPCAP_BIT_ST_DAC_CLK0
#define CPCAP_BIT_ST_DAC_EN

/* Register 516 CPCAP_REG_SDACDI --- Stereo DAC Digital Audio Interface */
#define CPCAP_BIT_ST_L_TIMESLOT2
#define CPCAP_BIT_ST_L_TIMESLOT1
#define CPCAP_BIT_ST_L_TIMESLOT0
#define CPCAP_BIT_ST_R_TIMESLOT2
#define CPCAP_BIT_ST_R_TIMESLOT1
#define CPCAP_BIT_ST_R_TIMESLOT0
#define CPCAP_BIT_ST_DAC_CLK_IN_SEL
#define CPCAP_BIT_ST_FS_INV
#define CPCAP_BIT_ST_CLK_INV
#define CPCAP_BIT_ST_DIG_AUD_FS1
#define CPCAP_BIT_ST_DIG_AUD_FS0
#define CPCAP_BIT_DIG_AUD_IN_ST_DAC
#define CPCAP_BIT_ST_CLK_EN
#define CPCAP_BIT_SMB_ST_DAC

/* Register 517 CPCAP_REG_TXI    --- TX Interface */
#define CPCAP_BIT_PTT_TH
#define CPCAP_BIT_PTT_CMP_EN
#define CPCAP_BIT_HS_ID_TX
#define CPCAP_BIT_MB_ON2
#define CPCAP_BIT_MB_ON1L
#define CPCAP_BIT_MB_ON1R
#define CPCAP_BIT_RX_L_ENCODE
#define CPCAP_BIT_RX_R_ENCODE
#define CPCAP_BIT_MIC2_MUX
#define CPCAP_BIT_MIC2_PGA_EN
#define CPCAP_BIT_CDET_DIS
#define CPCAP_BIT_EMU_MIC_MUX
#define CPCAP_BIT_HS_MIC_MUX
#define CPCAP_BIT_MIC1_MUX
#define CPCAP_BIT_MIC1_PGA_EN
#define CPCAP_BIT_DLM

/* Register 518 CPCAP_REG_TXMP   --- Mic Gain */
#define CPCAP_BIT_MB_BIAS_R1
#define CPCAP_BIT_MB_BIAS_R0
#define CPCAP_BIT_MIC2_GAIN_4
#define CPCAP_BIT_MIC2_GAIN_3
#define CPCAP_BIT_MIC2_GAIN_2
#define CPCAP_BIT_MIC2_GAIN_1
#define CPCAP_BIT_MIC2_GAIN_0
#define CPCAP_BIT_MIC1_GAIN_4
#define CPCAP_BIT_MIC1_GAIN_3
#define CPCAP_BIT_MIC1_GAIN_2
#define CPCAP_BIT_MIC1_GAIN_1
#define CPCAP_BIT_MIC1_GAIN_0

/* Register 519 CPCAP_REG_RXOA   --- RX Output Amplifier */
#define CPCAP_BIT_UNUSED_519_15
#define CPCAP_BIT_UNUSED_519_14
#define CPCAP_BIT_UNUSED_519_13
#define CPCAP_BIT_STDAC_LOW_PWR_DISABLE
#define CPCAP_BIT_HS_LOW_PWR
#define CPCAP_BIT_HS_ID_RX
#define CPCAP_BIT_ST_HS_CP_EN
#define CPCAP_BIT_EMU_SPKR_R_EN
#define CPCAP_BIT_EMU_SPKR_L_EN
#define CPCAP_BIT_HS_L_EN
#define CPCAP_BIT_HS_R_EN
#define CPCAP_BIT_A4_LINEOUT_L_EN
#define CPCAP_BIT_A4_LINEOUT_R_EN
#define CPCAP_BIT_A2_LDSP_L_EN
#define CPCAP_BIT_A2_LDSP_R_EN
#define CPCAP_BIT_A1_EAR_EN

/* Register 520 CPCAP_REG_RXVC   --- RX Volume Control */
#define CPCAP_BIT_VOL_EXT3
#define CPCAP_BIT_VOL_EXT2
#define CPCAP_BIT_VOL_EXT1
#define CPCAP_BIT_VOL_EXT0
#define CPCAP_BIT_VOL_DAC3
#define CPCAP_BIT_VOL_DAC2
#define CPCAP_BIT_VOL_DAC1
#define CPCAP_BIT_VOL_DAC0
#define CPCAP_BIT_VOL_DAC_LSB_1dB1
#define CPCAP_BIT_VOL_DAC_LSB_1dB0
#define CPCAP_BIT_VOL_CDC3
#define CPCAP_BIT_VOL_CDC2
#define CPCAP_BIT_VOL_CDC1
#define CPCAP_BIT_VOL_CDC0
#define CPCAP_BIT_VOL_CDC_LSB_1dB1
#define CPCAP_BIT_VOL_CDC_LSB_1dB0

/* Register 521 CPCAP_REG_RXCOA  --- Codec to Output Amp Switches */
#define CPCAP_BIT_PGA_CDC_EN
#define CPCAP_BIT_CDC_SW
#define CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW
#define CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW
#define CPCAP_BIT_ALEFT_HS_CDC_SW
#define CPCAP_BIT_ARIGHT_HS_CDC_SW
#define CPCAP_BIT_A4_LINEOUT_L_CDC_SW
#define CPCAP_BIT_A4_LINEOUT_R_CDC_SW
#define CPCAP_BIT_A2_LDSP_L_CDC_SW
#define CPCAP_BIT_A2_LDSP_R_CDC_SW
#define CPCAP_BIT_A1_EAR_CDC_SW

/* Register 522 CPCAP_REG_RXSDOA --- RX Stereo DAC to Output Amp Switches */
#define CPCAP_BIT_PGA_DAC_EN
#define CPCAP_BIT_ST_DAC_SW
#define CPCAP_BIT_MONO_DAC1
#define CPCAP_BIT_MONO_DAC0
#define CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW
#define CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW
#define CPCAP_BIT_ALEFT_HS_DAC_SW
#define CPCAP_BIT_ARIGHT_HS_DAC_SW
#define CPCAP_BIT_A4_LINEOUT_L_DAC_SW
#define CPCAP_BIT_A4_LINEOUT_R_DAC_SW
#define CPCAP_BIT_A2_LDSP_L_DAC_SW
#define CPCAP_BIT_A2_LDSP_R_DAC_SW
#define CPCAP_BIT_A1_EAR_DAC_SW

/* Register 523 CPCAP_REG_RXEPOA --- RX External PGA to Output Amp Switches */
#define CPCAP_BIT_PGA_EXT_L_EN
#define CPCAP_BIT_PGA_EXT_R_EN
#define CPCAP_BIT_PGA_IN_L_SW
#define CPCAP_BIT_PGA_IN_R_SW
#define CPCAP_BIT_MONO_EXT1
#define CPCAP_BIT_MONO_EXT0
#define CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW
#define CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW
#define CPCAP_BIT_ALEFT_HS_EXT_SW
#define CPCAP_BIT_ARIGHT_HS_EXT_SW
#define CPCAP_BIT_A4_LINEOUT_L_EXT_SW
#define CPCAP_BIT_A4_LINEOUT_R_EXT_SW
#define CPCAP_BIT_A2_LDSP_L_EXT_SW
#define CPCAP_BIT_A2_LDSP_R_EXT_SW
#define CPCAP_BIT_A1_EAR_EXT_SW

/* Register 525 CPCAP_REG_A2LA --- SPK Amplifier and Clock Config for Headset */
#define CPCAP_BIT_NCP_CLK_SYNC
#define CPCAP_BIT_A2_CLK_SYNC
#define CPCAP_BIT_A2_FREE_RUN
#define CPCAP_BIT_A2_CLK2
#define CPCAP_BIT_A2_CLK1
#define CPCAP_BIT_A2_CLK0
#define CPCAP_BIT_A2_CLK_IN
#define CPCAP_BIT_A2_CONFIG

#define SLEEP_ACTIVATE_POWER
#define CLOCK_TREE_RESET_TIME

/* constants for ST delay workaround */
#define STM_STDAC_ACTIVATE_RAMP_TIME
#define STM_STDAC_EN_TEST_PRE
#define STM_STDAC_EN_TEST_POST
#define STM_STDAC_EN_ST_TEST1_PRE
#define STM_STDAC_EN_ST_TEST1_POST

struct cpcap_reg_info {};

static const struct cpcap_reg_info cpcap_default_regs[] =;

enum cpcap_dai {};

struct cpcap_audio {};

static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
			       struct snd_kcontrol *kcontrol, int event)
{}

/* Capture Gain Control: 0dB to 31dB in 1dB steps */
static const DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);

/* Playback Gain Control: -33dB to 12dB in 3dB steps */
static const DECLARE_TLV_DB_SCALE(vol_tlv, -3300, 300, 0);

static const struct snd_kcontrol_new cpcap_snd_controls[] =;

static const char * const cpcap_out_mux_texts[] =;

static const char * const cpcap_in_right_mux_texts[] =;

static const char * const cpcap_in_left_mux_texts[] =;

/*
 * input muxes use unusual register layout, so that we need to use custom
 * getter/setter methods
 */
static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_left_mux_enum,
				cpcap_in_left_mux_texts);
static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_right_mux_enum,
				cpcap_in_right_mux_texts);

/*
 * mux uses same bit in CPCAP_REG_RXCOA, CPCAP_REG_RXSDOA & CPCAP_REG_RXEPOA;
 * even though the register layout makes it look like a mixer, this is a mux.
 * Enabling multiple inputs will result in no audio being forwarded.
 */
static SOC_ENUM_SINGLE_DECL(cpcap_earpiece_mux_enum, 0, 0, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_spkr_r_mux_enum, 0, 1, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_spkr_l_mux_enum, 0, 2, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_line_r_mux_enum, 0, 3, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_line_l_mux_enum, 0, 4, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_hs_r_mux_enum, 0, 5, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts);
static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);

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

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

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

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

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

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

static const struct snd_kcontrol_new cpcap_input_left_mux =;
static const struct snd_kcontrol_new cpcap_input_right_mux =;
static const struct snd_kcontrol_new cpcap_emu_left_mux =;
static const struct snd_kcontrol_new cpcap_emu_right_mux =;
static const struct snd_kcontrol_new cpcap_hs_left_mux =;
static const struct snd_kcontrol_new cpcap_hs_right_mux =;
static const struct snd_kcontrol_new cpcap_line_left_mux =;
static const struct snd_kcontrol_new cpcap_line_right_mux =;
static const struct snd_kcontrol_new cpcap_speaker_left_mux =;
static const struct snd_kcontrol_new cpcap_speaker_right_mux =;
static const struct snd_kcontrol_new cpcap_earpiece_mux =;

static const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] =;
static const struct snd_kcontrol_new cpcap_ext_mono_mixer_controls[] =;

static const struct snd_kcontrol_new cpcap_extr_mute_control =;
static const struct snd_kcontrol_new cpcap_extl_mute_control =;

static const struct snd_kcontrol_new cpcap_voice_loopback =;

static const struct snd_soc_dapm_widget cpcap_dapm_widgets[] =;

static const struct snd_soc_dapm_route intercon[] =;

static int cpcap_set_sysclk(struct cpcap_audio *cpcap, enum cpcap_dai dai,
			    int clk_id, int freq)
{}

static int cpcap_set_samprate(struct cpcap_audio *cpcap, enum cpcap_dai dai,
			      int samplerate)
{}

static int cpcap_hifi_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{}

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

static int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
				  unsigned int fmt)
{}

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

static const struct snd_soc_dai_ops cpcap_dai_hifi_ops =;

static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params,
				 struct snd_soc_dai *dai)
{}

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

static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
				   unsigned int fmt)
{}


/*
 * Configure codec for voice call if requested.
 *
 * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt()
 * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the
 * cpcap related hardware as CPU is not involved in the voice call.
 */
static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai,
			    bool voice_call)
{}

static int cpcap_voice_set_tdm_slot(struct snd_soc_dai *dai,
				    unsigned int tx_mask, unsigned int rx_mask,
				    int slots, int slot_width)
{}

static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction)
{
	struct snd_soc_component *component = dai->component;
	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
	static const u16 reg = CPCAP_REG_RXCOA;
	static const u16 mask = BIT(CPCAP_BIT_CDC_SW);
	u16 val;

	if (mute)
		val = 0;
	else
		val = BIT(CPCAP_BIT_CDC_SW);

	dev_dbg(component->dev, "Voice mute: %d", mute);
	return regmap_update_bits(cpcap->regmap, reg, mask, val);
};

static const struct snd_soc_dai_ops cpcap_dai_voice_ops =;

static struct snd_soc_dai_driver cpcap_dai[] =;

static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
{}

static int cpcap_audio_reset(struct snd_soc_component *component,
			     bool swap_dai_configuration)
{}

static int cpcap_soc_probe(struct snd_soc_component *component)
{}

static struct snd_soc_component_driver soc_codec_dev_cpcap =;

static int cpcap_codec_probe(struct platform_device *pdev)
{}

static struct platform_driver cpcap_codec_driver =;
module_platform_driver();

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