linux/sound/soc/codecs/sgtl5000.c

// SPDX-License-Identifier: GPL-2.0
//
// sgtl5000.c  --  SGTL5000 ALSA SoC Audio driver
//
// Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/log2.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>

#include "sgtl5000.h"

#define SGTL5000_DAP_REG_OFFSET
#define SGTL5000_MAX_REG_OFFSET

/* Delay for the VAG ramp up */
#define SGTL5000_VAG_POWERUP_DELAY
/* Delay for the VAG ramp down */
#define SGTL5000_VAG_POWERDOWN_DELAY

#define SGTL5000_OUTPUTS_MUTE

/* default value of sgtl5000 registers */
static const struct reg_default sgtl5000_reg_defaults[] =;

/* AVC: Threshold dB -> register: pre-calculated values */
static const u16 avc_thr_db2reg[97] =;

/* regulator supplies for sgtl5000, VDDD is an optional external supply */
enum sgtl5000_regulator_supplies {};

/* vddd is optional supply */
static const char *supply_names[SGTL5000_SUPPLY_NUM] =;

#define LDO_VOLTAGE
#define LINREG_VDDD

enum sgtl5000_micbias_resistor {};

enum  {};

enum  {};

enum {};

/* sgtl5000 private structure in codec */
struct sgtl5000_priv {};

static inline int hp_sel_input(struct snd_soc_component *component)
{}

static inline u16 mute_output(struct snd_soc_component *component,
			      u16 mute_mask)
{}

static inline void restore_output(struct snd_soc_component *component,
				  u16 mute_mask, u16 mute_reg)
{}

static void vag_power_on(struct snd_soc_component *component, u32 source)
{}

static int vag_power_consumers(struct snd_soc_component *component,
			       u16 ana_pwr_reg, u32 source)
{}

static void vag_power_off(struct snd_soc_component *component, u32 source)
{}

/*
 * mic_bias power on/off share the same register bits with
 * output impedance of mic bias, when power on mic bias, we
 * need reclaim it to impedance value.
 * 0x0 = Powered off
 * 0x1 = 2Kohm
 * 0x2 = 4Kohm
 * 0x3 = 8Kohm
 */
static int mic_bias_event(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{}

static int vag_and_mute_control(struct snd_soc_component *component,
				 int event, int event_source)
{}

/*
 * Mute Headphone when power it up/down.
 * Control VAG power on HP power path.
 */
static int headphone_pga_event(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{}

/* As manual describes, ADC/DAC powering up/down requires
 * to mute outputs to avoid pops.
 * Control VAG power on ADC/DAC power path.
 */
static int adc_updown_depop(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{}

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

/* input sources for ADC */
static const char *adc_mux_text[] =;

static SOC_ENUM_SINGLE_DECL(adc_enum,
			    SGTL5000_CHIP_ANA_CTRL, 2,
			    adc_mux_text);

static const struct snd_kcontrol_new adc_mux =;

/* input sources for headphone */
static const char *hp_mux_text[] =;

static SOC_ENUM_SINGLE_DECL(hp_enum,
			    SGTL5000_CHIP_ANA_CTRL, 6,
			    hp_mux_text);

static const struct snd_kcontrol_new hp_mux =;

/* input sources for DAC */
static const char *dac_mux_text[] =;

static SOC_ENUM_SINGLE_DECL(dac_enum,
			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAC_SEL_SHIFT,
			    dac_mux_text);

static const struct snd_kcontrol_new dac_mux =;

/* input sources for DAP */
static const char *dap_mux_text[] =;

static SOC_ENUM_SINGLE_DECL(dap_enum,
			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAP_SEL_SHIFT,
			    dap_mux_text);

static const struct snd_kcontrol_new dap_mux =;

/* input sources for DAP mix */
static const char *dapmix_mux_text[] =;

static SOC_ENUM_SINGLE_DECL(dapmix_enum,
			    SGTL5000_CHIP_SSS_CTRL, SGTL5000_DAP_MIX_SEL_SHIFT,
			    dapmix_mux_text);

static const struct snd_kcontrol_new dapmix_mux =;


static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] =;

/* routes for sgtl5000 */
static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] =;

/* custom function to fetch info of PCM playback volume */
static int dac_info_volsw(struct snd_kcontrol *kcontrol,
			  struct snd_ctl_elem_info *uinfo)
{}

/*
 * custom function to get of PCM playback volume
 *
 * dac volume register
 * 15-------------8-7--------------0
 * | R channel vol | L channel vol |
 *  -------------------------------
 *
 * PCM volume with 0.5017 dB steps from 0 to -90 dB
 *
 * register values map to dB
 * 0x3B and less = Reserved
 * 0x3C = 0 dB
 * 0x3D = -0.5 dB
 * 0xF0 = -90 dB
 * 0xFC and greater = Muted
 *
 * register value map to userspace value
 *
 * register value	0x3c(0dB)	  0xf0(-90dB)0xfc
 *			------------------------------
 * userspace value	0xc0			     0
 */
static int dac_get_volsw(struct snd_kcontrol *kcontrol,
			 struct snd_ctl_elem_value *ucontrol)
{}

/*
 * custom function to put of PCM playback volume
 *
 * dac volume register
 * 15-------------8-7--------------0
 * | R channel vol | L channel vol |
 *  -------------------------------
 *
 * PCM volume with 0.5017 dB steps from 0 to -90 dB
 *
 * register values map to dB
 * 0x3B and less = Reserved
 * 0x3C = 0 dB
 * 0x3D = -0.5 dB
 * 0xF0 = -90 dB
 * 0xFC and greater = Muted
 *
 * userspace value map to register value
 *
 * userspace value	0xc0			     0
 *			------------------------------
 * register value	0x3c(0dB)	0xf0(-90dB)0xfc
 */
static int dac_put_volsw(struct snd_kcontrol *kcontrol,
			 struct snd_ctl_elem_value *ucontrol)
{}

/*
 * custom function to get AVC threshold
 *
 * The threshold dB is calculated by rearranging the calculation from the
 * avc_put_threshold function: register_value = 10^(dB/20) * 0.636 * 2^15 ==>
 * dB = ( fls(register_value) - 14.347 ) * 6.02
 *
 * As this calculation is expensive and the threshold dB values may not exceed
 * 0 to 96 we use pre-calculated values.
 */
static int avc_get_threshold(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{}

/*
 * custom function to put AVC threshold
 *
 * The register value is calculated by following formula:
 *                                    register_value = 10^(dB/20) * 0.636 * 2^15
 * As this calculation is expensive and the threshold dB values may not exceed
 * 0 to 96 we use pre-calculated values.
 */
static int avc_put_threshold(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{}

static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);

/* tlv for mic gain, 0db 20db 30db 40db */
static const DECLARE_TLV_DB_RANGE(mic_gain_tlv,
	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
	1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0)
);

/* tlv for DAP channels, 0% - 100% - 200% */
static const DECLARE_TLV_DB_SCALE(dap_volume, 0, 1, 0);

/* tlv for bass bands, -11.75db to 12.0db, step .25db */
static const DECLARE_TLV_DB_SCALE(bass_band, -1175, 25, 0);

/* tlv for hp volume, -51.5db to 12.0db, step .5db */
static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);

/* tlv for lineout volume, 31 steps of .5db each */
static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0);

/* tlv for dap avc max gain, 0db, 6db, 12db */
static const DECLARE_TLV_DB_SCALE(avc_max_gain, 0, 600, 0);

/* tlv for dap avc threshold, */
static const DECLARE_TLV_DB_MINMAX(avc_threshold, 0, 9600);

static const struct snd_kcontrol_new sgtl5000_snd_controls[] =;

/* mute the codec used by alsa core */
static int sgtl5000_mute_stream(struct snd_soc_dai *codec_dai, int mute, int direction)
{}

/* set codec format */
static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{}

/* set codec sysclk */
static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
				   int clk_id, unsigned int freq, int dir)
{}

/*
 * set clock according to i2s frame clock,
 * sgtl5000 provides 2 clock sources:
 * 1. sys_mclk: sample freq can only be configured to
 *	1/256, 1/384, 1/512 of sys_mclk.
 * 2. pll: can derive any audio clocks.
 *
 * clock setting rules:
 * 1. in slave mode, only sys_mclk can be used
 * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz
 * and above.
 * 3. usage of sys_mclk is preferred over pll to save power.
 */
static int sgtl5000_set_clock(struct snd_soc_component *component, int frame_rate)
{}

/*
 * Set PCM DAI bit size and sample rate.
 * input: params_rate, params_fmt
 */
static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params *params,
				  struct snd_soc_dai *dai)
{}

/*
 * set dac bias
 * common state changes:
 * startup:
 * off --> standby --> prepare --> on
 * standby --> prepare --> on
 *
 * stop:
 * on --> prepare --> standby
 */
static int sgtl5000_set_bias_level(struct snd_soc_component *component,
				   enum snd_soc_bias_level level)
{}

#define SGTL5000_FORMATS

static const struct snd_soc_dai_ops sgtl5000_ops =;

static struct snd_soc_dai_driver sgtl5000_dai =;

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

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

/*
 * This precalculated table contains all (vag_val * 100 / lo_calcntrl) results
 * to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL
 * The calculatation was done for all possible register values which
 * is the array index and the following formula: 10^((idx−15)/40) * 100
 */
static const u8 vol_quot_table[] =;

/*
 * sgtl5000 has 3 internal power supplies:
 * 1. VAG, normally set to vdda/2
 * 2. charge pump, set to different value
 *	according to voltage of vdda and vddio
 * 3. line out VAG, normally set to vddio/2
 *
 * and should be set according to:
 * 1. vddd provided by external or not
 * 2. vdda and vddio voltage value. > 3.1v or not
 */
static int sgtl5000_set_power_regs(struct snd_soc_component *component)
{}

static int sgtl5000_enable_regulators(struct i2c_client *client)
{}

static int sgtl5000_probe(struct snd_soc_component *component)
{}

static int sgtl5000_of_xlate_dai_id(struct snd_soc_component *component,
				    struct device_node *endpoint)
{}

static const struct snd_soc_component_driver sgtl5000_driver =;

static const struct regmap_config sgtl5000_regmap =;

/*
 * Write all the default values from sgtl5000_reg_defaults[] array into the
 * sgtl5000 registers, to make sure we always start with the sane registers
 * values as stated in the datasheet.
 *
 * Since sgtl5000 does not have a reset line, nor a reset command in software,
 * we follow this approach to guarantee we always start from the default values
 * and avoid problems like, not being able to probe after an audio playback
 * followed by a system reset or a 'reboot' command in Linux
 */
static void sgtl5000_fill_defaults(struct i2c_client *client)
{}

static int sgtl5000_i2c_probe(struct i2c_client *client)
{}

static void sgtl5000_i2c_remove(struct i2c_client *client)
{}

static void sgtl5000_i2c_shutdown(struct i2c_client *client)
{}

static const struct i2c_device_id sgtl5000_id[] =;

MODULE_DEVICE_TABLE(i2c, sgtl5000_id);

static const struct of_device_id sgtl5000_dt_ids[] =;
MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);

static struct i2c_driver sgtl5000_i2c_driver =;

module_i2c_driver();

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