linux/sound/soc/codecs/nau8825.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Nuvoton NAU8825 audio codec driver
 *
 * Copyright 2015 Google Chromium project.
 *  Author: Anatol Pomozov <[email protected]>
 * Copyright 2015 Nuvoton Technology Corp.
 *  Co-author: Meng-Huang Kuo <[email protected]>
 */

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/int_log.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/acpi.h>
#include <linux/math64.h>
#include <linux/semaphore.h>

#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>


#include "nau8825.h"


#define NUVOTON_CODEC_DAI

#define NAU_FREF_MAX
#define NAU_FVCO_MAX
#define NAU_FVCO_MIN

/* cross talk suppression detection */
#define GAIN_AUGMENT
#define SIDETONE_BASE

/* the maximum frequency of CLK_ADC and CLK_DAC */
#define CLK_DA_AD_MAX

static int nau8825_configure_sysclk(struct nau8825 *nau8825,
		int clk_id, unsigned int freq);
static bool nau8825_is_jack_inserted(struct regmap *regmap);

struct nau8825_fll {};

struct nau8825_fll_attr {};

/* scaling for mclk from sysclk_src output */
static const struct nau8825_fll_attr mclk_src_scaling[] =;

/* ratio for input clk freq */
static const struct nau8825_fll_attr fll_ratio[] =;

static const struct nau8825_fll_attr fll_pre_scalar[] =;

/* over sampling rate */
struct nau8825_osr_attr {};

static const struct nau8825_osr_attr osr_dac_sel[] =;

static const struct nau8825_osr_attr osr_adc_sel[] =;

static const struct reg_default nau8825_reg_defaults[] =;

/* register backup table when cross talk detection */
static struct reg_default nau8825_xtalk_baktab[] =;

/* The regmap patch for Rev C */
static const struct reg_sequence nau8825_regmap_patch[] =;

/**
 * nau8825_sema_acquire - acquire the semaphore of nau88l25
 * @nau8825:  component to register the codec private data with
 * @timeout: how long in jiffies to wait before failure or zero to wait
 * until release
 *
 * Attempts to acquire the semaphore with number of jiffies. If no more
 * tasks are allowed to acquire the semaphore, calling this function will
 * put the task to sleep. If the semaphore is not released within the
 * specified number of jiffies, this function returns.
 * If the semaphore is not released within the specified number of jiffies,
 * this function returns -ETIME. If the sleep is interrupted by a signal,
 * this function will return -EINTR. It returns 0 if the semaphore was
 * acquired successfully.
 *
 * Acquires the semaphore without jiffies. Try to acquire the semaphore
 * atomically. Returns 0 if the semaphore has been acquired successfully
 * or 1 if it cannot be acquired.
 */
static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout)
{}

/**
 * nau8825_sema_release - release the semaphore of nau88l25
 * @nau8825:  component to register the codec private data with
 *
 * Release the semaphore which may be called from any context and
 * even by tasks which have never called down().
 */
static inline void nau8825_sema_release(struct nau8825 *nau8825)
{}

/**
 * nau8825_sema_reset - reset the semaphore for nau88l25
 * @nau8825:  component to register the codec private data with
 *
 * Reset the counter of the semaphore. Call this function to restart
 * a new round task management.
 */
static inline void nau8825_sema_reset(struct nau8825 *nau8825)
{}

/**
 * nau8825_hpvol_ramp - Ramp up the headphone volume change gradually to target level.
 *
 * @nau8825:  component to register the codec private data with
 * @vol_from: the volume to start up
 * @vol_to: the target volume
 * @step: the volume span to move on
 *
 * The headphone volume is from 0dB to minimum -54dB and -1dB per step.
 * If the volume changes sharp, there is a pop noise heard in headphone. We
 * provide the function to ramp up the volume up or down by delaying 10ms
 * per step.
 */
static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
	unsigned int vol_from, unsigned int vol_to, unsigned int step)
{}

/**
 * nau8825_intlog10_dec3 - Computes log10 of a value, rounding the result to 3 decimal places.
 * @value:  input for log10
 *
 * return log10(value) * 1000
 */
static u32 nau8825_intlog10_dec3(u32 value)
{}

/**
 * nau8825_xtalk_sidetone - computes cross talk suppression sidetone gain.
 *
 * @sig_org: orignal signal level
 * @sig_cros: cross talk signal level
 *
 * The orignal and cross talk signal vlues need to be characterized.
 * Once these values have been characterized, this sidetone value
 * can be converted to decibel with the equation below.
 * sidetone = 20 * log (original signal level / crosstalk signal level)
 *
 * return cross talk sidetone gain
 */
static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
{}

static int nau8825_xtalk_baktab_index_by_reg(unsigned int reg)
{}

static void nau8825_xtalk_backup(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_restore(struct nau8825 *nau8825, bool cause_cancel)
{}

static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_prepare_adc(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_clock(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_prepare(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_clean(struct nau8825 *nau8825, bool cause_cancel)
{}

static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol)
{}

static void nau8825_xtalk_imm_stop(struct nau8825 *nau8825)
{}

/* The cross talk measurement function can reduce cross talk across the
 * JKTIP(HPL) and JKR1(HPR) outputs which measures the cross talk signal
 * level to determine what cross talk reduction gain is. This system works by
 * sending a 23Hz -24dBV sine wave into the headset output DAC and through
 * the PGA. The output of the PGA is then connected to an internal current
 * sense which measures the attenuated 23Hz signal and passing the output to
 * an ADC which converts the measurement to a binary code. With two separated
 * measurement, one for JKR1(HPR) and the other JKTIP(HPL), measurement data
 * can be separated read in IMM_RMS_L for HSR and HSL after each measurement.
 * Thus, the measurement function has four states to complete whole sequence.
 * 1. Prepare state : Prepare the resource for detection and transfer to HPR
 *     IMM stat to make JKR1(HPR) impedance measure.
 * 2. HPR IMM state : Read out orignal signal level of JKR1(HPR) and transfer
 *     to HPL IMM state to make JKTIP(HPL) impedance measure.
 * 3. HPL IMM state : Read out cross talk signal level of JKTIP(HPL) and
 *     transfer to IMM state to determine suppression sidetone gain.
 * 4. IMM state : Computes cross talk suppression sidetone gain with orignal
 *     and cross talk signal level. Apply this gain and then restore codec
 *     configuration. Then transfer to Done state for ending.
 */
static void nau8825_xtalk_measure(struct nau8825 *nau8825)
{}

static void nau8825_xtalk_work(struct work_struct *work)
{}

static void nau8825_xtalk_cancel(struct nau8825 *nau8825)
{}

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

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

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

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

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

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

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

static int system_clock_control(struct snd_soc_dapm_widget *w,
				struct snd_kcontrol *k, int  event)
{}

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

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

static const char * const nau8825_biq_path[] =;

static const struct soc_enum nau8825_biq_path_enum =;

static const char * const nau8825_adc_decimation[] =;

static const struct soc_enum nau8825_adc_decimation_enum =;

static const char * const nau8825_dac_oversampl[] =;

static const struct soc_enum nau8825_dac_oversampl_enum =;

static const DECLARE_TLV_DB_MINMAX_MUTE(adc_vol_tlv, -10300, 2400);
static const DECLARE_TLV_DB_MINMAX_MUTE(sidetone_vol_tlv, -4200, 0);
static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -5400, 0);
static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600);
static const DECLARE_TLV_DB_MINMAX_MUTE(crosstalk_vol_tlv, -9600, 2400);

static const struct snd_kcontrol_new nau8825_controls[] =;

/* DAC Mux 0x33[9] and 0x34[9] */
static const char * const nau8825_dac_src[] =;

static SOC_ENUM_SINGLE_DECL(
	nau8825_dacl_enum, NAU8825_REG_DACL_CTRL,
	NAU8825_DACL_CH_SEL_SFT, nau8825_dac_src);

static SOC_ENUM_SINGLE_DECL(
	nau8825_dacr_enum, NAU8825_REG_DACR_CTRL,
	NAU8825_DACR_CH_SEL_SFT, nau8825_dac_src);

static const struct snd_kcontrol_new nau8825_dacl_mux =;

static const struct snd_kcontrol_new nau8825_dacr_mux =;


static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] =;

static const struct snd_soc_dapm_route nau8825_dapm_routes[] =;

static const struct nau8825_osr_attr *
nau8825_get_osr(struct nau8825 *nau8825, int stream)
{}

static int nau8825_dai_startup(struct snd_pcm_substream *substream,
			       struct snd_soc_dai *dai)
{}

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

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

/**
 * nau8825_set_tdm_slot - configure DAI TDM.
 * @dai: DAI
 * @tx_mask: bitmask representing active TX slots.
 * @rx_mask: bitmask representing active RX slots.
 * @slots: Number of slots in use.
 * @slot_width: Width in bits for each slot.
 *
 * Configures a DAI for TDM operation. Support TDM 4/8 slots.
 * The limitation is DAC and ADC need shift 4 slots at 8 slots mode.
 */
static int nau8825_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
				unsigned int rx_mask, int slots, int slot_width)
{}

static const struct snd_soc_dai_ops nau8825_dai_ops =;

#define NAU8825_RATES
#define NAU8825_FORMATS

static struct snd_soc_dai_driver nau8825_dai =;

/**
 * nau8825_enable_jack_detect - Specify a jack for event reporting
 *
 * @component:  component to register the jack with
 * @jack: jack to use to report headset and button events on
 *
 * After this function has been called the headset insert/remove and button
 * events will be routed to the given jack.  Jack can be null to stop
 * reporting.
 */
int nau8825_enable_jack_detect(struct snd_soc_component *component,
				struct snd_soc_jack *jack)
{}
EXPORT_SYMBOL_GPL();


static bool nau8825_is_jack_inserted(struct regmap *regmap)
{}

static void nau8825_restart_jack_detection(struct regmap *regmap)
{}

static void nau8825_int_status_clear_all(struct regmap *regmap)
{}

static void nau8825_eject_jack(struct nau8825 *nau8825)
{}

/* Enable audo mode interruptions with internal clock. */
static void nau8825_setup_auto_irq(struct nau8825 *nau8825)
{}

static int nau8825_button_decode(int value)
{}

static int nau8825_high_imped_detection(struct nau8825 *nau8825)
{}

static int nau8825_jack_insert(struct nau8825 *nau8825)
{}

#define NAU8825_BUTTONS

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

static void nau8825_setup_buttons(struct nau8825 *nau8825)
{}

static void nau8825_init_regs(struct nau8825 *nau8825)
{}

static const struct regmap_config nau8825_regmap_config =;

static int nau8825_component_probe(struct snd_soc_component *component)
{}

static void nau8825_component_remove(struct snd_soc_component *component)
{}

/**
 * nau8825_calc_fll_param - Calculate FLL parameters.
 * @fll_in: external clock provided to codec.
 * @fs: sampling rate.
 * @fll_param: Pointer to structure of FLL parameters.
 *
 * Calculate FLL parameters to configure codec.
 *
 * Returns 0 for success or negative error code.
 */
static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
		struct nau8825_fll *fll_param)
{}

static void nau8825_fll_apply(struct nau8825 *nau8825,
		struct nau8825_fll *fll_param)
{}

/* freq_out must be 256*Fs in order to achieve the best performance */
static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int source,
		unsigned int freq_in, unsigned int freq_out)
{}

static int nau8825_mclk_prepare(struct nau8825 *nau8825, unsigned int freq)
{}

static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap)
{}

static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
	unsigned int freq)
{}

static int nau8825_set_sysclk(struct snd_soc_component *component, int clk_id,
	int source, unsigned int freq, int dir)
{}

static int nau8825_resume_setup(struct nau8825 *nau8825)
{}

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

static int __maybe_unused nau8825_suspend(struct snd_soc_component *component)
{}

static int __maybe_unused nau8825_resume(struct snd_soc_component *component)
{}

static int nau8825_set_jack(struct snd_soc_component *component,
			    struct snd_soc_jack *jack, void *data)
{}

static const struct snd_soc_component_driver nau8825_component_driver =;

static void nau8825_reset_chip(struct regmap *regmap)
{}

static void nau8825_print_device_properties(struct nau8825 *nau8825)
{}

static int nau8825_read_device_properties(struct device *dev,
	struct nau8825 *nau8825) {}

static int nau8825_setup_irq(struct nau8825 *nau8825)
{}

static int nau8825_i2c_probe(struct i2c_client *i2c)
{}

static void nau8825_i2c_remove(struct i2c_client *client)
{}

static const struct i2c_device_id nau8825_i2c_ids[] =;
MODULE_DEVICE_TABLE(i2c, nau8825_i2c_ids);

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

#ifdef CONFIG_ACPI
static const struct acpi_device_id nau8825_acpi_match[] =;
MODULE_DEVICE_TABLE(acpi, nau8825_acpi_match);
#endif

static struct i2c_driver nau8825_driver =;
module_i2c_driver();

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