162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * alc5623.c -- alc562[123] ALSA Soc Audio driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2008 Realtek Microelectronics 662306a36Sopenharmony_ci * Author: flove <flove@realtek.com> Ethan <eku@marvell.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Based on WM8753.c 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/pm.h> 1862306a36Sopenharmony_ci#include <linux/i2c.h> 1962306a36Sopenharmony_ci#include <linux/regmap.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <sound/core.h> 2362306a36Sopenharmony_ci#include <sound/pcm.h> 2462306a36Sopenharmony_ci#include <sound/pcm_params.h> 2562306a36Sopenharmony_ci#include <sound/tlv.h> 2662306a36Sopenharmony_ci#include <sound/soc.h> 2762306a36Sopenharmony_ci#include <sound/initval.h> 2862306a36Sopenharmony_ci#include <sound/alc5623.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "alc5623.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int caps_charge = 2000; 3362306a36Sopenharmony_cimodule_param(caps_charge, int, 0); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)"); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* codec private data */ 3762306a36Sopenharmony_cistruct alc5623_priv { 3862306a36Sopenharmony_ci struct regmap *regmap; 3962306a36Sopenharmony_ci u8 id; 4062306a36Sopenharmony_ci unsigned int sysclk; 4162306a36Sopenharmony_ci unsigned int add_ctrl; 4262306a36Sopenharmony_ci unsigned int jack_det_ctrl; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline int alc5623_reset(struct snd_soc_component *component) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci return snd_soc_component_write(component, ALC5623_RESET, 0); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int amp_mixer_event(struct snd_soc_dapm_widget *w, 5162306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* to power-on/off class-d amp generators/speaker */ 5662306a36Sopenharmony_ci /* need to write to 'index-46h' register : */ 5762306a36Sopenharmony_ci /* so write index num (here 0x46) to reg 0x6a */ 5862306a36Sopenharmony_ci /* and then 0xffff/0 to reg 0x6c */ 5962306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_HID_CTRL_INDEX, 0x46); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci switch (event) { 6262306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 6362306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_HID_CTRL_DATA, 0xFFFF); 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 6662306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_HID_CTRL_DATA, 0); 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * ALC5623 Controls 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0); 7862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0); 7962306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0); 8062306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(boost_tlv, 8162306a36Sopenharmony_ci 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 8262306a36Sopenharmony_ci 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 8362306a36Sopenharmony_ci 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0) 8462306a36Sopenharmony_ci); 8562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5621_vol_snd_controls[] = { 8862306a36Sopenharmony_ci SOC_DOUBLE_TLV("Speaker Playback Volume", 8962306a36Sopenharmony_ci ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv), 9062306a36Sopenharmony_ci SOC_DOUBLE("Speaker Playback Switch", 9162306a36Sopenharmony_ci ALC5623_SPK_OUT_VOL, 15, 7, 1, 1), 9262306a36Sopenharmony_ci SOC_DOUBLE_TLV("Headphone Playback Volume", 9362306a36Sopenharmony_ci ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv), 9462306a36Sopenharmony_ci SOC_DOUBLE("Headphone Playback Switch", 9562306a36Sopenharmony_ci ALC5623_HP_OUT_VOL, 15, 7, 1, 1), 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5622_vol_snd_controls[] = { 9962306a36Sopenharmony_ci SOC_DOUBLE_TLV("Speaker Playback Volume", 10062306a36Sopenharmony_ci ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv), 10162306a36Sopenharmony_ci SOC_DOUBLE("Speaker Playback Switch", 10262306a36Sopenharmony_ci ALC5623_SPK_OUT_VOL, 15, 7, 1, 1), 10362306a36Sopenharmony_ci SOC_DOUBLE_TLV("Line Playback Volume", 10462306a36Sopenharmony_ci ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv), 10562306a36Sopenharmony_ci SOC_DOUBLE("Line Playback Switch", 10662306a36Sopenharmony_ci ALC5623_HP_OUT_VOL, 15, 7, 1, 1), 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_vol_snd_controls[] = { 11062306a36Sopenharmony_ci SOC_DOUBLE_TLV("Line Playback Volume", 11162306a36Sopenharmony_ci ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv), 11262306a36Sopenharmony_ci SOC_DOUBLE("Line Playback Switch", 11362306a36Sopenharmony_ci ALC5623_SPK_OUT_VOL, 15, 7, 1, 1), 11462306a36Sopenharmony_ci SOC_DOUBLE_TLV("Headphone Playback Volume", 11562306a36Sopenharmony_ci ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv), 11662306a36Sopenharmony_ci SOC_DOUBLE("Headphone Playback Switch", 11762306a36Sopenharmony_ci ALC5623_HP_OUT_VOL, 15, 7, 1, 1), 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_snd_controls[] = { 12162306a36Sopenharmony_ci SOC_DOUBLE_TLV("Auxout Playback Volume", 12262306a36Sopenharmony_ci ALC5623_MONO_AUX_OUT_VOL, 8, 0, 31, 1, hp_tlv), 12362306a36Sopenharmony_ci SOC_DOUBLE("Auxout Playback Switch", 12462306a36Sopenharmony_ci ALC5623_MONO_AUX_OUT_VOL, 15, 7, 1, 1), 12562306a36Sopenharmony_ci SOC_DOUBLE_TLV("PCM Playback Volume", 12662306a36Sopenharmony_ci ALC5623_STEREO_DAC_VOL, 8, 0, 31, 1, vol_tlv), 12762306a36Sopenharmony_ci SOC_DOUBLE_TLV("AuxI Capture Volume", 12862306a36Sopenharmony_ci ALC5623_AUXIN_VOL, 8, 0, 31, 1, vol_tlv), 12962306a36Sopenharmony_ci SOC_DOUBLE_TLV("LineIn Capture Volume", 13062306a36Sopenharmony_ci ALC5623_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv), 13162306a36Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Capture Volume", 13262306a36Sopenharmony_ci ALC5623_MIC_VOL, 8, 31, 1, vol_tlv), 13362306a36Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Capture Volume", 13462306a36Sopenharmony_ci ALC5623_MIC_VOL, 0, 31, 1, vol_tlv), 13562306a36Sopenharmony_ci SOC_DOUBLE_TLV("Rec Capture Volume", 13662306a36Sopenharmony_ci ALC5623_ADC_REC_GAIN, 7, 0, 31, 0, adc_rec_tlv), 13762306a36Sopenharmony_ci SOC_SINGLE_TLV("Mic 1 Boost Volume", 13862306a36Sopenharmony_ci ALC5623_MIC_CTRL, 10, 2, 0, boost_tlv), 13962306a36Sopenharmony_ci SOC_SINGLE_TLV("Mic 2 Boost Volume", 14062306a36Sopenharmony_ci ALC5623_MIC_CTRL, 8, 2, 0, boost_tlv), 14162306a36Sopenharmony_ci SOC_SINGLE_TLV("Digital Boost Volume", 14262306a36Sopenharmony_ci ALC5623_ADD_CTRL_REG, 4, 3, 0, dig_tlv), 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * DAPM Controls 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_hp_mixer_controls[] = { 14962306a36Sopenharmony_ciSOC_DAPM_SINGLE("LI2HP Playback Switch", ALC5623_LINE_IN_VOL, 15, 1, 1), 15062306a36Sopenharmony_ciSOC_DAPM_SINGLE("AUXI2HP Playback Switch", ALC5623_AUXIN_VOL, 15, 1, 1), 15162306a36Sopenharmony_ciSOC_DAPM_SINGLE("MIC12HP Playback Switch", ALC5623_MIC_ROUTING_CTRL, 15, 1, 1), 15262306a36Sopenharmony_ciSOC_DAPM_SINGLE("MIC22HP Playback Switch", ALC5623_MIC_ROUTING_CTRL, 7, 1, 1), 15362306a36Sopenharmony_ciSOC_DAPM_SINGLE("DAC2HP Playback Switch", ALC5623_STEREO_DAC_VOL, 15, 1, 1), 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_hpl_mixer_controls[] = { 15762306a36Sopenharmony_ciSOC_DAPM_SINGLE("ADC2HP_L Playback Switch", ALC5623_ADC_REC_GAIN, 15, 1, 1), 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_hpr_mixer_controls[] = { 16162306a36Sopenharmony_ciSOC_DAPM_SINGLE("ADC2HP_R Playback Switch", ALC5623_ADC_REC_GAIN, 14, 1, 1), 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_mono_mixer_controls[] = { 16562306a36Sopenharmony_ciSOC_DAPM_SINGLE("ADC2MONO_L Playback Switch", ALC5623_ADC_REC_GAIN, 13, 1, 1), 16662306a36Sopenharmony_ciSOC_DAPM_SINGLE("ADC2MONO_R Playback Switch", ALC5623_ADC_REC_GAIN, 12, 1, 1), 16762306a36Sopenharmony_ciSOC_DAPM_SINGLE("LI2MONO Playback Switch", ALC5623_LINE_IN_VOL, 13, 1, 1), 16862306a36Sopenharmony_ciSOC_DAPM_SINGLE("AUXI2MONO Playback Switch", ALC5623_AUXIN_VOL, 13, 1, 1), 16962306a36Sopenharmony_ciSOC_DAPM_SINGLE("MIC12MONO Playback Switch", ALC5623_MIC_ROUTING_CTRL, 13, 1, 1), 17062306a36Sopenharmony_ciSOC_DAPM_SINGLE("MIC22MONO Playback Switch", ALC5623_MIC_ROUTING_CTRL, 5, 1, 1), 17162306a36Sopenharmony_ciSOC_DAPM_SINGLE("DAC2MONO Playback Switch", ALC5623_STEREO_DAC_VOL, 13, 1, 1), 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_speaker_mixer_controls[] = { 17562306a36Sopenharmony_ciSOC_DAPM_SINGLE("LI2SPK Playback Switch", ALC5623_LINE_IN_VOL, 14, 1, 1), 17662306a36Sopenharmony_ciSOC_DAPM_SINGLE("AUXI2SPK Playback Switch", ALC5623_AUXIN_VOL, 14, 1, 1), 17762306a36Sopenharmony_ciSOC_DAPM_SINGLE("MIC12SPK Playback Switch", ALC5623_MIC_ROUTING_CTRL, 14, 1, 1), 17862306a36Sopenharmony_ciSOC_DAPM_SINGLE("MIC22SPK Playback Switch", ALC5623_MIC_ROUTING_CTRL, 6, 1, 1), 17962306a36Sopenharmony_ciSOC_DAPM_SINGLE("DAC2SPK Playback Switch", ALC5623_STEREO_DAC_VOL, 14, 1, 1), 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* Left Record Mixer */ 18362306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_captureL_mixer_controls[] = { 18462306a36Sopenharmony_ciSOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5623_ADC_REC_MIXER, 14, 1, 1), 18562306a36Sopenharmony_ciSOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5623_ADC_REC_MIXER, 13, 1, 1), 18662306a36Sopenharmony_ciSOC_DAPM_SINGLE("LineInL Capture Switch", ALC5623_ADC_REC_MIXER, 12, 1, 1), 18762306a36Sopenharmony_ciSOC_DAPM_SINGLE("Left AuxI Capture Switch", ALC5623_ADC_REC_MIXER, 11, 1, 1), 18862306a36Sopenharmony_ciSOC_DAPM_SINGLE("HPMixerL Capture Switch", ALC5623_ADC_REC_MIXER, 10, 1, 1), 18962306a36Sopenharmony_ciSOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5623_ADC_REC_MIXER, 9, 1, 1), 19062306a36Sopenharmony_ciSOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5623_ADC_REC_MIXER, 8, 1, 1), 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* Right Record Mixer */ 19462306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_captureR_mixer_controls[] = { 19562306a36Sopenharmony_ciSOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5623_ADC_REC_MIXER, 6, 1, 1), 19662306a36Sopenharmony_ciSOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5623_ADC_REC_MIXER, 5, 1, 1), 19762306a36Sopenharmony_ciSOC_DAPM_SINGLE("LineInR Capture Switch", ALC5623_ADC_REC_MIXER, 4, 1, 1), 19862306a36Sopenharmony_ciSOC_DAPM_SINGLE("Right AuxI Capture Switch", ALC5623_ADC_REC_MIXER, 3, 1, 1), 19962306a36Sopenharmony_ciSOC_DAPM_SINGLE("HPMixerR Capture Switch", ALC5623_ADC_REC_MIXER, 2, 1, 1), 20062306a36Sopenharmony_ciSOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5623_ADC_REC_MIXER, 1, 1, 1), 20162306a36Sopenharmony_ciSOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5623_ADC_REC_MIXER, 0, 1, 1), 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic const char *alc5623_spk_n_sour_sel[] = { 20562306a36Sopenharmony_ci "RN/-R", "RP/+R", "LN/-R", "Vmid" }; 20662306a36Sopenharmony_cistatic const char *alc5623_hpl_out_input_sel[] = { 20762306a36Sopenharmony_ci "Vmid", "HP Left Mix"}; 20862306a36Sopenharmony_cistatic const char *alc5623_hpr_out_input_sel[] = { 20962306a36Sopenharmony_ci "Vmid", "HP Right Mix"}; 21062306a36Sopenharmony_cistatic const char *alc5623_spkout_input_sel[] = { 21162306a36Sopenharmony_ci "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; 21262306a36Sopenharmony_cistatic const char *alc5623_aux_out_input_sel[] = { 21362306a36Sopenharmony_ci "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* auxout output mux */ 21662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum, 21762306a36Sopenharmony_ci ALC5623_OUTPUT_MIXER_CTRL, 6, 21862306a36Sopenharmony_ci alc5623_aux_out_input_sel); 21962306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_auxout_mux_controls = 22062306a36Sopenharmony_ciSOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* speaker output mux */ 22362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum, 22462306a36Sopenharmony_ci ALC5623_OUTPUT_MIXER_CTRL, 10, 22562306a36Sopenharmony_ci alc5623_spkout_input_sel); 22662306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_spkout_mux_controls = 22762306a36Sopenharmony_ciSOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* headphone left output mux */ 23062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum, 23162306a36Sopenharmony_ci ALC5623_OUTPUT_MIXER_CTRL, 9, 23262306a36Sopenharmony_ci alc5623_hpl_out_input_sel); 23362306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = 23462306a36Sopenharmony_ciSOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* headphone right output mux */ 23762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum, 23862306a36Sopenharmony_ci ALC5623_OUTPUT_MIXER_CTRL, 8, 23962306a36Sopenharmony_ci alc5623_hpr_out_input_sel); 24062306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = 24162306a36Sopenharmony_ciSOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* speaker output N select */ 24462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum, 24562306a36Sopenharmony_ci ALC5623_OUTPUT_MIXER_CTRL, 14, 24662306a36Sopenharmony_ci alc5623_spk_n_sour_sel); 24762306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = 24862306a36Sopenharmony_ciSOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget alc5623_dapm_widgets[] = { 25162306a36Sopenharmony_ci/* Muxes */ 25262306a36Sopenharmony_ciSND_SOC_DAPM_MUX("AuxOut Mux", SND_SOC_NOPM, 0, 0, 25362306a36Sopenharmony_ci &alc5623_auxout_mux_controls), 25462306a36Sopenharmony_ciSND_SOC_DAPM_MUX("SpeakerOut Mux", SND_SOC_NOPM, 0, 0, 25562306a36Sopenharmony_ci &alc5623_spkout_mux_controls), 25662306a36Sopenharmony_ciSND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, 25762306a36Sopenharmony_ci &alc5623_hpl_out_mux_controls), 25862306a36Sopenharmony_ciSND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, 25962306a36Sopenharmony_ci &alc5623_hpr_out_mux_controls), 26062306a36Sopenharmony_ciSND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0, 26162306a36Sopenharmony_ci &alc5623_spkoutn_mux_controls), 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* output mixers */ 26462306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0, 26562306a36Sopenharmony_ci &alc5623_hp_mixer_controls[0], 26662306a36Sopenharmony_ci ARRAY_SIZE(alc5623_hp_mixer_controls)), 26762306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("HPR Mix", ALC5623_PWR_MANAG_ADD2, 4, 0, 26862306a36Sopenharmony_ci &alc5623_hpr_mixer_controls[0], 26962306a36Sopenharmony_ci ARRAY_SIZE(alc5623_hpr_mixer_controls)), 27062306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("HPL Mix", ALC5623_PWR_MANAG_ADD2, 5, 0, 27162306a36Sopenharmony_ci &alc5623_hpl_mixer_controls[0], 27262306a36Sopenharmony_ci ARRAY_SIZE(alc5623_hpl_mixer_controls)), 27362306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("HPOut Mix", SND_SOC_NOPM, 0, 0, NULL, 0), 27462306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Mono Mix", ALC5623_PWR_MANAG_ADD2, 2, 0, 27562306a36Sopenharmony_ci &alc5623_mono_mixer_controls[0], 27662306a36Sopenharmony_ci ARRAY_SIZE(alc5623_mono_mixer_controls)), 27762306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Speaker Mix", ALC5623_PWR_MANAG_ADD2, 3, 0, 27862306a36Sopenharmony_ci &alc5623_speaker_mixer_controls[0], 27962306a36Sopenharmony_ci ARRAY_SIZE(alc5623_speaker_mixer_controls)), 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* input mixers */ 28262306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Left Capture Mix", ALC5623_PWR_MANAG_ADD2, 1, 0, 28362306a36Sopenharmony_ci &alc5623_captureL_mixer_controls[0], 28462306a36Sopenharmony_ci ARRAY_SIZE(alc5623_captureL_mixer_controls)), 28562306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Right Capture Mix", ALC5623_PWR_MANAG_ADD2, 0, 0, 28662306a36Sopenharmony_ci &alc5623_captureR_mixer_controls[0], 28762306a36Sopenharmony_ci ARRAY_SIZE(alc5623_captureR_mixer_controls)), 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciSND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", 29062306a36Sopenharmony_ci ALC5623_PWR_MANAG_ADD2, 9, 0), 29162306a36Sopenharmony_ciSND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", 29262306a36Sopenharmony_ci ALC5623_PWR_MANAG_ADD2, 8, 0), 29362306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("I2S Mix", ALC5623_PWR_MANAG_ADD1, 15, 0, NULL, 0), 29462306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("AuxI Mix", SND_SOC_NOPM, 0, 0, NULL, 0), 29562306a36Sopenharmony_ciSND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0), 29662306a36Sopenharmony_ciSND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", 29762306a36Sopenharmony_ci ALC5623_PWR_MANAG_ADD2, 7, 0), 29862306a36Sopenharmony_ciSND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", 29962306a36Sopenharmony_ci ALC5623_PWR_MANAG_ADD2, 6, 0), 30062306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Left Headphone", ALC5623_PWR_MANAG_ADD3, 10, 0, NULL, 0), 30162306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Right Headphone", ALC5623_PWR_MANAG_ADD3, 9, 0, NULL, 0), 30262306a36Sopenharmony_ciSND_SOC_DAPM_PGA("SpeakerOut", ALC5623_PWR_MANAG_ADD3, 12, 0, NULL, 0), 30362306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Left AuxOut", ALC5623_PWR_MANAG_ADD3, 14, 0, NULL, 0), 30462306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Right AuxOut", ALC5623_PWR_MANAG_ADD3, 13, 0, NULL, 0), 30562306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Left LineIn", ALC5623_PWR_MANAG_ADD3, 7, 0, NULL, 0), 30662306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Right LineIn", ALC5623_PWR_MANAG_ADD3, 6, 0, NULL, 0), 30762306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Left AuxI", ALC5623_PWR_MANAG_ADD3, 5, 0, NULL, 0), 30862306a36Sopenharmony_ciSND_SOC_DAPM_PGA("Right AuxI", ALC5623_PWR_MANAG_ADD3, 4, 0, NULL, 0), 30962306a36Sopenharmony_ciSND_SOC_DAPM_PGA("MIC1 PGA", ALC5623_PWR_MANAG_ADD3, 3, 0, NULL, 0), 31062306a36Sopenharmony_ciSND_SOC_DAPM_PGA("MIC2 PGA", ALC5623_PWR_MANAG_ADD3, 2, 0, NULL, 0), 31162306a36Sopenharmony_ciSND_SOC_DAPM_PGA("MIC1 Pre Amp", ALC5623_PWR_MANAG_ADD3, 1, 0, NULL, 0), 31262306a36Sopenharmony_ciSND_SOC_DAPM_PGA("MIC2 Pre Amp", ALC5623_PWR_MANAG_ADD3, 0, 0, NULL, 0), 31362306a36Sopenharmony_ciSND_SOC_DAPM_MICBIAS("Mic Bias1", ALC5623_PWR_MANAG_ADD1, 11, 0), 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("AUXOUTL"), 31662306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("AUXOUTR"), 31762306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPL"), 31862306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPR"), 31962306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("SPKOUT"), 32062306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("SPKOUTN"), 32162306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("LINEINL"), 32262306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("LINEINR"), 32362306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("AUXINL"), 32462306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("AUXINR"), 32562306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("MIC1"), 32662306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("MIC2"), 32762306a36Sopenharmony_ciSND_SOC_DAPM_VMID("Vmid"), 32862306a36Sopenharmony_ci}; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; 33162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(alc5623_amp_enum, 33262306a36Sopenharmony_ci ALC5623_OUTPUT_MIXER_CTRL, 13, 33362306a36Sopenharmony_ci alc5623_amp_names); 33462306a36Sopenharmony_cistatic const struct snd_kcontrol_new alc5623_amp_mux_controls = 33562306a36Sopenharmony_ci SOC_DAPM_ENUM("Route", alc5623_amp_enum); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget alc5623_dapm_amp_widgets[] = { 33862306a36Sopenharmony_ciSND_SOC_DAPM_PGA_E("D Amp", ALC5623_PWR_MANAG_ADD2, 14, 0, NULL, 0, 33962306a36Sopenharmony_ci amp_mixer_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 34062306a36Sopenharmony_ciSND_SOC_DAPM_PGA("AB Amp", ALC5623_PWR_MANAG_ADD2, 15, 0, NULL, 0), 34162306a36Sopenharmony_ciSND_SOC_DAPM_MUX("AB-D Amp Mux", SND_SOC_NOPM, 0, 0, 34262306a36Sopenharmony_ci &alc5623_amp_mux_controls), 34362306a36Sopenharmony_ci}; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route intercon[] = { 34662306a36Sopenharmony_ci /* virtual mixer - mixes left & right channels */ 34762306a36Sopenharmony_ci {"I2S Mix", NULL, "Left DAC"}, 34862306a36Sopenharmony_ci {"I2S Mix", NULL, "Right DAC"}, 34962306a36Sopenharmony_ci {"Line Mix", NULL, "Right LineIn"}, 35062306a36Sopenharmony_ci {"Line Mix", NULL, "Left LineIn"}, 35162306a36Sopenharmony_ci {"AuxI Mix", NULL, "Left AuxI"}, 35262306a36Sopenharmony_ci {"AuxI Mix", NULL, "Right AuxI"}, 35362306a36Sopenharmony_ci {"AUXOUTL", NULL, "Left AuxOut"}, 35462306a36Sopenharmony_ci {"AUXOUTR", NULL, "Right AuxOut"}, 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* HP mixer */ 35762306a36Sopenharmony_ci {"HPL Mix", "ADC2HP_L Playback Switch", "Left Capture Mix"}, 35862306a36Sopenharmony_ci {"HPL Mix", NULL, "HP Mix"}, 35962306a36Sopenharmony_ci {"HPR Mix", "ADC2HP_R Playback Switch", "Right Capture Mix"}, 36062306a36Sopenharmony_ci {"HPR Mix", NULL, "HP Mix"}, 36162306a36Sopenharmony_ci {"HP Mix", "LI2HP Playback Switch", "Line Mix"}, 36262306a36Sopenharmony_ci {"HP Mix", "AUXI2HP Playback Switch", "AuxI Mix"}, 36362306a36Sopenharmony_ci {"HP Mix", "MIC12HP Playback Switch", "MIC1 PGA"}, 36462306a36Sopenharmony_ci {"HP Mix", "MIC22HP Playback Switch", "MIC2 PGA"}, 36562306a36Sopenharmony_ci {"HP Mix", "DAC2HP Playback Switch", "I2S Mix"}, 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* speaker mixer */ 36862306a36Sopenharmony_ci {"Speaker Mix", "LI2SPK Playback Switch", "Line Mix"}, 36962306a36Sopenharmony_ci {"Speaker Mix", "AUXI2SPK Playback Switch", "AuxI Mix"}, 37062306a36Sopenharmony_ci {"Speaker Mix", "MIC12SPK Playback Switch", "MIC1 PGA"}, 37162306a36Sopenharmony_ci {"Speaker Mix", "MIC22SPK Playback Switch", "MIC2 PGA"}, 37262306a36Sopenharmony_ci {"Speaker Mix", "DAC2SPK Playback Switch", "I2S Mix"}, 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* mono mixer */ 37562306a36Sopenharmony_ci {"Mono Mix", "ADC2MONO_L Playback Switch", "Left Capture Mix"}, 37662306a36Sopenharmony_ci {"Mono Mix", "ADC2MONO_R Playback Switch", "Right Capture Mix"}, 37762306a36Sopenharmony_ci {"Mono Mix", "LI2MONO Playback Switch", "Line Mix"}, 37862306a36Sopenharmony_ci {"Mono Mix", "AUXI2MONO Playback Switch", "AuxI Mix"}, 37962306a36Sopenharmony_ci {"Mono Mix", "MIC12MONO Playback Switch", "MIC1 PGA"}, 38062306a36Sopenharmony_ci {"Mono Mix", "MIC22MONO Playback Switch", "MIC2 PGA"}, 38162306a36Sopenharmony_ci {"Mono Mix", "DAC2MONO Playback Switch", "I2S Mix"}, 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Left record mixer */ 38462306a36Sopenharmony_ci {"Left Capture Mix", "LineInL Capture Switch", "LINEINL"}, 38562306a36Sopenharmony_ci {"Left Capture Mix", "Left AuxI Capture Switch", "AUXINL"}, 38662306a36Sopenharmony_ci {"Left Capture Mix", "Mic1 Capture Switch", "MIC1 Pre Amp"}, 38762306a36Sopenharmony_ci {"Left Capture Mix", "Mic2 Capture Switch", "MIC2 Pre Amp"}, 38862306a36Sopenharmony_ci {"Left Capture Mix", "HPMixerL Capture Switch", "HPL Mix"}, 38962306a36Sopenharmony_ci {"Left Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"}, 39062306a36Sopenharmony_ci {"Left Capture Mix", "MonoMixer Capture Switch", "Mono Mix"}, 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /*Right record mixer */ 39362306a36Sopenharmony_ci {"Right Capture Mix", "LineInR Capture Switch", "LINEINR"}, 39462306a36Sopenharmony_ci {"Right Capture Mix", "Right AuxI Capture Switch", "AUXINR"}, 39562306a36Sopenharmony_ci {"Right Capture Mix", "Mic1 Capture Switch", "MIC1 Pre Amp"}, 39662306a36Sopenharmony_ci {"Right Capture Mix", "Mic2 Capture Switch", "MIC2 Pre Amp"}, 39762306a36Sopenharmony_ci {"Right Capture Mix", "HPMixerR Capture Switch", "HPR Mix"}, 39862306a36Sopenharmony_ci {"Right Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"}, 39962306a36Sopenharmony_ci {"Right Capture Mix", "MonoMixer Capture Switch", "Mono Mix"}, 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* headphone left mux */ 40262306a36Sopenharmony_ci {"Left Headphone Mux", "HP Left Mix", "HPL Mix"}, 40362306a36Sopenharmony_ci {"Left Headphone Mux", "Vmid", "Vmid"}, 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* headphone right mux */ 40662306a36Sopenharmony_ci {"Right Headphone Mux", "HP Right Mix", "HPR Mix"}, 40762306a36Sopenharmony_ci {"Right Headphone Mux", "Vmid", "Vmid"}, 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* speaker out mux */ 41062306a36Sopenharmony_ci {"SpeakerOut Mux", "Vmid", "Vmid"}, 41162306a36Sopenharmony_ci {"SpeakerOut Mux", "HPOut Mix", "HPOut Mix"}, 41262306a36Sopenharmony_ci {"SpeakerOut Mux", "Speaker Mix", "Speaker Mix"}, 41362306a36Sopenharmony_ci {"SpeakerOut Mux", "Mono Mix", "Mono Mix"}, 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Mono/Aux Out mux */ 41662306a36Sopenharmony_ci {"AuxOut Mux", "Vmid", "Vmid"}, 41762306a36Sopenharmony_ci {"AuxOut Mux", "HPOut Mix", "HPOut Mix"}, 41862306a36Sopenharmony_ci {"AuxOut Mux", "Speaker Mix", "Speaker Mix"}, 41962306a36Sopenharmony_ci {"AuxOut Mux", "Mono Mix", "Mono Mix"}, 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* output pga */ 42262306a36Sopenharmony_ci {"HPL", NULL, "Left Headphone"}, 42362306a36Sopenharmony_ci {"Left Headphone", NULL, "Left Headphone Mux"}, 42462306a36Sopenharmony_ci {"HPR", NULL, "Right Headphone"}, 42562306a36Sopenharmony_ci {"Right Headphone", NULL, "Right Headphone Mux"}, 42662306a36Sopenharmony_ci {"Left AuxOut", NULL, "AuxOut Mux"}, 42762306a36Sopenharmony_ci {"Right AuxOut", NULL, "AuxOut Mux"}, 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* input pga */ 43062306a36Sopenharmony_ci {"Left LineIn", NULL, "LINEINL"}, 43162306a36Sopenharmony_ci {"Right LineIn", NULL, "LINEINR"}, 43262306a36Sopenharmony_ci {"Left AuxI", NULL, "AUXINL"}, 43362306a36Sopenharmony_ci {"Right AuxI", NULL, "AUXINR"}, 43462306a36Sopenharmony_ci {"MIC1 Pre Amp", NULL, "MIC1"}, 43562306a36Sopenharmony_ci {"MIC2 Pre Amp", NULL, "MIC2"}, 43662306a36Sopenharmony_ci {"MIC1 PGA", NULL, "MIC1 Pre Amp"}, 43762306a36Sopenharmony_ci {"MIC2 PGA", NULL, "MIC2 Pre Amp"}, 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* left ADC */ 44062306a36Sopenharmony_ci {"Left ADC", NULL, "Left Capture Mix"}, 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* right ADC */ 44362306a36Sopenharmony_ci {"Right ADC", NULL, "Right Capture Mix"}, 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci {"SpeakerOut N Mux", "RN/-R", "SpeakerOut"}, 44662306a36Sopenharmony_ci {"SpeakerOut N Mux", "RP/+R", "SpeakerOut"}, 44762306a36Sopenharmony_ci {"SpeakerOut N Mux", "LN/-R", "SpeakerOut"}, 44862306a36Sopenharmony_ci {"SpeakerOut N Mux", "Vmid", "Vmid"}, 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci {"SPKOUT", NULL, "SpeakerOut"}, 45162306a36Sopenharmony_ci {"SPKOUTN", NULL, "SpeakerOut N Mux"}, 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic const struct snd_soc_dapm_route intercon_spk[] = { 45562306a36Sopenharmony_ci {"SpeakerOut", NULL, "SpeakerOut Mux"}, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic const struct snd_soc_dapm_route intercon_amp_spk[] = { 45962306a36Sopenharmony_ci {"AB Amp", NULL, "SpeakerOut Mux"}, 46062306a36Sopenharmony_ci {"D Amp", NULL, "SpeakerOut Mux"}, 46162306a36Sopenharmony_ci {"AB-D Amp Mux", "AB Amp", "AB Amp"}, 46262306a36Sopenharmony_ci {"AB-D Amp Mux", "D Amp", "D Amp"}, 46362306a36Sopenharmony_ci {"SpeakerOut", NULL, "AB-D Amp Mux"}, 46462306a36Sopenharmony_ci}; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/* PLL divisors */ 46762306a36Sopenharmony_cistruct _pll_div { 46862306a36Sopenharmony_ci u32 pll_in; 46962306a36Sopenharmony_ci u32 pll_out; 47062306a36Sopenharmony_ci u16 regvalue; 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* Note : pll code from original alc5623 driver. Not sure of how good it is */ 47462306a36Sopenharmony_ci/* useful only for master mode */ 47562306a36Sopenharmony_cistatic const struct _pll_div codec_master_pll_div[] = { 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci { 2048000, 8192000, 0x0ea0}, 47862306a36Sopenharmony_ci { 3686400, 8192000, 0x4e27}, 47962306a36Sopenharmony_ci { 12000000, 8192000, 0x456b}, 48062306a36Sopenharmony_ci { 13000000, 8192000, 0x495f}, 48162306a36Sopenharmony_ci { 13100000, 8192000, 0x0320}, 48262306a36Sopenharmony_ci { 2048000, 11289600, 0xf637}, 48362306a36Sopenharmony_ci { 3686400, 11289600, 0x2f22}, 48462306a36Sopenharmony_ci { 12000000, 11289600, 0x3e2f}, 48562306a36Sopenharmony_ci { 13000000, 11289600, 0x4d5b}, 48662306a36Sopenharmony_ci { 13100000, 11289600, 0x363b}, 48762306a36Sopenharmony_ci { 2048000, 16384000, 0x1ea0}, 48862306a36Sopenharmony_ci { 3686400, 16384000, 0x9e27}, 48962306a36Sopenharmony_ci { 12000000, 16384000, 0x452b}, 49062306a36Sopenharmony_ci { 13000000, 16384000, 0x542f}, 49162306a36Sopenharmony_ci { 13100000, 16384000, 0x03a0}, 49262306a36Sopenharmony_ci { 2048000, 16934400, 0xe625}, 49362306a36Sopenharmony_ci { 3686400, 16934400, 0x9126}, 49462306a36Sopenharmony_ci { 12000000, 16934400, 0x4d2c}, 49562306a36Sopenharmony_ci { 13000000, 16934400, 0x742f}, 49662306a36Sopenharmony_ci { 13100000, 16934400, 0x3c27}, 49762306a36Sopenharmony_ci { 2048000, 22579200, 0x2aa0}, 49862306a36Sopenharmony_ci { 3686400, 22579200, 0x2f20}, 49962306a36Sopenharmony_ci { 12000000, 22579200, 0x7e2f}, 50062306a36Sopenharmony_ci { 13000000, 22579200, 0x742f}, 50162306a36Sopenharmony_ci { 13100000, 22579200, 0x3c27}, 50262306a36Sopenharmony_ci { 2048000, 24576000, 0x2ea0}, 50362306a36Sopenharmony_ci { 3686400, 24576000, 0xee27}, 50462306a36Sopenharmony_ci { 12000000, 24576000, 0x2915}, 50562306a36Sopenharmony_ci { 13000000, 24576000, 0x772e}, 50662306a36Sopenharmony_ci { 13100000, 24576000, 0x0d20}, 50762306a36Sopenharmony_ci}; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic const struct _pll_div codec_slave_pll_div[] = { 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci { 1024000, 16384000, 0x3ea0}, 51262306a36Sopenharmony_ci { 1411200, 22579200, 0x3ea0}, 51362306a36Sopenharmony_ci { 1536000, 24576000, 0x3ea0}, 51462306a36Sopenharmony_ci { 2048000, 16384000, 0x1ea0}, 51562306a36Sopenharmony_ci { 2822400, 22579200, 0x1ea0}, 51662306a36Sopenharmony_ci { 3072000, 24576000, 0x1ea0}, 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci}; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int alc5623_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 52162306a36Sopenharmony_ci int source, unsigned int freq_in, unsigned int freq_out) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci int i; 52462306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 52562306a36Sopenharmony_ci int gbl_clk = 0, pll_div = 0; 52662306a36Sopenharmony_ci u16 reg; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (pll_id < ALC5623_PLL_FR_MCLK || pll_id > ALC5623_PLL_FR_BCK) 52962306a36Sopenharmony_ci return -ENODEV; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* Disable PLL power */ 53262306a36Sopenharmony_ci snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD2, 53362306a36Sopenharmony_ci ALC5623_PWR_ADD2_PLL, 53462306a36Sopenharmony_ci 0); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* pll is not used in slave mode */ 53762306a36Sopenharmony_ci reg = snd_soc_component_read(component, ALC5623_DAI_CONTROL); 53862306a36Sopenharmony_ci if (reg & ALC5623_DAI_SDP_SLAVE_MODE) 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (!freq_in || !freq_out) 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci switch (pll_id) { 54562306a36Sopenharmony_ci case ALC5623_PLL_FR_MCLK: 54662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) { 54762306a36Sopenharmony_ci if (codec_master_pll_div[i].pll_in == freq_in 54862306a36Sopenharmony_ci && codec_master_pll_div[i].pll_out == freq_out) { 54962306a36Sopenharmony_ci /* PLL source from MCLK */ 55062306a36Sopenharmony_ci pll_div = codec_master_pll_div[i].regvalue; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case ALC5623_PLL_FR_BCK: 55662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) { 55762306a36Sopenharmony_ci if (codec_slave_pll_div[i].pll_in == freq_in 55862306a36Sopenharmony_ci && codec_slave_pll_div[i].pll_out == freq_out) { 55962306a36Sopenharmony_ci /* PLL source from Bitclk */ 56062306a36Sopenharmony_ci gbl_clk = ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK; 56162306a36Sopenharmony_ci pll_div = codec_slave_pll_div[i].regvalue; 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci default: 56762306a36Sopenharmony_ci return -EINVAL; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (!pll_div) 57162306a36Sopenharmony_ci return -EINVAL; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk); 57462306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PLL_CTRL, pll_div); 57562306a36Sopenharmony_ci snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD2, 57662306a36Sopenharmony_ci ALC5623_PWR_ADD2_PLL, 57762306a36Sopenharmony_ci ALC5623_PWR_ADD2_PLL); 57862306a36Sopenharmony_ci gbl_clk |= ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL; 57962306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistruct _coeff_div { 58562306a36Sopenharmony_ci u16 fs; 58662306a36Sopenharmony_ci u16 regvalue; 58762306a36Sopenharmony_ci}; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/* codec hifi mclk (after PLL) clock divider coefficients */ 59062306a36Sopenharmony_ci/* values inspired from column BCLK=32Fs of Appendix A table */ 59162306a36Sopenharmony_cistatic const struct _coeff_div coeff_div[] = { 59262306a36Sopenharmony_ci {256*8, 0x3a69}, 59362306a36Sopenharmony_ci {384*8, 0x3c6b}, 59462306a36Sopenharmony_ci {256*4, 0x2a69}, 59562306a36Sopenharmony_ci {384*4, 0x2c6b}, 59662306a36Sopenharmony_ci {256*2, 0x1a69}, 59762306a36Sopenharmony_ci {384*2, 0x1c6b}, 59862306a36Sopenharmony_ci {256*1, 0x0a69}, 59962306a36Sopenharmony_ci {384*1, 0x0c6b}, 60062306a36Sopenharmony_ci}; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int get_coeff(struct snd_soc_component *component, int rate) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 60562306a36Sopenharmony_ci int i; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { 60862306a36Sopenharmony_ci if (coeff_div[i].fs * rate == alc5623->sysclk) 60962306a36Sopenharmony_ci return i; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* 61562306a36Sopenharmony_ci * Clock after PLL and dividers 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_cistatic int alc5623_set_dai_sysclk(struct snd_soc_dai *codec_dai, 61862306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 62162306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci switch (freq) { 62462306a36Sopenharmony_ci case 8192000: 62562306a36Sopenharmony_ci case 11289600: 62662306a36Sopenharmony_ci case 12288000: 62762306a36Sopenharmony_ci case 16384000: 62862306a36Sopenharmony_ci case 16934400: 62962306a36Sopenharmony_ci case 18432000: 63062306a36Sopenharmony_ci case 22579200: 63162306a36Sopenharmony_ci case 24576000: 63262306a36Sopenharmony_ci alc5623->sysclk = freq; 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai, 63962306a36Sopenharmony_ci unsigned int fmt) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 64262306a36Sopenharmony_ci u16 iface = 0; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* set audio interface clocking */ 64562306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 64662306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 64762306a36Sopenharmony_ci iface = ALC5623_DAI_SDP_MASTER_MODE; 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 65062306a36Sopenharmony_ci iface = ALC5623_DAI_SDP_SLAVE_MODE; 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci default: 65362306a36Sopenharmony_ci return -EINVAL; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* interface format */ 65762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 65862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 65962306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DF_I2S; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 66262306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DF_RIGHT; 66362306a36Sopenharmony_ci break; 66462306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 66562306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DF_LEFT; 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 66862306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DF_PCM; 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 67162306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DF_PCM | ALC5623_DAI_I2S_PCM_MODE; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci default: 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* clock inversion */ 67862306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 67962306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 68262306a36Sopenharmony_ci iface |= ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL; 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 68562306a36Sopenharmony_ci iface |= ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci default: 69062306a36Sopenharmony_ci return -EINVAL; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return snd_soc_component_write(component, ALC5623_DAI_CONTROL, iface); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int alc5623_pcm_hw_params(struct snd_pcm_substream *substream, 69762306a36Sopenharmony_ci struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 70062306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 70162306a36Sopenharmony_ci int coeff, rate; 70262306a36Sopenharmony_ci u16 iface; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci iface = snd_soc_component_read(component, ALC5623_DAI_CONTROL); 70562306a36Sopenharmony_ci iface &= ~ALC5623_DAI_I2S_DL_MASK; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* bit size */ 70862306a36Sopenharmony_ci switch (params_width(params)) { 70962306a36Sopenharmony_ci case 16: 71062306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DL_16; 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci case 20: 71362306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DL_20; 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci case 24: 71662306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DL_24; 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci case 32: 71962306a36Sopenharmony_ci iface |= ALC5623_DAI_I2S_DL_32; 72062306a36Sopenharmony_ci break; 72162306a36Sopenharmony_ci default: 72262306a36Sopenharmony_ci return -EINVAL; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* set iface & srate */ 72662306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_DAI_CONTROL, iface); 72762306a36Sopenharmony_ci rate = params_rate(params); 72862306a36Sopenharmony_ci coeff = get_coeff(component, rate); 72962306a36Sopenharmony_ci if (coeff < 0) 73062306a36Sopenharmony_ci return -EINVAL; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci coeff = coeff_div[coeff].regvalue; 73362306a36Sopenharmony_ci dev_dbg(component->dev, "%s: sysclk=%d,rate=%d,coeff=0x%04x\n", 73462306a36Sopenharmony_ci __func__, alc5623->sysclk, rate, coeff); 73562306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_STEREO_AD_DA_CLK_CTRL, coeff); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return 0; 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int alc5623_mute(struct snd_soc_dai *dai, int mute, int direction) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 74362306a36Sopenharmony_ci u16 hp_mute = ALC5623_MISC_M_DAC_L_INPUT | ALC5623_MISC_M_DAC_R_INPUT; 74462306a36Sopenharmony_ci u16 mute_reg = snd_soc_component_read(component, ALC5623_MISC_CTRL) & ~hp_mute; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (mute) 74762306a36Sopenharmony_ci mute_reg |= hp_mute; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return snd_soc_component_write(component, ALC5623_MISC_CTRL, mute_reg); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci#define ALC5623_ADD2_POWER_EN (ALC5623_PWR_ADD2_VREF \ 75362306a36Sopenharmony_ci | ALC5623_PWR_ADD2_DAC_REF_CIR) 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci#define ALC5623_ADD3_POWER_EN (ALC5623_PWR_ADD3_MAIN_BIAS \ 75662306a36Sopenharmony_ci | ALC5623_PWR_ADD3_MIC1_BOOST_AD) 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci#define ALC5623_ADD1_POWER_EN \ 75962306a36Sopenharmony_ci (ALC5623_PWR_ADD1_SHORT_CURR_DET_EN | ALC5623_PWR_ADD1_SOFTGEN_EN \ 76062306a36Sopenharmony_ci | ALC5623_PWR_ADD1_DEPOP_BUF_HP | ALC5623_PWR_ADD1_HP_OUT_AMP \ 76162306a36Sopenharmony_ci | ALC5623_PWR_ADD1_HP_OUT_ENH_AMP) 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci#define ALC5623_ADD1_POWER_EN_5622 \ 76462306a36Sopenharmony_ci (ALC5623_PWR_ADD1_SHORT_CURR_DET_EN \ 76562306a36Sopenharmony_ci | ALC5623_PWR_ADD1_HP_OUT_AMP) 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic void enable_power_depop(struct snd_soc_component *component) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci snd_soc_component_update_bits(component, ALC5623_PWR_MANAG_ADD1, 77262306a36Sopenharmony_ci ALC5623_PWR_ADD1_SOFTGEN_EN, 77362306a36Sopenharmony_ci ALC5623_PWR_ADD1_SOFTGEN_EN); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, ALC5623_ADD3_POWER_EN); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci snd_soc_component_update_bits(component, ALC5623_MISC_CTRL, 77862306a36Sopenharmony_ci ALC5623_MISC_HP_DEPOP_MODE2_EN, 77962306a36Sopenharmony_ci ALC5623_MISC_HP_DEPOP_MODE2_EN); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci msleep(500); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, ALC5623_ADD2_POWER_EN); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* avoid writing '1' into 5622 reserved bits */ 78662306a36Sopenharmony_ci if (alc5623->id == 0x22) 78762306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1, 78862306a36Sopenharmony_ci ALC5623_ADD1_POWER_EN_5622); 78962306a36Sopenharmony_ci else 79062306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1, 79162306a36Sopenharmony_ci ALC5623_ADD1_POWER_EN); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* disable HP Depop2 */ 79462306a36Sopenharmony_ci snd_soc_component_update_bits(component, ALC5623_MISC_CTRL, 79562306a36Sopenharmony_ci ALC5623_MISC_HP_DEPOP_MODE2_EN, 79662306a36Sopenharmony_ci 0); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic int alc5623_set_bias_level(struct snd_soc_component *component, 80162306a36Sopenharmony_ci enum snd_soc_bias_level level) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci switch (level) { 80462306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 80562306a36Sopenharmony_ci enable_power_depop(component); 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 81062306a36Sopenharmony_ci /* everything off except vref/vmid, */ 81162306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, 81262306a36Sopenharmony_ci ALC5623_PWR_ADD2_VREF); 81362306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, 81462306a36Sopenharmony_ci ALC5623_PWR_ADD3_MAIN_BIAS); 81562306a36Sopenharmony_ci break; 81662306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 81762306a36Sopenharmony_ci /* everything off, dac mute, inactive */ 81862306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD2, 0); 81962306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD3, 0); 82062306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_PWR_MANAG_ADD1, 0); 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci return 0; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci#define ALC5623_FORMATS (SNDRV_PCM_FMTBIT_S16_LE \ 82762306a36Sopenharmony_ci | SNDRV_PCM_FMTBIT_S24_LE \ 82862306a36Sopenharmony_ci | SNDRV_PCM_FMTBIT_S32_LE) 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops alc5623_dai_ops = { 83162306a36Sopenharmony_ci .hw_params = alc5623_pcm_hw_params, 83262306a36Sopenharmony_ci .mute_stream = alc5623_mute, 83362306a36Sopenharmony_ci .set_fmt = alc5623_set_dai_fmt, 83462306a36Sopenharmony_ci .set_sysclk = alc5623_set_dai_sysclk, 83562306a36Sopenharmony_ci .set_pll = alc5623_set_dai_pll, 83662306a36Sopenharmony_ci .no_capture_mute = 1, 83762306a36Sopenharmony_ci}; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic struct snd_soc_dai_driver alc5623_dai = { 84062306a36Sopenharmony_ci .name = "alc5623-hifi", 84162306a36Sopenharmony_ci .playback = { 84262306a36Sopenharmony_ci .stream_name = "Playback", 84362306a36Sopenharmony_ci .channels_min = 1, 84462306a36Sopenharmony_ci .channels_max = 2, 84562306a36Sopenharmony_ci .rate_min = 8000, 84662306a36Sopenharmony_ci .rate_max = 48000, 84762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 84862306a36Sopenharmony_ci .formats = ALC5623_FORMATS,}, 84962306a36Sopenharmony_ci .capture = { 85062306a36Sopenharmony_ci .stream_name = "Capture", 85162306a36Sopenharmony_ci .channels_min = 1, 85262306a36Sopenharmony_ci .channels_max = 2, 85362306a36Sopenharmony_ci .rate_min = 8000, 85462306a36Sopenharmony_ci .rate_max = 48000, 85562306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 85662306a36Sopenharmony_ci .formats = ALC5623_FORMATS,}, 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci .ops = &alc5623_dai_ops, 85962306a36Sopenharmony_ci}; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic int alc5623_suspend(struct snd_soc_component *component) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci regcache_cache_only(alc5623->regmap, true); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic int alc5623_resume(struct snd_soc_component *component) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 87362306a36Sopenharmony_ci int ret; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Sync reg_cache with the hardware */ 87662306a36Sopenharmony_ci regcache_cache_only(alc5623->regmap, false); 87762306a36Sopenharmony_ci ret = regcache_sync(alc5623->regmap); 87862306a36Sopenharmony_ci if (ret != 0) { 87962306a36Sopenharmony_ci dev_err(component->dev, "Failed to sync register cache: %d\n", 88062306a36Sopenharmony_ci ret); 88162306a36Sopenharmony_ci regcache_cache_only(alc5623->regmap, true); 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic int alc5623_probe(struct snd_soc_component *component) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct alc5623_priv *alc5623 = snd_soc_component_get_drvdata(component); 89162306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci alc5623_reset(component); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (alc5623->add_ctrl) { 89662306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_ADD_CTRL_REG, 89762306a36Sopenharmony_ci alc5623->add_ctrl); 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (alc5623->jack_det_ctrl) { 90162306a36Sopenharmony_ci snd_soc_component_write(component, ALC5623_JACK_DET_CTRL, 90262306a36Sopenharmony_ci alc5623->jack_det_ctrl); 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci switch (alc5623->id) { 90662306a36Sopenharmony_ci case 0x21: 90762306a36Sopenharmony_ci snd_soc_add_component_controls(component, alc5621_vol_snd_controls, 90862306a36Sopenharmony_ci ARRAY_SIZE(alc5621_vol_snd_controls)); 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci case 0x22: 91162306a36Sopenharmony_ci snd_soc_add_component_controls(component, alc5622_vol_snd_controls, 91262306a36Sopenharmony_ci ARRAY_SIZE(alc5622_vol_snd_controls)); 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci case 0x23: 91562306a36Sopenharmony_ci snd_soc_add_component_controls(component, alc5623_vol_snd_controls, 91662306a36Sopenharmony_ci ARRAY_SIZE(alc5623_vol_snd_controls)); 91762306a36Sopenharmony_ci break; 91862306a36Sopenharmony_ci default: 91962306a36Sopenharmony_ci return -EINVAL; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci snd_soc_add_component_controls(component, alc5623_snd_controls, 92362306a36Sopenharmony_ci ARRAY_SIZE(alc5623_snd_controls)); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci snd_soc_dapm_new_controls(dapm, alc5623_dapm_widgets, 92662306a36Sopenharmony_ci ARRAY_SIZE(alc5623_dapm_widgets)); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* set up audio path interconnects */ 92962306a36Sopenharmony_ci snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci switch (alc5623->id) { 93262306a36Sopenharmony_ci case 0x21: 93362306a36Sopenharmony_ci case 0x22: 93462306a36Sopenharmony_ci snd_soc_dapm_new_controls(dapm, alc5623_dapm_amp_widgets, 93562306a36Sopenharmony_ci ARRAY_SIZE(alc5623_dapm_amp_widgets)); 93662306a36Sopenharmony_ci snd_soc_dapm_add_routes(dapm, intercon_amp_spk, 93762306a36Sopenharmony_ci ARRAY_SIZE(intercon_amp_spk)); 93862306a36Sopenharmony_ci break; 93962306a36Sopenharmony_ci case 0x23: 94062306a36Sopenharmony_ci snd_soc_dapm_add_routes(dapm, intercon_spk, 94162306a36Sopenharmony_ci ARRAY_SIZE(intercon_spk)); 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci default: 94462306a36Sopenharmony_ci return -EINVAL; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_device_alc5623 = { 95162306a36Sopenharmony_ci .probe = alc5623_probe, 95262306a36Sopenharmony_ci .suspend = alc5623_suspend, 95362306a36Sopenharmony_ci .resume = alc5623_resume, 95462306a36Sopenharmony_ci .set_bias_level = alc5623_set_bias_level, 95562306a36Sopenharmony_ci .suspend_bias_off = 1, 95662306a36Sopenharmony_ci .idle_bias_on = 1, 95762306a36Sopenharmony_ci .use_pmdown_time = 1, 95862306a36Sopenharmony_ci .endianness = 1, 95962306a36Sopenharmony_ci}; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic const struct regmap_config alc5623_regmap = { 96262306a36Sopenharmony_ci .reg_bits = 8, 96362306a36Sopenharmony_ci .val_bits = 16, 96462306a36Sopenharmony_ci .reg_stride = 2, 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci .max_register = ALC5623_VENDOR_ID2, 96762306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 96862306a36Sopenharmony_ci}; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic const struct i2c_device_id alc5623_i2c_table[] = { 97162306a36Sopenharmony_ci {"alc5621", 0x21}, 97262306a36Sopenharmony_ci {"alc5622", 0x22}, 97362306a36Sopenharmony_ci {"alc5623", 0x23}, 97462306a36Sopenharmony_ci {} 97562306a36Sopenharmony_ci}; 97662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, alc5623_i2c_table); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci/* 97962306a36Sopenharmony_ci * ALC5623 2 wire address is determined by A1 pin 98062306a36Sopenharmony_ci * state during powerup. 98162306a36Sopenharmony_ci * low = 0x1a 98262306a36Sopenharmony_ci * high = 0x1b 98362306a36Sopenharmony_ci */ 98462306a36Sopenharmony_cistatic int alc5623_i2c_probe(struct i2c_client *client) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci struct alc5623_platform_data *pdata; 98762306a36Sopenharmony_ci struct alc5623_priv *alc5623; 98862306a36Sopenharmony_ci struct device_node *np; 98962306a36Sopenharmony_ci unsigned int vid1, vid2; 99062306a36Sopenharmony_ci int ret; 99162306a36Sopenharmony_ci u32 val32; 99262306a36Sopenharmony_ci const struct i2c_device_id *id; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), 99562306a36Sopenharmony_ci GFP_KERNEL); 99662306a36Sopenharmony_ci if (alc5623 == NULL) 99762306a36Sopenharmony_ci return -ENOMEM; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap); 100062306a36Sopenharmony_ci if (IS_ERR(alc5623->regmap)) { 100162306a36Sopenharmony_ci ret = PTR_ERR(alc5623->regmap); 100262306a36Sopenharmony_ci dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret); 100362306a36Sopenharmony_ci return ret; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1); 100762306a36Sopenharmony_ci if (ret < 0) { 100862306a36Sopenharmony_ci dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); 100962306a36Sopenharmony_ci return ret; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2); 101362306a36Sopenharmony_ci if (ret < 0) { 101462306a36Sopenharmony_ci dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret); 101562306a36Sopenharmony_ci return ret; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci vid2 >>= 8; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci id = i2c_match_id(alc5623_i2c_table, client); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { 102262306a36Sopenharmony_ci dev_err(&client->dev, "unknown or wrong codec\n"); 102362306a36Sopenharmony_ci dev_err(&client->dev, "Expected %x:%lx, got %x:%x\n", 102462306a36Sopenharmony_ci 0x10ec, id->driver_data, 102562306a36Sopenharmony_ci vid1, vid2); 102662306a36Sopenharmony_ci return -ENODEV; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci pdata = client->dev.platform_data; 103262306a36Sopenharmony_ci if (pdata) { 103362306a36Sopenharmony_ci alc5623->add_ctrl = pdata->add_ctrl; 103462306a36Sopenharmony_ci alc5623->jack_det_ctrl = pdata->jack_det_ctrl; 103562306a36Sopenharmony_ci } else { 103662306a36Sopenharmony_ci if (client->dev.of_node) { 103762306a36Sopenharmony_ci np = client->dev.of_node; 103862306a36Sopenharmony_ci ret = of_property_read_u32(np, "add-ctrl", &val32); 103962306a36Sopenharmony_ci if (!ret) 104062306a36Sopenharmony_ci alc5623->add_ctrl = val32; 104162306a36Sopenharmony_ci ret = of_property_read_u32(np, "jack-det-ctrl", &val32); 104262306a36Sopenharmony_ci if (!ret) 104362306a36Sopenharmony_ci alc5623->jack_det_ctrl = val32; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci alc5623->id = vid2; 104862306a36Sopenharmony_ci switch (alc5623->id) { 104962306a36Sopenharmony_ci case 0x21: 105062306a36Sopenharmony_ci alc5623_dai.name = "alc5621-hifi"; 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case 0x22: 105362306a36Sopenharmony_ci alc5623_dai.name = "alc5622-hifi"; 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci case 0x23: 105662306a36Sopenharmony_ci alc5623_dai.name = "alc5623-hifi"; 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci default: 105962306a36Sopenharmony_ci return -EINVAL; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci i2c_set_clientdata(client, alc5623); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&client->dev, 106562306a36Sopenharmony_ci &soc_component_device_alc5623, &alc5623_dai, 1); 106662306a36Sopenharmony_ci if (ret != 0) 106762306a36Sopenharmony_ci dev_err(&client->dev, "Failed to register codec: %d\n", ret); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci return ret; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci#ifdef CONFIG_OF 107362306a36Sopenharmony_cistatic const struct of_device_id alc5623_of_match[] = { 107462306a36Sopenharmony_ci { .compatible = "realtek,alc5623", }, 107562306a36Sopenharmony_ci { } 107662306a36Sopenharmony_ci}; 107762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, alc5623_of_match); 107862306a36Sopenharmony_ci#endif 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci/* i2c codec control layer */ 108162306a36Sopenharmony_cistatic struct i2c_driver alc5623_i2c_driver = { 108262306a36Sopenharmony_ci .driver = { 108362306a36Sopenharmony_ci .name = "alc562x-codec", 108462306a36Sopenharmony_ci .of_match_table = of_match_ptr(alc5623_of_match), 108562306a36Sopenharmony_ci }, 108662306a36Sopenharmony_ci .probe = alc5623_i2c_probe, 108762306a36Sopenharmony_ci .id_table = alc5623_i2c_table, 108862306a36Sopenharmony_ci}; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cimodule_i2c_driver(alc5623_i2c_driver); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC alc5621/2/3 driver"); 109362306a36Sopenharmony_ciMODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); 109462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1095