linux/sound/soc/codecs/88pm860x-codec.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
 *
 * Copyright 2010 Marvell International Ltd.
 * Author: Haojian Zhuang <[email protected]>
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <sound/jack.h>
#include <trace/events/asoc.h>

#include "88pm860x-codec.h"

#define MAX_NAME_LEN
#define REG_CACHE_SIZE
#define REG_CACHE_BASE

/* Status Register 1 (0x01) */
#define REG_STATUS_1
#define MIC_STATUS
#define HOOK_STATUS
#define HEADSET_STATUS

/* Mic Detection Register (0x37) */
#define REG_MIC_DET
#define CONTINUOUS_POLLING
#define EN_MIC_DET
#define MICDET_MASK

/* Headset Detection Register (0x38) */
#define REG_HS_DET
#define EN_HS_DET

/* Misc2 Register (0x42) */
#define REG_MISC2
#define AUDIO_PLL
#define AUDIO_SECTION_RESET
#define AUDIO_SECTION_ON

/* PCM Interface Register 2 (0xb1) */
#define PCM_INF2_BCLK
#define PCM_INF2_FS
#define PCM_INF2_MASTER
#define PCM_INF2_18WL
#define PCM_GENERAL_I2S
#define PCM_EXACT_I2S
#define PCM_LEFT_I2S
#define PCM_RIGHT_I2S
#define PCM_SHORT_FS
#define PCM_LONG_FS
#define PCM_MODE_MASK

/* I2S Interface Register 4 (0xbe) */
#define I2S_EQU_BYP

/* DAC Offset Register (0xcb) */
#define DAC_MUTE
#define MUTE_LEFT
#define MUTE_RIGHT

/* ADC Analog Register 1 (0xd0) */
#define REG_ADC_ANA_1
#define MIC1BIAS_MASK

/* Earpiece/Speaker Control Register 2 (0xda) */
#define REG_EAR2
#define RSYNC_CHANGE

/* Audio Supplies Register 2 (0xdc) */
#define REG_SUPPLIES2
#define LDO15_READY
#define LDO15_EN
#define CPUMP_READY
#define CPUMP_EN
#define AUDIO_EN
#define SUPPLY_MASK

/* Audio Enable Register 1 (0xdd) */
#define ADC_MOD_RIGHT
#define ADC_MOD_LEFT

/* Audio Enable Register 2 (0xde) */
#define ADC_LEFT
#define ADC_RIGHT

/* DAC Enable Register 2 (0xe1) */
#define DAC_LEFT
#define DAC_RIGHT
#define MODULATOR

/* Shorts Register (0xeb) */
#define REG_SHORTS
#define CLR_SHORT_LO2
#define SHORT_LO2
#define CLR_SHORT_LO1
#define SHORT_LO1
#define CLR_SHORT_HS2
#define SHORT_HS2
#define CLR_SHORT_HS1
#define SHORT_HS1

/*
 * This widget should be just after DAC & PGA in DAPM power-on sequence and
 * before DAC & PGA in DAPM power-off sequence.
 */
#define PM860X_DAPM_OUTPUT(wname, wevent)

struct pm860x_det {};

struct pm860x_priv {};

/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);

/* -9dB to 0db in 3dB steps */
static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);

/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
static const DECLARE_TLV_DB_RANGE(mic_tlv,
	0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
	1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
	2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
	3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
	4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0)
);

/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
static const DECLARE_TLV_DB_RANGE(aux_tlv,
	0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
	3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0)
);

/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
static const DECLARE_TLV_DB_RANGE(out_tlv,
	0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
	4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
	5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
	6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0)
);

static const DECLARE_TLV_DB_RANGE(st_tlv,
	0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
	2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
	4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
	6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
	8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
	10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
	14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
	18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0)
);

/* Sidetone Gain = M * 2^(-5-N) */
struct st_gain {};

static struct st_gain st_table[] =;

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

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

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

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

/* DAPM Widget Events */
/*
 * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
 * after updating these registers. Otherwise, these updated registers won't
 * be effective.
 */
static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
			      struct snd_kcontrol *kcontrol, int event)
{}

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

static const char *pm860x_opamp_texts[] =;

static const char *pm860x_pa_texts[] =;

static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum,
			    PM860X_HS1_CTRL, 5, pm860x_opamp_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum,
			    PM860X_HS2_CTRL, 5, pm860x_opamp_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum,
			    PM860X_HS1_CTRL, 3, pm860x_pa_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum,
			    PM860X_HS2_CTRL, 3, pm860x_pa_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum,
			    PM860X_LO1_CTRL, 5, pm860x_opamp_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum,
			    PM860X_LO2_CTRL, 5, pm860x_opamp_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum,
			    PM860X_LO1_CTRL, 3, pm860x_pa_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum,
			    PM860X_LO2_CTRL, 3, pm860x_pa_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum,
			    PM860X_EAR_CTRL_1, 5, pm860x_pa_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum,
			    PM860X_EAR_CTRL_2, 0, pm860x_pa_texts);

static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum,
			    PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts);

static const struct snd_kcontrol_new pm860x_snd_controls[] =;

/*
 * DAPM Controls
 */

/* AUX1 Switch */
static const struct snd_kcontrol_new aux1_switch_controls =;

/* AUX2 Switch */
static const struct snd_kcontrol_new aux2_switch_controls =;

/* Left Ex. PA Switch */
static const struct snd_kcontrol_new lepa_switch_controls =;

/* Right Ex. PA Switch */
static const struct snd_kcontrol_new repa_switch_controls =;

/* I2S Mux / Mux9 */
static const char *i2s_din_text[] =;

static SOC_ENUM_SINGLE_DECL(i2s_din_enum,
			    PM860X_I2S_IFACE_3, 1, i2s_din_text);

static const struct snd_kcontrol_new i2s_din_mux =;

/* I2S Mic Mux / Mux8 */
static const char *i2s_mic_text[] =;

static SOC_ENUM_SINGLE_DECL(i2s_mic_enum,
			    PM860X_I2S_IFACE_3, 4, i2s_mic_text);

static const struct snd_kcontrol_new i2s_mic_mux =;

/* ADCL Mux / Mux2 */
static const char *adcl_text[] =;

static SOC_ENUM_SINGLE_DECL(adcl_enum,
			    PM860X_PCM_IFACE_3, 4, adcl_text);

static const struct snd_kcontrol_new adcl_mux =;

/* ADCR Mux / Mux3 */
static const char *adcr_text[] =;

static SOC_ENUM_SINGLE_DECL(adcr_enum,
			    PM860X_PCM_IFACE_3, 2, adcr_text);

static const struct snd_kcontrol_new adcr_mux =;

/* ADCR EC Mux / Mux6 */
static const char *adcr_ec_text[] =;

static SOC_ENUM_SINGLE_DECL(adcr_ec_enum,
			    PM860X_ADC_EN_2, 3, adcr_ec_text);

static const struct snd_kcontrol_new adcr_ec_mux =;

/* EC Mux / Mux4 */
static const char *ec_text[] =;

static SOC_ENUM_SINGLE_DECL(ec_enum,
			    PM860X_EC_PATH, 1, ec_text);

static const struct snd_kcontrol_new ec_mux =;

static const char *dac_text[] =;

/* DAC Headset 1 Mux / Mux10 */
static SOC_ENUM_SINGLE_DECL(dac_hs1_enum,
			    PM860X_ANA_INPUT_SEL_1, 0, dac_text);

static const struct snd_kcontrol_new dac_hs1_mux =;

/* DAC Headset 2 Mux / Mux11 */
static SOC_ENUM_SINGLE_DECL(dac_hs2_enum,
			    PM860X_ANA_INPUT_SEL_1, 2, dac_text);

static const struct snd_kcontrol_new dac_hs2_mux =;

/* DAC Lineout 1 Mux / Mux12 */
static SOC_ENUM_SINGLE_DECL(dac_lo1_enum,
			    PM860X_ANA_INPUT_SEL_1, 4, dac_text);

static const struct snd_kcontrol_new dac_lo1_mux =;

/* DAC Lineout 2 Mux / Mux13 */
static SOC_ENUM_SINGLE_DECL(dac_lo2_enum,
			    PM860X_ANA_INPUT_SEL_1, 6, dac_text);

static const struct snd_kcontrol_new dac_lo2_mux =;

/* DAC Spearker Earphone Mux / Mux14 */
static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum,
			    PM860X_ANA_INPUT_SEL_2, 0, dac_text);

static const struct snd_kcontrol_new dac_spk_ear_mux =;

/* Headset 1 Mux / Mux15 */
static const char *in_text[] =;

static SOC_ENUM_SINGLE_DECL(hs1_enum,
			    PM860X_ANA_TO_ANA, 0, in_text);

static const struct snd_kcontrol_new hs1_mux =;

/* Headset 2 Mux / Mux16 */
static SOC_ENUM_SINGLE_DECL(hs2_enum,
			    PM860X_ANA_TO_ANA, 1, in_text);

static const struct snd_kcontrol_new hs2_mux =;

/* Lineout 1 Mux / Mux17 */
static SOC_ENUM_SINGLE_DECL(lo1_enum,
			    PM860X_ANA_TO_ANA, 2, in_text);

static const struct snd_kcontrol_new lo1_mux =;

/* Lineout 2 Mux / Mux18 */
static SOC_ENUM_SINGLE_DECL(lo2_enum,
			    PM860X_ANA_TO_ANA, 3, in_text);

static const struct snd_kcontrol_new lo2_mux =;

/* Speaker Earpiece Demux */
static const char *spk_text[] =;

static SOC_ENUM_SINGLE_DECL(spk_enum,
			    PM860X_ANA_TO_ANA, 6, spk_text);

static const struct snd_kcontrol_new spk_demux =;

/* MIC Mux / Mux1 */
static const char *mic_text[] =;

static SOC_ENUM_SINGLE_DECL(mic_enum,
			    PM860X_ADC_ANA_4, 4, mic_text);

static const struct snd_kcontrol_new mic_mux =;

static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] =;

static const struct snd_soc_dapm_route pm860x_dapm_routes[] =;

/*
 * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
 * These bits can also be used to mute.
 */
static int pm860x_mute_stream(struct snd_soc_dai *codec_dai, int mute, int direction)
{}

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

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

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

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

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

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

static const struct snd_soc_dai_ops pm860x_pcm_dai_ops =;

static const struct snd_soc_dai_ops pm860x_i2s_dai_ops =;

#define PM860X_RATES

static struct snd_soc_dai_driver pm860x_dai[] =;

static irqreturn_t pm860x_component_handler(int irq, void *data)
{}

int pm860x_hs_jack_detect(struct snd_soc_component *component,
			  struct snd_soc_jack *jack,
			  int det, int hook, int hs_shrt, int lo_shrt)
{}
EXPORT_SYMBOL_GPL();

int pm860x_mic_jack_detect(struct snd_soc_component *component,
			   struct snd_soc_jack *jack, int det)
{}
EXPORT_SYMBOL_GPL();

static int pm860x_probe(struct snd_soc_component *component)
{}

static void pm860x_remove(struct snd_soc_component *component)
{}

static const struct snd_soc_component_driver soc_component_dev_pm860x =;

static int pm860x_codec_probe(struct platform_device *pdev)
{}

static struct platform_driver pm860x_codec_driver =;

module_platform_driver();

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