linux/sound/soc/codecs/wm8994.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * wm8994.c  --  WM8994 ALSA SoC Audio driver
 *
 * Copyright 2009-12 Wolfson Microelectronics plc
 *
 * Author: Mark Brown <[email protected]>
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <trace/events/asoc.h>

#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/mfd/wm8994/pdata.h>
#include <linux/mfd/wm8994/gpio.h>

#include "wm8994.h"
#include "wm_hubs.h"

#define WM1811_JACKDET_MODE_NONE
#define WM1811_JACKDET_MODE_JACK
#define WM1811_JACKDET_MODE_MIC
#define WM1811_JACKDET_MODE_AUDIO

#define WM8994_NUM_DRC
#define WM8994_NUM_EQ

struct wm8994_reg_mask {};

static struct wm8994_reg_mask wm8994_vu_bits[] =;

/* VU bitfields for ADC2, DAC2 not available on WM1811 */
static struct wm8994_reg_mask wm8994_adc2_dac2_vu_bits[] =;

static int wm8994_drc_base[] =;

static int wm8994_retune_mobile_base[] =;

static const struct wm8958_micd_rate micdet_rates[] =;

static const struct wm8958_micd_rate jackdet_rates[] =;

static void wm8958_micd_set_rate(struct snd_soc_component *component)
{}

static int configure_aif_clock(struct snd_soc_component *component, int aif)
{}

static int configure_clock(struct snd_soc_component *component)
{}

static int check_clk_sys(struct snd_soc_dapm_widget *source,
			 struct snd_soc_dapm_widget *sink)
{}

static const char *sidetone_hpf_text[] =;

static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
			    WM8994_SIDETONE, 7, sidetone_hpf_text);

static const char *adc_hpf_text[] =;

static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf,
			    WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text);

static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf,
			    WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text);

static SOC_ENUM_SINGLE_DECL(aif2adc_hpf,
			    WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);

static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);

#define WM8994_DRC_SWITCH(xname, reg, shift)

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

static void wm8994_set_drc(struct snd_soc_component *component, int drc)
{}

/* Icky as hell but saves code duplication */
static int wm8994_get_drc(const char *name)
{}

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

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

static void wm8994_set_retune_mobile(struct snd_soc_component *component, int block)
{}

/* Icky as hell but saves code duplication */
static int wm8994_get_retune_mobile_block(const char *name)
{}

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

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

static const char *aif_chan_src_text[] =;

static SOC_ENUM_SINGLE_DECL(aif1adcl_src,
			    WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif1adcr_src,
			    WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2adcl_src,
			    WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2adcr_src,
			    WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif1dacl_src,
			    WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif1dacr_src,
			    WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2dacl_src,
			    WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text);

static SOC_ENUM_SINGLE_DECL(aif2dacr_src,
			    WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);

static const char *osr_text[] =;

static SOC_ENUM_SINGLE_DECL(dac_osr,
			    WM8994_OVERSAMPLING, 0, osr_text);

static SOC_ENUM_SINGLE_DECL(adc_osr,
			    WM8994_OVERSAMPLING, 1, osr_text);

static const struct snd_kcontrol_new wm8994_common_snd_controls[] =;

/* Controls not available on WM1811 */
static const struct snd_kcontrol_new wm8994_snd_controls[] =;

static const struct snd_kcontrol_new wm8994_eq_controls[] =;

static const struct snd_kcontrol_new wm8994_drc_controls[] =;

static const char *wm8958_ng_text[] =;

static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold,
			    WM8958_AIF1_DAC1_NOISE_GATE,
			    WM8958_AIF1DAC1_NG_THR_SHIFT,
			    wm8958_ng_text);

static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold,
			    WM8958_AIF1_DAC2_NOISE_GATE,
			    WM8958_AIF1DAC2_NG_THR_SHIFT,
			    wm8958_ng_text);

static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold,
			    WM8958_AIF2_DAC_NOISE_GATE,
			    WM8958_AIF2DAC_NG_THR_SHIFT,
			    wm8958_ng_text);

static const struct snd_kcontrol_new wm8958_snd_controls[] =;

/* We run all mode setting through a function to enforce audio mode */
static void wm1811_jackdet_set_mode(struct snd_soc_component *component, u16 mode)
{}

static void active_reference(struct snd_soc_component *component)
{}

static void active_dereference(struct snd_soc_component *component)
{}

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

static void vmid_reference(struct snd_soc_component *component)
{}

static void vmid_dereference(struct snd_soc_component *component)
{}

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

static bool wm8994_check_class_w_digital(struct snd_soc_component *component)
{}

static void wm8994_update_vu_bits(struct snd_soc_component *component)
{}

static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enable)
{}

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

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

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

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

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

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

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

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

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

static const char *adc_mux_text[] =;

static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);

static const struct snd_kcontrol_new adcl_mux =;

static const struct snd_kcontrol_new adcr_mux =;

static const struct snd_kcontrol_new left_speaker_mixer[] =;

static const struct snd_kcontrol_new right_speaker_mixer[] =;

/* Debugging; dump chip status after DAPM transitions */
static int post_ev(struct snd_soc_dapm_widget *w,
	    struct snd_kcontrol *kcontrol, int event)
{}

static const struct snd_kcontrol_new aif1adc1l_mix[] =;

static const struct snd_kcontrol_new aif1adc1r_mix[] =;

static const struct snd_kcontrol_new aif1adc2l_mix[] =;

static const struct snd_kcontrol_new aif1adc2r_mix[] =;

static const struct snd_kcontrol_new aif2dac2l_mix[] =;

static const struct snd_kcontrol_new aif2dac2r_mix[] =;

#define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert)

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

static const struct snd_kcontrol_new dac1l_mix[] =;

static const struct snd_kcontrol_new dac1r_mix[] =;

static const char *sidetone_text[] =;

static SOC_ENUM_SINGLE_DECL(sidetone1_enum,
			    WM8994_SIDETONE, 0, sidetone_text);

static const struct snd_kcontrol_new sidetone1_mux =;

static SOC_ENUM_SINGLE_DECL(sidetone2_enum,
			    WM8994_SIDETONE, 1, sidetone_text);

static const struct snd_kcontrol_new sidetone2_mux =;

static const char *aif1dac_text[] =;

static const char *loopback_text[] =;

static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum,
			    WM8994_AIF1_CONTROL_2,
			    WM8994_AIF1_LOOPBACK_SHIFT,
			    loopback_text);

static const struct snd_kcontrol_new aif1_loopback =;

static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum,
			    WM8994_AIF2_CONTROL_2,
			    WM8994_AIF2_LOOPBACK_SHIFT,
			    loopback_text);

static const struct snd_kcontrol_new aif2_loopback =;

static SOC_ENUM_SINGLE_DECL(aif1dac_enum,
			    WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);

static const struct snd_kcontrol_new aif1dac_mux =;

static const char *aif2dac_text[] =;

static SOC_ENUM_SINGLE_DECL(aif2dac_enum,
			    WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);

static const struct snd_kcontrol_new aif2dac_mux =;

static const char *aif2adc_text[] =;

static SOC_ENUM_SINGLE_DECL(aif2adc_enum,
			    WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);

static const struct snd_kcontrol_new aif2adc_mux =;

static const char *aif3adc_text[] =;

static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum,
			    WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);

static const struct snd_kcontrol_new wm8994_aif3adc_mux =;

static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum,
			    WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);

static const struct snd_kcontrol_new wm8958_aif3adc_mux =;

static const char *mono_pcm_out_text[] =;

static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum,
			    WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);

static const struct snd_kcontrol_new mono_pcm_out_mux =;

static const char *aif2dac_src_text[] =;

/* Note that these two control shouldn't be simultaneously switched to AIF3 */
static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum,
			    WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);

static const struct snd_kcontrol_new aif2dacl_src_mux =;

static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum,
			    WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);

static const struct snd_kcontrol_new aif2dacr_src_mux =;

static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_dac_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_adc_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] =;

static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] =;

static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] =;

static const struct snd_soc_dapm_route intercon[] =;

static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] =;

static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] =;

static const struct snd_soc_dapm_route wm8994_revd_intercon[] =;

static const struct snd_soc_dapm_route wm8994_intercon[] =;

static const struct snd_soc_dapm_route wm8958_intercon[] =;

/* The size in bits of the FLL divide multiplied by 10
 * to allow rounding later */
#define FIXED_FLL_SIZE

struct fll_div {};

static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
				 int freq_in, int freq_out)
{}

static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
			  unsigned int freq_in, unsigned int freq_out)
{}

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

static int opclk_divs[] =;

static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
			  unsigned int freq_in, unsigned int freq_out)
{}

static int wm8994_set_mclk_rate(struct wm8994_priv *wm8994, unsigned int id,
				unsigned int *freq)
{}

static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
		int clk_id, unsigned int freq, int dir)
{}

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

int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode)
{}

static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{}

static struct {} srs[] =;

static int fs_ratios[] =;

static int bclk_divs[] =;

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

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

static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute,
			   int direction)
{}

static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
{}

static int wm8994_aif2_probe(struct snd_soc_dai *dai)
{}

#define WM8994_RATES

#define WM8994_FORMATS

static const struct snd_soc_dai_ops wm8994_aif1_dai_ops =;

static const struct snd_soc_dai_ops wm8994_aif2_dai_ops =;

static const struct snd_soc_dai_ops wm8994_aif3_dai_ops =;

static struct snd_soc_dai_driver wm8994_dai[] =;

#ifdef CONFIG_PM
static int wm8994_component_suspend(struct snd_soc_component *component)
{}

static int wm8994_component_resume(struct snd_soc_component *component)
{}
#else
#define wm8994_component_suspend
#define wm8994_component_resume
#endif

static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
{}

static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
{}

/**
 * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
 *
 * @component:   WM8994 component
 * @jack:    jack to report detection events on
 * @micbias: microphone bias to detect on
 *
 * Enable microphone detection via IRQ on the WM8994.  If GPIOs are
 * being used to bring out signals to the processor then only platform
 * data configuration is needed for WM8994 and processor GPIOs should
 * be configured using snd_soc_jack_add_gpios() instead.
 *
 * Configuration of detection levels is available via the micbias1_lvl
 * and micbias2_lvl platform data members.
 */
int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
		      int micbias)
{}
EXPORT_SYMBOL_GPL();

static void wm8994_mic_work(struct work_struct *work)
{}

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

/* Should be called with accdet_lock held */
static void wm1811_micd_stop(struct snd_soc_component *component)
{}

static void wm8958_button_det(struct snd_soc_component *component, u16 status)
{}

static void wm8958_open_circuit_work(struct work_struct *work)
{}

static void wm8958_mic_id(void *data, u16 status)
{}

/* Deferred mic detection to allow for extra settling time */
static void wm1811_mic_work(struct work_struct *work)
{}

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

static void wm1811_jackdet_bootstrap(struct work_struct *work)
{}

/**
 * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
 *
 * @component:   WM8958 component
 * @jack:    jack to report detection events on
 * @det_cb: detection callback
 * @det_cb_data: data for detection callback
 * @id_cb: mic id callback
 * @id_cb_data: data for mic id callback
 *
 * Enable microphone detection functionality for the WM8958.  By
 * default simple detection which supports the detection of up to 6
 * buttons plus video and microphone functionality is supported.
 *
 * The WM8958 has an advanced jack detection facility which is able to
 * support complex accessory detection, especially when used in
 * conjunction with external circuitry.  In order to provide maximum
 * flexiblity a callback is provided which allows a completely custom
 * detection algorithm.
 */
int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
		      wm1811_micdet_cb det_cb, void *det_cb_data,
		      wm1811_mic_id_cb id_cb, void *id_cb_data)
{}
EXPORT_SYMBOL_GPL();

static void wm8958_mic_work(struct work_struct *work)
{}

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

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

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

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

static int wm8994_component_probe(struct snd_soc_component *component)
{}

static void wm8994_component_remove(struct snd_soc_component *component)
{}

static const struct snd_soc_component_driver soc_component_dev_wm8994 =;

static int wm8994_probe(struct platform_device *pdev)
{}

static void wm8994_remove(struct platform_device *pdev)
{}

#ifdef CONFIG_PM_SLEEP
static int wm8994_suspend(struct device *dev)
{}

static int wm8994_resume(struct device *dev)
{}
#endif

static const struct dev_pm_ops wm8994_pm_ops =;

static struct platform_driver wm8994_codec_driver =;

module_platform_driver();

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