Initial import
Signed-off-by: Alexander Egorenkov <egorenar-dev@posteo.net>
This commit is contained in:
commit
9ec319283d
9 changed files with 3946 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
*.cmd
|
||||||
|
*.ko
|
||||||
|
*.o
|
||||||
|
Module.symvers
|
||||||
|
modules.order
|
||||||
|
*.mod
|
||||||
|
*.mod.c
|
24
Makefile
Normal file
24
Makefile
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
snd-hda-codec-cs8409-objs := patch_cs8409.o patch_cs8409-tables.o
|
||||||
|
obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
|
||||||
|
|
||||||
|
# debug build flags
|
||||||
|
#KBUILD_EXTRA_CFLAGS = "-DCONFIG_SND_DEBUG=1 -DMYSOUNDDEBUGFULL -DCONFIG_SND_HDA_RECONFIG=1 -Wno-unused-variable -Wno-unused-function"
|
||||||
|
# normal build flags
|
||||||
|
KBUILD_EXTRA_CFLAGS = "-DCONFIG_SND_HDA_RECONFIG=1 -Wno-unused-variable -Wno-unused-function"
|
||||||
|
|
||||||
|
|
||||||
|
ifdef KVER
|
||||||
|
KDIR := /lib/modules/$(KVER)
|
||||||
|
else
|
||||||
|
KDIR := /lib/modules/$(shell uname -r)
|
||||||
|
endif
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KDIR)/build CFLAGS_MODULE=$(KBUILD_EXTRA_CFLAGS) M=$(shell pwd) modules
|
||||||
|
clean:
|
||||||
|
make -C $(KDIR)/build M=$(shell pwd) clean
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(KDIR)/updates/
|
||||||
|
cp snd-hda-codec-cs8409.ko $(KDIR)/updates/
|
||||||
|
depmod -a
|
118
hda_auto_parser.h
Normal file
118
hda_auto_parser.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* BIOS auto-parser helper functions for HD-audio
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_HDA_AUTO_PARSER_H
|
||||||
|
#define __SOUND_HDA_AUTO_PARSER_H
|
||||||
|
|
||||||
|
#include "hda_local.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper for automatic pin configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUTO_PIN_MIC,
|
||||||
|
AUTO_PIN_LINE_IN,
|
||||||
|
AUTO_PIN_CD,
|
||||||
|
AUTO_PIN_AUX,
|
||||||
|
AUTO_PIN_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUTO_PIN_LINE_OUT,
|
||||||
|
AUTO_PIN_SPEAKER_OUT,
|
||||||
|
AUTO_PIN_HP_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
|
||||||
|
#define AUTO_CFG_MAX_INS 18
|
||||||
|
|
||||||
|
struct auto_pin_cfg_item {
|
||||||
|
hda_nid_t pin;
|
||||||
|
int type;
|
||||||
|
unsigned int is_headset_mic:1;
|
||||||
|
unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */
|
||||||
|
unsigned int has_boost_on_pin:1;
|
||||||
|
int order;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct auto_pin_cfg;
|
||||||
|
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
|
||||||
|
const struct auto_pin_cfg *cfg,
|
||||||
|
int input);
|
||||||
|
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
const struct auto_pin_cfg *cfg,
|
||||||
|
char *label, int maxlen, int *indexp);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
|
||||||
|
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
|
||||||
|
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
|
||||||
|
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
|
||||||
|
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
|
||||||
|
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
|
||||||
|
INPUT_PIN_ATTR_LAST = INPUT_PIN_ATTR_FRONT,
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_get_input_pin_attr(unsigned int def_conf);
|
||||||
|
|
||||||
|
struct auto_pin_cfg {
|
||||||
|
int line_outs;
|
||||||
|
/* sorted in the order of Front/Surr/CLFE/Side */
|
||||||
|
hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
|
||||||
|
int speaker_outs;
|
||||||
|
hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
|
||||||
|
int hp_outs;
|
||||||
|
int line_out_type; /* AUTO_PIN_XXX_OUT */
|
||||||
|
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
|
||||||
|
int num_inputs;
|
||||||
|
struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
|
||||||
|
int dig_outs;
|
||||||
|
hda_nid_t dig_out_pins[2];
|
||||||
|
hda_nid_t dig_in_pin;
|
||||||
|
hda_nid_t mono_out_pin;
|
||||||
|
int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
|
||||||
|
int dig_in_type; /* HDA_PCM_TYPE_XXX */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* bit-flags for snd_hda_parse_pin_def_config() behavior */
|
||||||
|
#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
|
||||||
|
#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
|
||||||
|
#define HDA_PINCFG_HEADSET_MIC (1 << 2) /* Try to find headset mic; mark seq number as 0xc to trigger */
|
||||||
|
#define HDA_PINCFG_HEADPHONE_MIC (1 << 3) /* Try to find headphone mic; mark seq number as 0xd to trigger */
|
||||||
|
|
||||||
|
int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
|
||||||
|
struct auto_pin_cfg *cfg,
|
||||||
|
const hda_nid_t *ignore_nids,
|
||||||
|
unsigned int cond_flags);
|
||||||
|
|
||||||
|
/* older function */
|
||||||
|
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
|
||||||
|
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
|
||||||
|
|
||||||
|
static inline int auto_cfg_hp_outs(const struct auto_pin_cfg *cfg)
|
||||||
|
{
|
||||||
|
return (cfg->line_out_type == AUTO_PIN_HP_OUT) ?
|
||||||
|
cfg->line_outs : cfg->hp_outs;
|
||||||
|
}
|
||||||
|
static inline const hda_nid_t *auto_cfg_hp_pins(const struct auto_pin_cfg *cfg)
|
||||||
|
{
|
||||||
|
return (cfg->line_out_type == AUTO_PIN_HP_OUT) ?
|
||||||
|
cfg->line_out_pins : cfg->hp_pins;
|
||||||
|
}
|
||||||
|
static inline int auto_cfg_speaker_outs(const struct auto_pin_cfg *cfg)
|
||||||
|
{
|
||||||
|
return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ?
|
||||||
|
cfg->line_outs : cfg->speaker_outs;
|
||||||
|
}
|
||||||
|
static inline const hda_nid_t *auto_cfg_speaker_pins(const struct auto_pin_cfg *cfg)
|
||||||
|
{
|
||||||
|
return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ?
|
||||||
|
cfg->line_out_pins : cfg->speaker_pins;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SOUND_HDA_AUTO_PARSER_H */
|
357
hda_generic.h
Normal file
357
hda_generic.h
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Generic BIOS auto-parser helper functions for HD-audio
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_HDA_GENERIC_H
|
||||||
|
#define __SOUND_HDA_GENERIC_H
|
||||||
|
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include "hda_auto_parser.h"
|
||||||
|
|
||||||
|
struct hda_jack_callback;
|
||||||
|
|
||||||
|
/* table entry for multi-io paths */
|
||||||
|
struct hda_multi_io {
|
||||||
|
hda_nid_t pin; /* multi-io widget pin NID */
|
||||||
|
hda_nid_t dac; /* DAC to be connected */
|
||||||
|
unsigned int ctl_in; /* cached input-pin control value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Widget connection path
|
||||||
|
*
|
||||||
|
* For output, stored in the order of DAC -> ... -> pin,
|
||||||
|
* for input, pin -> ... -> ADC.
|
||||||
|
*
|
||||||
|
* idx[i] contains the source index number to select on of the widget path[i];
|
||||||
|
* e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
|
||||||
|
* multi[] indicates whether it's a selector widget with multi-connectors
|
||||||
|
* (i.e. the connection selection is mandatory)
|
||||||
|
* vol_ctl and mute_ctl contains the NIDs for the assigned mixers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_NID_PATH_DEPTH 10
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NID_PATH_VOL_CTL,
|
||||||
|
NID_PATH_MUTE_CTL,
|
||||||
|
NID_PATH_BOOST_CTL,
|
||||||
|
NID_PATH_NUM_CTLS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nid_path {
|
||||||
|
int depth;
|
||||||
|
hda_nid_t path[MAX_NID_PATH_DEPTH];
|
||||||
|
unsigned char idx[MAX_NID_PATH_DEPTH];
|
||||||
|
unsigned char multi[MAX_NID_PATH_DEPTH];
|
||||||
|
unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
|
||||||
|
bool active:1; /* activated by driver */
|
||||||
|
bool pin_enabled:1; /* pins are enabled */
|
||||||
|
bool pin_fixed:1; /* path with fixed pin */
|
||||||
|
bool stream_enabled:1; /* stream is active */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* mic/line-in auto switching entry */
|
||||||
|
|
||||||
|
#define MAX_AUTO_MIC_PINS 3
|
||||||
|
|
||||||
|
struct automic_entry {
|
||||||
|
hda_nid_t pin; /* pin */
|
||||||
|
int idx; /* imux index, -1 = invalid */
|
||||||
|
unsigned int attr; /* pin attribute (INPUT_PIN_ATTR_*) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* active stream id */
|
||||||
|
enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
|
||||||
|
|
||||||
|
/* PCM hook action */
|
||||||
|
enum {
|
||||||
|
HDA_GEN_PCM_ACT_OPEN,
|
||||||
|
HDA_GEN_PCM_ACT_PREPARE,
|
||||||
|
HDA_GEN_PCM_ACT_CLEANUP,
|
||||||
|
HDA_GEN_PCM_ACT_CLOSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* DAC assignment badness table */
|
||||||
|
struct badness_table {
|
||||||
|
int no_primary_dac; /* no primary DAC */
|
||||||
|
int no_dac; /* no secondary DACs */
|
||||||
|
int shared_primary; /* primary DAC is shared with main output */
|
||||||
|
int shared_surr; /* secondary DAC shared with main or primary */
|
||||||
|
int shared_clfe; /* third DAC shared with main or primary */
|
||||||
|
int shared_surr_main; /* secondary DAC sahred with main/DAC0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct badness_table hda_main_out_badness;
|
||||||
|
extern const struct badness_table hda_extra_out_badness;
|
||||||
|
|
||||||
|
struct hda_gen_spec {
|
||||||
|
char stream_name_analog[32]; /* analog PCM stream */
|
||||||
|
const struct hda_pcm_stream *stream_analog_playback;
|
||||||
|
const struct hda_pcm_stream *stream_analog_capture;
|
||||||
|
|
||||||
|
char stream_name_alt_analog[32]; /* alternative analog PCM stream */
|
||||||
|
const struct hda_pcm_stream *stream_analog_alt_playback;
|
||||||
|
const struct hda_pcm_stream *stream_analog_alt_capture;
|
||||||
|
|
||||||
|
char stream_name_digital[32]; /* digital PCM stream */
|
||||||
|
const struct hda_pcm_stream *stream_digital_playback;
|
||||||
|
const struct hda_pcm_stream *stream_digital_capture;
|
||||||
|
|
||||||
|
/* PCM */
|
||||||
|
unsigned int active_streams;
|
||||||
|
struct mutex pcm_mutex;
|
||||||
|
|
||||||
|
/* playback */
|
||||||
|
struct hda_multi_out multiout; /* playback set-up
|
||||||
|
* max_channels, dacs must be set
|
||||||
|
* dig_out_nid and hp_nid are optional
|
||||||
|
*/
|
||||||
|
hda_nid_t alt_dac_nid;
|
||||||
|
hda_nid_t follower_dig_outs[3]; /* optional - for auto-parsing */
|
||||||
|
int dig_out_type;
|
||||||
|
|
||||||
|
/* capture */
|
||||||
|
unsigned int num_adc_nids;
|
||||||
|
hda_nid_t adc_nids[AUTO_CFG_MAX_INS];
|
||||||
|
hda_nid_t dig_in_nid; /* digital-in NID; optional */
|
||||||
|
hda_nid_t mixer_nid; /* analog-mixer NID */
|
||||||
|
hda_nid_t mixer_merge_nid; /* aamix merge-point NID (optional) */
|
||||||
|
const char *input_labels[HDA_MAX_NUM_INPUTS];
|
||||||
|
int input_label_idxs[HDA_MAX_NUM_INPUTS];
|
||||||
|
|
||||||
|
/* capture setup for dynamic dual-adc switch */
|
||||||
|
hda_nid_t cur_adc;
|
||||||
|
unsigned int cur_adc_stream_tag;
|
||||||
|
unsigned int cur_adc_format;
|
||||||
|
|
||||||
|
/* capture source */
|
||||||
|
struct hda_input_mux input_mux;
|
||||||
|
unsigned int cur_mux[3];
|
||||||
|
|
||||||
|
/* channel model */
|
||||||
|
/* min_channel_count contains the minimum channel count for primary
|
||||||
|
* outputs. When multi_ios is set, the channels can be configured
|
||||||
|
* between min_channel_count and (min_channel_count + multi_ios * 2).
|
||||||
|
*
|
||||||
|
* ext_channel_count contains the current channel count of the primary
|
||||||
|
* out. This varies in the range above.
|
||||||
|
*
|
||||||
|
* Meanwhile, const_channel_count is the channel count for all outputs
|
||||||
|
* including headphone and speakers. It's a constant value, and the
|
||||||
|
* PCM is set up as max(ext_channel_count, const_channel_count).
|
||||||
|
*/
|
||||||
|
int min_channel_count; /* min. channel count for primary out */
|
||||||
|
int ext_channel_count; /* current channel count for primary */
|
||||||
|
int const_channel_count; /* channel count for all */
|
||||||
|
|
||||||
|
/* PCM information */
|
||||||
|
struct hda_pcm *pcm_rec[3]; /* used in build_pcms() */
|
||||||
|
|
||||||
|
/* dynamic controls, init_verbs and input_mux */
|
||||||
|
struct auto_pin_cfg autocfg;
|
||||||
|
struct snd_array kctls;
|
||||||
|
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
||||||
|
hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
|
||||||
|
unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
|
||||||
|
/* shared hp/mic */
|
||||||
|
hda_nid_t shared_mic_vref_pin;
|
||||||
|
hda_nid_t hp_mic_pin;
|
||||||
|
int hp_mic_mux_idx;
|
||||||
|
|
||||||
|
/* DAC/ADC lists */
|
||||||
|
int num_all_dacs;
|
||||||
|
hda_nid_t all_dacs[16];
|
||||||
|
int num_all_adcs;
|
||||||
|
hda_nid_t all_adcs[AUTO_CFG_MAX_INS];
|
||||||
|
|
||||||
|
/* path list */
|
||||||
|
struct snd_array paths;
|
||||||
|
|
||||||
|
/* path indices */
|
||||||
|
int out_paths[AUTO_CFG_MAX_OUTS];
|
||||||
|
int hp_paths[AUTO_CFG_MAX_OUTS];
|
||||||
|
int speaker_paths[AUTO_CFG_MAX_OUTS];
|
||||||
|
int aamix_out_paths[3];
|
||||||
|
int digout_paths[AUTO_CFG_MAX_OUTS];
|
||||||
|
int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS];
|
||||||
|
int loopback_paths[HDA_MAX_NUM_INPUTS];
|
||||||
|
int loopback_merge_path;
|
||||||
|
int digin_path;
|
||||||
|
|
||||||
|
/* auto-mic stuff */
|
||||||
|
int am_num_entries;
|
||||||
|
struct automic_entry am_entry[MAX_AUTO_MIC_PINS];
|
||||||
|
|
||||||
|
/* for pin sensing */
|
||||||
|
/* current status; set in hda_generic.c */
|
||||||
|
unsigned int hp_jack_present:1;
|
||||||
|
unsigned int line_jack_present:1;
|
||||||
|
unsigned int speaker_muted:1; /* current status of speaker mute */
|
||||||
|
unsigned int line_out_muted:1; /* current status of LO mute */
|
||||||
|
|
||||||
|
/* internal states of automute / autoswitch behavior */
|
||||||
|
unsigned int auto_mic:1;
|
||||||
|
unsigned int automute_speaker:1; /* automute speaker outputs */
|
||||||
|
unsigned int automute_lo:1; /* automute LO outputs */
|
||||||
|
|
||||||
|
/* capabilities detected by parser */
|
||||||
|
unsigned int detect_hp:1; /* Headphone detection enabled */
|
||||||
|
unsigned int detect_lo:1; /* Line-out detection enabled */
|
||||||
|
unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
|
||||||
|
unsigned int automute_lo_possible:1; /* there are line outs and HP */
|
||||||
|
|
||||||
|
/* additional parameters set by codec drivers */
|
||||||
|
unsigned int master_mute:1; /* master mute over all */
|
||||||
|
unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
|
||||||
|
unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
|
||||||
|
unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */
|
||||||
|
|
||||||
|
/* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
|
||||||
|
unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
|
||||||
|
unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */
|
||||||
|
|
||||||
|
/* other parse behavior flags */
|
||||||
|
unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
|
||||||
|
unsigned int hp_mic:1; /* Allow HP as a mic-in */
|
||||||
|
unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
|
||||||
|
unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
|
||||||
|
unsigned int no_multi_io:1; /* Don't try multi I/O config */
|
||||||
|
unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
|
||||||
|
unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
|
||||||
|
unsigned int own_eapd_ctl:1; /* set EAPD by own function */
|
||||||
|
unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */
|
||||||
|
unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */
|
||||||
|
unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */
|
||||||
|
unsigned int indep_hp:1; /* independent HP supported */
|
||||||
|
unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
|
||||||
|
unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
|
||||||
|
unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
|
||||||
|
unsigned int power_down_unused:1; /* power down unused widgets */
|
||||||
|
unsigned int dac_min_mute:1; /* minimal = mute for DACs */
|
||||||
|
unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
|
||||||
|
|
||||||
|
/* other internal flags */
|
||||||
|
unsigned int no_analog:1; /* digital I/O only */
|
||||||
|
unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
|
||||||
|
unsigned int indep_hp_enabled:1; /* independent HP enabled */
|
||||||
|
unsigned int have_aamix_ctl:1;
|
||||||
|
unsigned int hp_mic_jack_modes:1;
|
||||||
|
unsigned int skip_verbs:1; /* don't apply verbs at snd_hda_gen_init() */
|
||||||
|
|
||||||
|
/* additional mute flags (only effective with auto_mute_via_amp=1) */
|
||||||
|
u64 mute_bits;
|
||||||
|
|
||||||
|
/* bitmask for skipping volume controls */
|
||||||
|
u64 out_vol_mask;
|
||||||
|
|
||||||
|
/* badness tables for output path evaluations */
|
||||||
|
const struct badness_table *main_out_badness;
|
||||||
|
const struct badness_table *extra_out_badness;
|
||||||
|
|
||||||
|
/* preferred pin/DAC pairs; an array of paired NIDs */
|
||||||
|
const hda_nid_t *preferred_dacs;
|
||||||
|
|
||||||
|
/* loopback mixing mode */
|
||||||
|
bool aamix_mode;
|
||||||
|
|
||||||
|
/* digital beep */
|
||||||
|
hda_nid_t beep_nid;
|
||||||
|
|
||||||
|
/* for virtual master */
|
||||||
|
hda_nid_t vmaster_nid;
|
||||||
|
unsigned int vmaster_tlv[4];
|
||||||
|
struct hda_vmaster_mute_hook vmaster_mute;
|
||||||
|
|
||||||
|
struct hda_loopback_check loopback;
|
||||||
|
struct snd_array loopback_list;
|
||||||
|
|
||||||
|
/* multi-io */
|
||||||
|
int multi_ios;
|
||||||
|
struct hda_multi_io multi_io[4];
|
||||||
|
|
||||||
|
/* hooks */
|
||||||
|
void (*init_hook)(struct hda_codec *codec);
|
||||||
|
void (*automute_hook)(struct hda_codec *codec);
|
||||||
|
void (*cap_sync_hook)(struct hda_codec *codec,
|
||||||
|
struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
|
||||||
|
/* PCM hooks */
|
||||||
|
void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
|
||||||
|
struct hda_codec *codec,
|
||||||
|
struct snd_pcm_substream *substream,
|
||||||
|
int action);
|
||||||
|
void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo,
|
||||||
|
struct hda_codec *codec,
|
||||||
|
struct snd_pcm_substream *substream,
|
||||||
|
int action);
|
||||||
|
|
||||||
|
/* automute / autoswitch hooks */
|
||||||
|
void (*hp_automute_hook)(struct hda_codec *codec,
|
||||||
|
struct hda_jack_callback *cb);
|
||||||
|
void (*line_automute_hook)(struct hda_codec *codec,
|
||||||
|
struct hda_jack_callback *cb);
|
||||||
|
void (*mic_autoswitch_hook)(struct hda_codec *codec,
|
||||||
|
struct hda_jack_callback *cb);
|
||||||
|
|
||||||
|
/* leds */
|
||||||
|
struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* values for add_stereo_mix_input flag */
|
||||||
|
enum {
|
||||||
|
HDA_HINT_STEREO_MIX_DISABLE, /* No stereo mix input */
|
||||||
|
HDA_HINT_STEREO_MIX_ENABLE, /* Add stereo mix input */
|
||||||
|
HDA_HINT_STEREO_MIX_AUTO, /* Add only if auto-mic is disabled */
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
|
||||||
|
|
||||||
|
int snd_hda_gen_init(struct hda_codec *codec);
|
||||||
|
void snd_hda_gen_free(struct hda_codec *codec);
|
||||||
|
|
||||||
|
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
|
||||||
|
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
|
||||||
|
struct nid_path *
|
||||||
|
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
|
||||||
|
hda_nid_t to_nid, int anchor_nid);
|
||||||
|
void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
|
||||||
|
bool enable, bool add_aamix);
|
||||||
|
|
||||||
|
struct snd_kcontrol_new *
|
||||||
|
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
|
||||||
|
const struct snd_kcontrol_new *temp);
|
||||||
|
|
||||||
|
int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
|
||||||
|
struct auto_pin_cfg *cfg);
|
||||||
|
int snd_hda_gen_build_controls(struct hda_codec *codec);
|
||||||
|
int snd_hda_gen_build_pcms(struct hda_codec *codec);
|
||||||
|
|
||||||
|
/* standard jack event callbacks */
|
||||||
|
void snd_hda_gen_hp_automute(struct hda_codec *codec,
|
||||||
|
struct hda_jack_callback *jack);
|
||||||
|
void snd_hda_gen_line_automute(struct hda_codec *codec,
|
||||||
|
struct hda_jack_callback *jack);
|
||||||
|
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
|
||||||
|
struct hda_jack_callback *jack);
|
||||||
|
void snd_hda_gen_update_outputs(struct hda_codec *codec);
|
||||||
|
|
||||||
|
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
|
||||||
|
unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
|
||||||
|
hda_nid_t nid,
|
||||||
|
unsigned int power_state);
|
||||||
|
void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
|
||||||
|
int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
|
||||||
|
|
||||||
|
int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
|
||||||
|
int (*callback)(struct led_classdev *,
|
||||||
|
enum led_brightness));
|
||||||
|
int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
|
||||||
|
int (*callback)(struct led_classdev *,
|
||||||
|
enum led_brightness));
|
||||||
|
bool snd_hda_gen_shutup_speakers(struct hda_codec *codec);
|
||||||
|
|
||||||
|
#endif /* __SOUND_HDA_GENERIC_H */
|
195
hda_jack.h
Normal file
195
hda_jack.h
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Jack-detection handling for HD-audio
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_HDA_JACK_H
|
||||||
|
#define __SOUND_HDA_JACK_H
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <sound/jack.h>
|
||||||
|
|
||||||
|
struct auto_pin_cfg;
|
||||||
|
struct hda_jack_tbl;
|
||||||
|
struct hda_jack_callback;
|
||||||
|
|
||||||
|
typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *);
|
||||||
|
|
||||||
|
struct hda_jack_callback {
|
||||||
|
hda_nid_t nid;
|
||||||
|
int dev_id;
|
||||||
|
hda_jack_callback_fn func;
|
||||||
|
unsigned int private_data; /* arbitrary data */
|
||||||
|
unsigned int unsol_res; /* unsolicited event bits */
|
||||||
|
struct hda_jack_tbl *jack; /* associated jack entry */
|
||||||
|
struct hda_jack_callback *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hda_jack_tbl {
|
||||||
|
hda_nid_t nid;
|
||||||
|
int dev_id;
|
||||||
|
unsigned char tag; /* unsol event tag */
|
||||||
|
struct hda_jack_callback *callback;
|
||||||
|
/* jack-detection stuff */
|
||||||
|
unsigned int pin_sense; /* cached pin-sense value */
|
||||||
|
unsigned int jack_detect:1; /* capable of jack-detection? */
|
||||||
|
unsigned int jack_dirty:1; /* needs to update? */
|
||||||
|
unsigned int phantom_jack:1; /* a fixed, always present port? */
|
||||||
|
unsigned int block_report:1; /* in a transitional state - do not report to userspace */
|
||||||
|
hda_nid_t gating_jack; /* valid when gating jack plugged */
|
||||||
|
hda_nid_t gated_jack; /* gated is dependent on this jack */
|
||||||
|
hda_nid_t key_report_jack; /* key reports to this jack */
|
||||||
|
int type;
|
||||||
|
int button_state;
|
||||||
|
struct snd_jack *jack;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hda_jack_keymap {
|
||||||
|
enum snd_jack_types type;
|
||||||
|
int key;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hda_jack_tbl *
|
||||||
|
snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_jack_tbl_get - query the jack-table entry for the given NID
|
||||||
|
* @codec: the HDA codec
|
||||||
|
* @nid: pin NID to refer to
|
||||||
|
*/
|
||||||
|
static inline struct hda_jack_tbl *
|
||||||
|
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
return snd_hda_jack_tbl_get_mst(codec, nid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hda_jack_tbl *
|
||||||
|
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec,
|
||||||
|
unsigned char tag, int dev_id);
|
||||||
|
|
||||||
|
void snd_hda_jack_tbl_disconnect(struct hda_codec *codec);
|
||||||
|
void snd_hda_jack_tbl_clear(struct hda_codec *codec);
|
||||||
|
|
||||||
|
void snd_hda_jack_set_dirty_all(struct hda_codec *codec);
|
||||||
|
|
||||||
|
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dev_id);
|
||||||
|
|
||||||
|
struct hda_jack_callback *
|
||||||
|
snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dev_id, hda_jack_callback_fn func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_jack_detect_enable - enable the jack-detection
|
||||||
|
* @codec: the HDA codec
|
||||||
|
* @nid: pin NID to enable
|
||||||
|
* @func: callback function to register
|
||||||
|
*
|
||||||
|
* In the case of error, the return value will be a pointer embedded with
|
||||||
|
* errno. Check and handle the return value appropriately with standard
|
||||||
|
* macros such as @IS_ERR() and @PTR_ERR().
|
||||||
|
*/
|
||||||
|
static inline struct hda_jack_callback *
|
||||||
|
snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
hda_jack_callback_fn cb)
|
||||||
|
{
|
||||||
|
return snd_hda_jack_detect_enable_callback_mst(codec, nid, 0, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
|
||||||
|
hda_nid_t gating_nid);
|
||||||
|
|
||||||
|
int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid,
|
||||||
|
const struct hda_jack_keymap *keymap,
|
||||||
|
hda_nid_t jack_nid);
|
||||||
|
|
||||||
|
void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid,
|
||||||
|
int button_state);
|
||||||
|
|
||||||
|
u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id);
|
||||||
|
|
||||||
|
/* the jack state returned from snd_hda_jack_detect_state() */
|
||||||
|
enum {
|
||||||
|
HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM,
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_jack_detect_state_mst(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dev_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_jack_detect_state - query pin Presence Detect status
|
||||||
|
* @codec: the CODEC to sense
|
||||||
|
* @nid: the pin NID to sense
|
||||||
|
*
|
||||||
|
* Query and return the pin's Presence Detect status, as either
|
||||||
|
* HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
return snd_hda_jack_detect_state_mst(codec, nid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_jack_detect_mst - Detect the jack
|
||||||
|
* @codec: the HDA codec
|
||||||
|
* @nid: pin NID to check jack detection
|
||||||
|
* @dev_id: pin device entry id
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
snd_hda_jack_detect_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id)
|
||||||
|
{
|
||||||
|
return snd_hda_jack_detect_state_mst(codec, nid, dev_id) !=
|
||||||
|
HDA_JACK_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_jack_detect - Detect the jack
|
||||||
|
* @codec: the HDA codec
|
||||||
|
* @nid: pin NID to check jack detection
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
return snd_hda_jack_detect_mst(codec, nid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
|
||||||
|
|
||||||
|
int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dev_id, const char *name, bool phantom_jack,
|
||||||
|
int type, const struct hda_jack_keymap *keymap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_jack_add_kctl - Add a kctl for the given pin
|
||||||
|
* @codec: the HDA codec
|
||||||
|
* @nid: pin NID to assign
|
||||||
|
* @name: string name for the jack
|
||||||
|
* @phantom_jack: flag to deal as a phantom jack
|
||||||
|
* @type: jack type bits to be reported, 0 for guessing from pincfg
|
||||||
|
* @keymap: optional jack / key mapping
|
||||||
|
*
|
||||||
|
* This assigns a jack-detection kctl to the given pin. The kcontrol
|
||||||
|
* will have the given name and index.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
const char *name, bool phantom_jack,
|
||||||
|
int type, const struct hda_jack_keymap *keymap)
|
||||||
|
{
|
||||||
|
return snd_hda_jack_add_kctl_mst(codec, nid, 0,
|
||||||
|
name, phantom_jack, type, keymap);
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_hda_jack_add_kctls(struct hda_codec *codec,
|
||||||
|
const struct auto_pin_cfg *cfg);
|
||||||
|
|
||||||
|
void snd_hda_jack_report_sync(struct hda_codec *codec);
|
||||||
|
|
||||||
|
void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res);
|
||||||
|
|
||||||
|
void snd_hda_jack_poll_all(struct hda_codec *codec);
|
||||||
|
|
||||||
|
#endif /* __SOUND_HDA_JACK_H */
|
763
hda_local.h
Normal file
763
hda_local.h
Normal file
|
@ -0,0 +1,763 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Universal Interface for Intel High Definition Audio Codec
|
||||||
|
*
|
||||||
|
* Local helper functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_HDA_LOCAL_H
|
||||||
|
#define __SOUND_HDA_LOCAL_H
|
||||||
|
|
||||||
|
/* We abuse kcontrol_new.subdev field to pass the NID corresponding to
|
||||||
|
* the given new control. If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG,
|
||||||
|
* snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID.
|
||||||
|
*
|
||||||
|
* Note that the subdevice field is cleared again before the real registration
|
||||||
|
* in snd_hda_ctl_add(), so that this value won't appear in the outside.
|
||||||
|
*/
|
||||||
|
#define HDA_SUBDEV_NID_FLAG (1U << 31)
|
||||||
|
#define HDA_SUBDEV_AMP_FLAG (1U << 30)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for mixer controls
|
||||||
|
*/
|
||||||
|
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
|
||||||
|
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
|
||||||
|
#define HDA_AMP_VAL_MIN_MUTE (1<<29)
|
||||||
|
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
|
||||||
|
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
|
||||||
|
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
||||||
|
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||||
|
.subdevice = HDA_SUBDEV_AMP_FLAG, \
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
|
||||||
|
.info = snd_hda_mixer_amp_volume_info, \
|
||||||
|
.get = snd_hda_mixer_amp_volume_get, \
|
||||||
|
.put = snd_hda_mixer_amp_volume_put, \
|
||||||
|
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
|
||||||
|
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
|
||||||
|
/* stereo volume with index */
|
||||||
|
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
|
||||||
|
HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
|
||||||
|
/* mono volume */
|
||||||
|
#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
|
||||||
|
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
|
||||||
|
/* stereo volume */
|
||||||
|
#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
|
||||||
|
HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
|
||||||
|
/* stereo volume with min=mute */
|
||||||
|
#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
|
||||||
|
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
|
||||||
|
HDA_AMP_VAL_MIN_MUTE)
|
||||||
|
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
|
||||||
|
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||||
|
.subdevice = HDA_SUBDEV_AMP_FLAG, \
|
||||||
|
.info = snd_hda_mixer_amp_switch_info, \
|
||||||
|
.get = snd_hda_mixer_amp_switch_get, \
|
||||||
|
.put = snd_hda_mixer_amp_switch_put, \
|
||||||
|
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
|
||||||
|
/* stereo mute switch with index */
|
||||||
|
#define HDA_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \
|
||||||
|
HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
|
||||||
|
/* mono mute switch */
|
||||||
|
#define HDA_CODEC_MUTE_MONO(xname, nid, channel, xindex, direction) \
|
||||||
|
HDA_CODEC_MUTE_MONO_IDX(xname, 0, nid, channel, xindex, direction)
|
||||||
|
/* stereo mute switch */
|
||||||
|
#define HDA_CODEC_MUTE(xname, nid, xindex, direction) \
|
||||||
|
HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction)
|
||||||
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
||||||
|
/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
|
||||||
|
#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||||
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||||
|
.subdevice = HDA_SUBDEV_AMP_FLAG, \
|
||||||
|
.info = snd_hda_mixer_amp_switch_info, \
|
||||||
|
.get = snd_hda_mixer_amp_switch_get_beep, \
|
||||||
|
.put = snd_hda_mixer_amp_switch_put_beep, \
|
||||||
|
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
|
||||||
|
#else
|
||||||
|
/* no digital beep - just the standard one */
|
||||||
|
#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, ch, xidx, dir) \
|
||||||
|
HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, ch, xidx, dir)
|
||||||
|
#endif /* CONFIG_SND_HDA_INPUT_BEEP */
|
||||||
|
/* special beep mono mute switch */
|
||||||
|
#define HDA_CODEC_MUTE_BEEP_MONO(xname, nid, channel, xindex, direction) \
|
||||||
|
HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, 0, nid, channel, xindex, direction)
|
||||||
|
/* special beep stereo mute switch */
|
||||||
|
#define HDA_CODEC_MUTE_BEEP(xname, nid, xindex, direction) \
|
||||||
|
HDA_CODEC_MUTE_BEEP_MONO(xname, nid, 3, xindex, direction)
|
||||||
|
|
||||||
|
extern const char *snd_hda_pcm_type_name[];
|
||||||
|
|
||||||
|
int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_info *uinfo);
|
||||||
|
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
||||||
|
unsigned int size, unsigned int __user *_tlv);
|
||||||
|
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_info *uinfo);
|
||||||
|
int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
||||||
|
int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol);
|
||||||
|
#endif
|
||||||
|
/* lowlevel accessor with caching; use carefully */
|
||||||
|
#define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \
|
||||||
|
snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx)
|
||||||
|
int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int ch, int dir, int idx, int mask, int val);
|
||||||
|
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int direction, int idx, int mask, int val);
|
||||||
|
int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
|
||||||
|
int direction, int idx, int mask, int val);
|
||||||
|
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dir, int idx, int mask, int val);
|
||||||
|
void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||||
|
unsigned int *tlv);
|
||||||
|
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
||||||
|
const char *name);
|
||||||
|
int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||||
|
unsigned int *tlv, const char * const *followers,
|
||||||
|
const char *suffix, bool init_follower_vol,
|
||||||
|
unsigned int access, struct snd_kcontrol **ctl_ret);
|
||||||
|
#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \
|
||||||
|
__snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL)
|
||||||
|
int snd_hda_codec_reset(struct hda_codec *codec);
|
||||||
|
void snd_hda_codec_disconnect_pcms(struct hda_codec *codec);
|
||||||
|
|
||||||
|
#define snd_hda_regmap_sync(codec) snd_hdac_regmap_sync(&(codec)->core)
|
||||||
|
|
||||||
|
struct hda_vmaster_mute_hook {
|
||||||
|
/* below two fields must be filled by the caller of
|
||||||
|
* snd_hda_add_vmaster_hook() beforehand
|
||||||
|
*/
|
||||||
|
struct snd_kcontrol *sw_kctl;
|
||||||
|
void (*hook)(void *, int);
|
||||||
|
/* below are initialized automatically */
|
||||||
|
struct hda_codec *codec;
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
|
||||||
|
struct hda_vmaster_mute_hook *hook);
|
||||||
|
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);
|
||||||
|
|
||||||
|
/* amp value bits */
|
||||||
|
#define HDA_AMP_MUTE 0x80
|
||||||
|
#define HDA_AMP_UNMUTE 0x00
|
||||||
|
#define HDA_AMP_VOLMASK 0x7f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPDIF I/O
|
||||||
|
*/
|
||||||
|
int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
|
||||||
|
hda_nid_t associated_nid,
|
||||||
|
hda_nid_t cvt_nid, int type);
|
||||||
|
#define snd_hda_create_spdif_out_ctls(codec, anid, cnid) \
|
||||||
|
snd_hda_create_dig_out_ctls(codec, anid, cnid, HDA_PCM_TYPE_SPDIF)
|
||||||
|
int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* input MUX helper
|
||||||
|
*/
|
||||||
|
#define HDA_MAX_NUM_INPUTS 36
|
||||||
|
struct hda_input_mux_item {
|
||||||
|
char label[32];
|
||||||
|
unsigned int index;
|
||||||
|
};
|
||||||
|
struct hda_input_mux {
|
||||||
|
unsigned int num_items;
|
||||||
|
struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_input_mux_info(const struct hda_input_mux *imux,
|
||||||
|
struct snd_ctl_elem_info *uinfo);
|
||||||
|
int snd_hda_input_mux_put(struct hda_codec *codec,
|
||||||
|
const struct hda_input_mux *imux,
|
||||||
|
struct snd_ctl_elem_value *ucontrol, hda_nid_t nid,
|
||||||
|
unsigned int *cur_val);
|
||||||
|
int snd_hda_add_imux_item(struct hda_codec *codec,
|
||||||
|
struct hda_input_mux *imux, const char *label,
|
||||||
|
int index, int *type_idx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multi-channel / digital-out PCM helper
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */
|
||||||
|
enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */
|
||||||
|
|
||||||
|
#define HDA_MAX_OUTS 5
|
||||||
|
|
||||||
|
struct hda_multi_out {
|
||||||
|
int num_dacs; /* # of DACs, must be more than 1 */
|
||||||
|
const hda_nid_t *dac_nids; /* DAC list */
|
||||||
|
hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */
|
||||||
|
hda_nid_t hp_out_nid[HDA_MAX_OUTS]; /* DACs for multiple HPs */
|
||||||
|
hda_nid_t extra_out_nid[HDA_MAX_OUTS]; /* other (e.g. speaker) DACs */
|
||||||
|
hda_nid_t dig_out_nid; /* digital out audio widget */
|
||||||
|
const hda_nid_t *follower_dig_outs;
|
||||||
|
int max_channels; /* currently supported analog channels */
|
||||||
|
int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */
|
||||||
|
int no_share_stream; /* don't share a stream with multiple pins */
|
||||||
|
int share_spdif; /* share SPDIF pin */
|
||||||
|
/* PCM information for both analog and SPDIF DACs */
|
||||||
|
unsigned int analog_rates;
|
||||||
|
unsigned int analog_maxbps;
|
||||||
|
u64 analog_formats;
|
||||||
|
unsigned int spdif_rates;
|
||||||
|
unsigned int spdif_maxbps;
|
||||||
|
u64 spdif_formats;
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout);
|
||||||
|
int snd_hda_multi_out_dig_open(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout);
|
||||||
|
int snd_hda_multi_out_dig_close(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout);
|
||||||
|
int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout,
|
||||||
|
unsigned int stream_tag,
|
||||||
|
unsigned int format,
|
||||||
|
struct snd_pcm_substream *substream);
|
||||||
|
int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout);
|
||||||
|
int snd_hda_multi_out_analog_open(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout,
|
||||||
|
struct snd_pcm_substream *substream,
|
||||||
|
struct hda_pcm_stream *hinfo);
|
||||||
|
int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout,
|
||||||
|
unsigned int stream_tag,
|
||||||
|
unsigned int format,
|
||||||
|
struct snd_pcm_substream *substream);
|
||||||
|
int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
|
||||||
|
struct hda_multi_out *mout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generic proc interface
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_SND_PROC_FS
|
||||||
|
int snd_hda_codec_proc_new(struct hda_codec *codec);
|
||||||
|
#else
|
||||||
|
static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SND_PRINT_BITS_ADVISED_BUFSIZE 16
|
||||||
|
void snd_print_pcm_bits(int pcm, char *buf, int buflen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Misc
|
||||||
|
*/
|
||||||
|
int snd_hda_add_new_ctls(struct hda_codec *codec,
|
||||||
|
const struct snd_kcontrol_new *knew);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fix-up pin default configurations and add default verbs
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct hda_pintbl {
|
||||||
|
hda_nid_t nid;
|
||||||
|
u32 val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hda_model_fixup {
|
||||||
|
const int id;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hda_fixup {
|
||||||
|
int type;
|
||||||
|
bool chained:1; /* call the chained fixup(s) after this */
|
||||||
|
bool chained_before:1; /* call the chained fixup(s) before this */
|
||||||
|
int chain_id;
|
||||||
|
union {
|
||||||
|
const struct hda_pintbl *pins;
|
||||||
|
const struct hda_verb *verbs;
|
||||||
|
void (*func)(struct hda_codec *codec,
|
||||||
|
const struct hda_fixup *fix,
|
||||||
|
int action);
|
||||||
|
} v;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extended form of snd_pci_quirk:
|
||||||
|
* for PCI SSID matching, use SND_PCI_QUIRK() like before;
|
||||||
|
* for codec SSID matching, use the new HDA_CODEC_QUIRK() instead
|
||||||
|
*/
|
||||||
|
struct hda_quirk {
|
||||||
|
unsigned short subvendor; /* PCI subvendor ID */
|
||||||
|
unsigned short subdevice; /* PCI subdevice ID */
|
||||||
|
unsigned short subdevice_mask; /* bitmask to match */
|
||||||
|
bool match_codec_ssid; /* match only with codec SSID */
|
||||||
|
int value; /* value */
|
||||||
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||||
|
const char *name; /* name of the device (optional) */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||||
|
#define HDA_CODEC_QUIRK(vend, dev, xname, val) \
|
||||||
|
{ _SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname),\
|
||||||
|
.match_codec_ssid = true }
|
||||||
|
#else
|
||||||
|
#define HDA_CODEC_QUIRK(vend, dev, xname, val) \
|
||||||
|
{ _SND_PCI_QUIRK_ID(vend, dev), .value = (val), \
|
||||||
|
.match_codec_ssid = true }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct snd_hda_pin_quirk {
|
||||||
|
unsigned int codec; /* Codec vendor/device ID */
|
||||||
|
unsigned short subvendor; /* PCI subvendor ID */
|
||||||
|
const struct hda_pintbl *pins; /* list of matching pins */
|
||||||
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||||
|
const char *name;
|
||||||
|
#endif
|
||||||
|
int value; /* quirk value */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||||
|
|
||||||
|
#define SND_HDA_PIN_QUIRK(_codec, _subvendor, _name, _value, _pins...) \
|
||||||
|
{ .codec = _codec,\
|
||||||
|
.subvendor = _subvendor,\
|
||||||
|
.name = _name,\
|
||||||
|
.value = _value,\
|
||||||
|
.pins = (const struct hda_pintbl[]) { _pins, {0, 0}} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SND_HDA_PIN_QUIRK(_codec, _subvendor, _name, _value, _pins...) \
|
||||||
|
{ .codec = _codec,\
|
||||||
|
.subvendor = _subvendor,\
|
||||||
|
.value = _value,\
|
||||||
|
.pins = (const struct hda_pintbl[]) { _pins, {0, 0}} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HDA_FIXUP_ID_NOT_SET -1
|
||||||
|
#define HDA_FIXUP_ID_NO_FIXUP -2
|
||||||
|
|
||||||
|
/* fixup types */
|
||||||
|
enum {
|
||||||
|
HDA_FIXUP_INVALID,
|
||||||
|
HDA_FIXUP_PINS,
|
||||||
|
HDA_FIXUP_VERBS,
|
||||||
|
HDA_FIXUP_FUNC,
|
||||||
|
HDA_FIXUP_PINCTLS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* fixup action definitions */
|
||||||
|
enum {
|
||||||
|
HDA_FIXUP_ACT_PRE_PROBE,
|
||||||
|
HDA_FIXUP_ACT_PROBE,
|
||||||
|
HDA_FIXUP_ACT_INIT,
|
||||||
|
HDA_FIXUP_ACT_BUILD,
|
||||||
|
HDA_FIXUP_ACT_FREE,
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list);
|
||||||
|
void snd_hda_apply_verbs(struct hda_codec *codec);
|
||||||
|
void snd_hda_apply_pincfgs(struct hda_codec *codec,
|
||||||
|
const struct hda_pintbl *cfg);
|
||||||
|
void snd_hda_apply_fixup(struct hda_codec *codec, int action);
|
||||||
|
void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth);
|
||||||
|
void snd_hda_pick_fixup(struct hda_codec *codec,
|
||||||
|
const struct hda_model_fixup *models,
|
||||||
|
const struct hda_quirk *quirk,
|
||||||
|
const struct hda_fixup *fixlist);
|
||||||
|
void snd_hda_pick_pin_fixup(struct hda_codec *codec,
|
||||||
|
const struct snd_hda_pin_quirk *pin_quirk,
|
||||||
|
const struct hda_fixup *fixlist,
|
||||||
|
bool match_all_pins);
|
||||||
|
|
||||||
|
/* helper macros to retrieve pin default-config values */
|
||||||
|
#define get_defcfg_connect(cfg) \
|
||||||
|
((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
|
||||||
|
#define get_defcfg_association(cfg) \
|
||||||
|
((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT)
|
||||||
|
#define get_defcfg_location(cfg) \
|
||||||
|
((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
|
||||||
|
#define get_defcfg_sequence(cfg) \
|
||||||
|
(cfg & AC_DEFCFG_SEQUENCE)
|
||||||
|
#define get_defcfg_device(cfg) \
|
||||||
|
((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
|
||||||
|
#define get_defcfg_misc(cfg) \
|
||||||
|
((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
|
||||||
|
|
||||||
|
/* amp values */
|
||||||
|
#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
|
||||||
|
#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
|
||||||
|
#define AMP_OUT_MUTE 0xb080
|
||||||
|
#define AMP_OUT_UNMUTE 0xb000
|
||||||
|
#define AMP_OUT_ZERO 0xb000
|
||||||
|
/* pinctl values */
|
||||||
|
#define PIN_IN (AC_PINCTL_IN_EN)
|
||||||
|
#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
|
||||||
|
#define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
|
||||||
|
#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
|
||||||
|
#define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
|
||||||
|
#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
|
||||||
|
#define PIN_OUT (AC_PINCTL_OUT_EN)
|
||||||
|
#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
|
||||||
|
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
|
||||||
|
|
||||||
|
unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
|
||||||
|
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
|
||||||
|
hda_nid_t pin, unsigned int val);
|
||||||
|
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
|
||||||
|
unsigned int val, bool cached);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _snd_hda_set_pin_ctl - Set a pin-control value safely
|
||||||
|
* @codec: the codec instance
|
||||||
|
* @pin: the pin NID to set the control
|
||||||
|
* @val: the pin-control value (AC_PINCTL_* bits)
|
||||||
|
*
|
||||||
|
* This function sets the pin-control value to the given pin, but
|
||||||
|
* filters out the invalid pin-control bits when the pin has no such
|
||||||
|
* capabilities. For example, when PIN_HP is passed but the pin has no
|
||||||
|
* HP-drive capability, the HP bit is omitted.
|
||||||
|
*
|
||||||
|
* The function doesn't check the input VREF capability bits, though.
|
||||||
|
* Use snd_hda_get_default_vref() to guess the right value.
|
||||||
|
* Also, this function is only for analog pins, not for HDMI pins.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val)
|
||||||
|
{
|
||||||
|
return _snd_hda_set_pin_ctl(codec, pin, val, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_set_pin_ctl_cache - Set a pin-control value safely
|
||||||
|
* @codec: the codec instance
|
||||||
|
* @pin: the pin NID to set the control
|
||||||
|
* @val: the pin-control value (AC_PINCTL_* bits)
|
||||||
|
*
|
||||||
|
* Just like snd_hda_set_pin_ctl() but write to cache as well.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
|
||||||
|
unsigned int val)
|
||||||
|
{
|
||||||
|
return _snd_hda_set_pin_ctl(codec, pin, val, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid);
|
||||||
|
int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
unsigned int val);
|
||||||
|
|
||||||
|
#define for_each_hda_codec_node(nid, codec) \
|
||||||
|
for ((nid) = (codec)->core.start_nid; (nid) < (codec)->core.end_nid; (nid)++)
|
||||||
|
|
||||||
|
/* Set the codec power_state flag to indicate to allow unsol event handling;
|
||||||
|
* see hda_codec_unsol_event() in hda_bind.c. Calling this might confuse the
|
||||||
|
* state tracking, so use with care.
|
||||||
|
*/
|
||||||
|
static inline void snd_hda_codec_allow_unsol_events(struct hda_codec *codec)
|
||||||
|
{
|
||||||
|
codec->core.dev.power.power_state = PMSG_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get widget capabilities
|
||||||
|
*/
|
||||||
|
static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
if (nid < codec->core.start_nid ||
|
||||||
|
nid >= codec->core.start_nid + codec->core.num_nodes)
|
||||||
|
return 0;
|
||||||
|
return codec->wcaps[nid - codec->core.start_nid];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the widget type from widget capability bits */
|
||||||
|
static inline int get_wcaps_type(unsigned int wcaps)
|
||||||
|
{
|
||||||
|
if (!wcaps)
|
||||||
|
return -1; /* invalid type */
|
||||||
|
return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int get_wcaps_channels(u32 wcaps)
|
||||||
|
{
|
||||||
|
unsigned int chans;
|
||||||
|
|
||||||
|
chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13;
|
||||||
|
chans = ((chans << 1) | 1) + 1;
|
||||||
|
|
||||||
|
return chans;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void snd_hda_override_wcaps(struct hda_codec *codec,
|
||||||
|
hda_nid_t nid, u32 val)
|
||||||
|
{
|
||||||
|
if (nid >= codec->core.start_nid &&
|
||||||
|
nid < codec->core.start_nid + codec->core.num_nodes)
|
||||||
|
codec->wcaps[nid - codec->core.start_nid] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
|
||||||
|
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||||
|
unsigned int caps);
|
||||||
|
/**
|
||||||
|
* snd_hda_query_pin_caps - Query PIN capabilities
|
||||||
|
* @codec: the HD-auio codec
|
||||||
|
* @nid: the NID to query
|
||||||
|
*
|
||||||
|
* Query PIN capabilities for the given widget.
|
||||||
|
* Returns the obtained capability bits.
|
||||||
|
*
|
||||||
|
* When cap bits have been already read, this doesn't read again but
|
||||||
|
* returns the cached value.
|
||||||
|
*/
|
||||||
|
static inline u32
|
||||||
|
snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_hda_override_pin_caps - Override the pin capabilities
|
||||||
|
* @codec: the CODEC
|
||||||
|
* @nid: the NID to override
|
||||||
|
* @caps: the capability bits to set
|
||||||
|
*
|
||||||
|
* Override the cached PIN capabilitiy bits value by the given one.
|
||||||
|
*
|
||||||
|
* Returns zero if successful or a negative error code.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
unsigned int caps)
|
||||||
|
{
|
||||||
|
return snd_hdac_override_parm(&codec->core, nid, AC_PAR_PIN_CAP, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dir, unsigned int bits);
|
||||||
|
|
||||||
|
#define nid_has_mute(codec, nid, dir) \
|
||||||
|
snd_hda_check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))
|
||||||
|
#define nid_has_volume(codec, nid, dir) \
|
||||||
|
snd_hda_check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
|
||||||
|
|
||||||
|
|
||||||
|
/* flags for hda_nid_item */
|
||||||
|
#define HDA_NID_ITEM_AMP (1<<0)
|
||||||
|
|
||||||
|
struct hda_nid_item {
|
||||||
|
struct snd_kcontrol *kctl;
|
||||||
|
unsigned int index;
|
||||||
|
hda_nid_t nid;
|
||||||
|
unsigned short flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
struct snd_kcontrol *kctl);
|
||||||
|
int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
|
||||||
|
unsigned int index, hda_nid_t nid);
|
||||||
|
void snd_hda_ctls_clear(struct hda_codec *codec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hwdep interface
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_SND_HDA_HWDEP
|
||||||
|
int snd_hda_create_hwdep(struct hda_codec *codec);
|
||||||
|
#else
|
||||||
|
static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void snd_hda_sysfs_init(struct hda_codec *codec);
|
||||||
|
void snd_hda_sysfs_clear(struct hda_codec *codec);
|
||||||
|
|
||||||
|
extern const struct attribute_group *snd_hda_dev_attr_groups[];
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_HDA_RECONFIG
|
||||||
|
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
|
||||||
|
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key);
|
||||||
|
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp);
|
||||||
|
#else
|
||||||
|
static inline
|
||||||
|
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
|
||||||
|
{
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
|
||||||
|
{
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* power-management
|
||||||
|
*/
|
||||||
|
|
||||||
|
void snd_hda_schedule_power_save(struct hda_codec *codec);
|
||||||
|
|
||||||
|
struct hda_amp_list {
|
||||||
|
hda_nid_t nid;
|
||||||
|
unsigned char dir;
|
||||||
|
unsigned char idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hda_loopback_check {
|
||||||
|
const struct hda_amp_list *amplist;
|
||||||
|
int power_on;
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
||||||
|
struct hda_loopback_check *check,
|
||||||
|
hda_nid_t nid);
|
||||||
|
|
||||||
|
/* check whether the actual power state matches with the target state */
|
||||||
|
static inline bool
|
||||||
|
snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
unsigned int target_state)
|
||||||
|
{
|
||||||
|
return snd_hdac_check_power_state(&codec->core, nid, target_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int snd_hda_sync_power_state(struct hda_codec *codec,
|
||||||
|
hda_nid_t nid,
|
||||||
|
unsigned int target_state)
|
||||||
|
{
|
||||||
|
return snd_hdac_sync_power_state(&codec->core, nid, target_state);
|
||||||
|
}
|
||||||
|
unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
|
||||||
|
hda_nid_t nid,
|
||||||
|
unsigned int power_state);
|
||||||
|
|
||||||
|
void snd_hda_codec_shutdown(struct hda_codec *codec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AMP control callbacks
|
||||||
|
*/
|
||||||
|
/* retrieve parameters from private_value */
|
||||||
|
#define get_amp_nid_(pv) ((pv) & 0xffff)
|
||||||
|
#define get_amp_nid(kc) get_amp_nid_((kc)->private_value)
|
||||||
|
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
|
||||||
|
#define get_amp_direction_(pv) (((pv) >> 18) & 0x1)
|
||||||
|
#define get_amp_direction(kc) get_amp_direction_((kc)->private_value)
|
||||||
|
#define get_amp_index_(pv) (((pv) >> 19) & 0xf)
|
||||||
|
#define get_amp_index(kc) get_amp_index_((kc)->private_value)
|
||||||
|
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
|
||||||
|
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum control helper
|
||||||
|
*/
|
||||||
|
int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_info *uinfo,
|
||||||
|
int num_items, const char * const *texts);
|
||||||
|
#define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \
|
||||||
|
snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CEA Short Audio Descriptor data
|
||||||
|
*/
|
||||||
|
struct cea_sad {
|
||||||
|
int channels;
|
||||||
|
int format; /* (format == 0) indicates invalid SAD */
|
||||||
|
int rates;
|
||||||
|
int sample_bits; /* for LPCM */
|
||||||
|
int max_bitrate; /* for AC3...ATRAC */
|
||||||
|
int profile; /* for WMAPRO */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ELD_FIXED_BYTES 20
|
||||||
|
#define ELD_MAX_SIZE 256
|
||||||
|
#define ELD_MAX_MNL 16
|
||||||
|
#define ELD_MAX_SAD 16
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ELD: EDID Like Data
|
||||||
|
*/
|
||||||
|
struct parsed_hdmi_eld {
|
||||||
|
/*
|
||||||
|
* all fields will be cleared before updating ELD
|
||||||
|
*/
|
||||||
|
int baseline_len;
|
||||||
|
int eld_ver;
|
||||||
|
int cea_edid_ver;
|
||||||
|
char monitor_name[ELD_MAX_MNL + 1];
|
||||||
|
int manufacture_id;
|
||||||
|
int product_id;
|
||||||
|
u64 port_id;
|
||||||
|
int support_hdcp;
|
||||||
|
int support_ai;
|
||||||
|
int conn_type;
|
||||||
|
int aud_synch_delay;
|
||||||
|
int spk_alloc;
|
||||||
|
int sad_count;
|
||||||
|
struct cea_sad sad[ELD_MAX_SAD];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hdmi_eld {
|
||||||
|
bool monitor_present;
|
||||||
|
bool eld_valid;
|
||||||
|
int eld_size;
|
||||||
|
char eld_buffer[ELD_MAX_SIZE];
|
||||||
|
struct parsed_hdmi_eld info;
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
|
||||||
|
int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
unsigned char *buf, int *eld_size);
|
||||||
|
int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e,
|
||||||
|
const unsigned char *buf, int size);
|
||||||
|
void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e);
|
||||||
|
void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
|
||||||
|
struct hda_pcm_stream *hinfo);
|
||||||
|
|
||||||
|
int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
unsigned char *buf, int *eld_size,
|
||||||
|
bool rev3_or_later);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SND_PROC_FS
|
||||||
|
void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
|
||||||
|
struct snd_info_buffer *buffer,
|
||||||
|
hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid);
|
||||||
|
void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
|
||||||
|
struct snd_info_buffer *buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
|
||||||
|
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
|
||||||
|
|
||||||
|
void snd_hda_codec_display_power(struct hda_codec *codec, bool enable);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
#define codec_err(codec, fmt, args...) \
|
||||||
|
dev_err(hda_codec_dev(codec), fmt, ##args)
|
||||||
|
#define codec_warn(codec, fmt, args...) \
|
||||||
|
dev_warn(hda_codec_dev(codec), fmt, ##args)
|
||||||
|
#define codec_info(codec, fmt, args...) \
|
||||||
|
dev_info(hda_codec_dev(codec), fmt, ##args)
|
||||||
|
#define codec_dbg(codec, fmt, args...) \
|
||||||
|
dev_dbg(hda_codec_dev(codec), fmt, ##args)
|
||||||
|
|
||||||
|
#endif /* __SOUND_HDA_LOCAL_H */
|
623
patch_cs8409-tables.c
Normal file
623
patch_cs8409-tables.c
Normal file
|
@ -0,0 +1,623 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* patch_cs8409-tables.c -- HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Cirrus Logic, Inc. and
|
||||||
|
* Cirrus Logic International Semiconductor Ltd.
|
||||||
|
*
|
||||||
|
* Author: Lucas Tanure <tanureal@opensource.cirrus.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "patch_cs8409.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* CS42L42 Specific Data
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
static const DECLARE_TLV_DB_SCALE(cs42l42_dac_db_scale, CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
|
||||||
|
|
||||||
|
static const DECLARE_TLV_DB_SCALE(cs42l42_adc_db_scale, CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
|
||||||
|
|
||||||
|
const struct snd_kcontrol_new cs42l42_dac_volume_mixer = {
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.index = 0,
|
||||||
|
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
|
.info = cs42l42_volume_info,
|
||||||
|
.get = cs42l42_volume_get,
|
||||||
|
.put = cs42l42_volume_put,
|
||||||
|
.tlv = { .p = cs42l42_dac_db_scale },
|
||||||
|
.private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_TRANSMITTER_A, 3, CS8409_CODEC0,
|
||||||
|
HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct snd_kcontrol_new cs42l42_adc_volume_mixer = {
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.index = 0,
|
||||||
|
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
|
||||||
|
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
|
||||||
|
.info = cs42l42_volume_info,
|
||||||
|
.get = cs42l42_volume_get,
|
||||||
|
.put = cs42l42_volume_put,
|
||||||
|
.tlv = { .p = cs42l42_adc_db_scale },
|
||||||
|
.private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_RECEIVER_A, 1, CS8409_CODEC0,
|
||||||
|
HDA_INPUT, CS42L42_VOL_ADC) | HDA_AMP_VAL_MIN_MUTE
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback = {
|
||||||
|
.rates = SNDRV_PCM_RATE_48000, /* fixed rate */
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture = {
|
||||||
|
.rates = SNDRV_PCM_RATE_48000, /* fixed rate */
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* BULLSEYE / WARLOCK / CYBORG Specific Arrays
|
||||||
|
* CS8409/CS42L42
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
const struct hda_verb cs8409_cs42l42_init_verbs[] = {
|
||||||
|
{ CS8409_PIN_AFG, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF, 0x0080 }, /* I2C mode */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF, 0x0200 }, /* 100kHz I2C_STO = 2 */
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
|
||||||
|
{ CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 }, /* ASP-1-TX */
|
||||||
|
{ CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 }, /* ASP-1-RX */
|
||||||
|
{ CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 }, /* ASP-2-TX */
|
||||||
|
{ CS8409_PIN_DMIC1_IN, 0x90a00090 }, /* DMIC-1 */
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hda_pintbl cs8409_cs42l42_pincfgs_no_dmic[] = {
|
||||||
|
{ CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 }, /* ASP-1-TX */
|
||||||
|
{ CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 }, /* ASP-1-RX */
|
||||||
|
{ CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 }, /* ASP-2-TX */
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vendor specific HW configuration for CS42L42 */
|
||||||
|
static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
|
||||||
|
{ CS42L42_I2C_TIMEOUT, 0xB0 },
|
||||||
|
{ CS42L42_ADC_CTL, 0x00 },
|
||||||
|
{ 0x1D02, 0x06 },
|
||||||
|
{ CS42L42_ADC_VOLUME, 0x9F },
|
||||||
|
{ CS42L42_OSC_SWITCH, 0x01 },
|
||||||
|
{ CS42L42_MCLK_CTL, 0x02 },
|
||||||
|
{ CS42L42_SRC_CTL, 0x03 },
|
||||||
|
{ CS42L42_MCLK_SRC_SEL, 0x00 },
|
||||||
|
{ CS42L42_ASP_FRM_CFG, 0x13 },
|
||||||
|
{ CS42L42_FSYNC_P_LOWER, 0xFF },
|
||||||
|
{ CS42L42_FSYNC_P_UPPER, 0x00 },
|
||||||
|
{ CS42L42_ASP_CLK_CFG, 0x20 },
|
||||||
|
{ CS42L42_SPDIF_CLK_CFG, 0x0D },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x80 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0xA0 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_EN, 0x0C },
|
||||||
|
{ CS42L42_ASP_TX_CH_EN, 0x01 },
|
||||||
|
{ CS42L42_ASP_TX_CH_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_SZ_EN, 0x01 },
|
||||||
|
{ CS42L42_PWR_CTL1, 0x0A },
|
||||||
|
{ CS42L42_PWR_CTL2, 0x84 },
|
||||||
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
||||||
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
||||||
|
{ CS42L42_MIXER_ADC_VOL, 0x3f },
|
||||||
|
{ CS42L42_HP_CTL, 0x0D },
|
||||||
|
{ CS42L42_MIC_DET_CTL1, 0xB6 },
|
||||||
|
{ CS42L42_TIPSENSE_CTL, 0xC2 },
|
||||||
|
{ CS42L42_HS_CLAMP_DISABLE, 0x01 },
|
||||||
|
{ CS42L42_HS_SWITCH_CTL, 0xF3 },
|
||||||
|
{ CS42L42_PWR_CTL3, 0x20 },
|
||||||
|
{ CS42L42_RSENSE_CTL2, 0x00 },
|
||||||
|
{ CS42L42_RSENSE_CTL3, 0x00 },
|
||||||
|
{ CS42L42_TSENSE_CTL, 0x80 },
|
||||||
|
{ CS42L42_HS_BIAS_CTL, 0xC0 },
|
||||||
|
{ CS42L42_PWR_CTL1, 0x02, 10000 },
|
||||||
|
{ CS42L42_ADC_OVFL_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_MIXER_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_SRC_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_ASP_RX_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_ASP_TX_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_CODEC_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_SRCPL_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_VPMON_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_PLL_LOCK_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_TSRS_PLUG_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_DET_INT1_MASK, 0xff },
|
||||||
|
{ CS42L42_DET_INT2_MASK, 0xff },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vendor specific hw configuration for CS8409 */
|
||||||
|
const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = {
|
||||||
|
/* +PLL1/2_EN, +I2C_EN */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
|
||||||
|
/* ASP1/2_EN=0, ASP1_STP=1 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
|
||||||
|
/* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
|
||||||
|
/* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL1, 0x0800 },
|
||||||
|
/* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL2, 0x0820 },
|
||||||
|
/* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL1, 0x0800 },
|
||||||
|
/* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL2, 0x2800 },
|
||||||
|
/* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL1, 0x0800 },
|
||||||
|
/* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL2, 0x0800 },
|
||||||
|
/* ASP1: LCHI = 00h */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
|
||||||
|
/* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
|
||||||
|
/* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
|
||||||
|
/* ASP2: LCHI=1Fh */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL1, 0x801f },
|
||||||
|
/* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL2, 0x283f },
|
||||||
|
/* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL3, 0x805c },
|
||||||
|
/* DMIC1_MO=10b, DMIC1/2_SR=1 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DMIC_CFG, 0x0023 },
|
||||||
|
/* ASP1/2_BEEP=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
|
||||||
|
/* ASP1/2_EN=1, ASP1_STP=1 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0062 },
|
||||||
|
/* -PLL2_EN */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 },
|
||||||
|
/* TX2.A: pre-scale att.=0 dB */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PRE_SCALE_ATTN2, 0x0000 },
|
||||||
|
/* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc03 },
|
||||||
|
/* test mode on */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x9999 },
|
||||||
|
/* GPIO hysteresis = 30 us */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, 0xc5, 0x0000 },
|
||||||
|
/* test mode off */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x0000 },
|
||||||
|
{} /* Terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = {
|
||||||
|
/* EQ_SEL=1, EQ1/2_EN=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_CTRL1, 0x4000 },
|
||||||
|
/* +EQ_ACC */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x4000 },
|
||||||
|
/* +EQ2_EN */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_CTRL1, 0x4010 },
|
||||||
|
/* EQ_DATA_HI=0x0647 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x0647 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=0, EQ_DATA_LO=0x67 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc0c7 },
|
||||||
|
/* EQ_DATA_HI=0x0647 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x0647 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=1, EQ_DATA_LO=0x67 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc1c7 },
|
||||||
|
/* EQ_DATA_HI=0xf370 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xf370 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=2, EQ_DATA_LO=0x71 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc271 },
|
||||||
|
/* EQ_DATA_HI=0x1ef8 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1ef8 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=3, EQ_DATA_LO=0x48 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc348 },
|
||||||
|
/* EQ_DATA_HI=0xc110 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc110 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=4, EQ_DATA_LO=0x5a */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc45a },
|
||||||
|
/* EQ_DATA_HI=0x1f29 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1f29 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=5, EQ_DATA_LO=0x74 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc574 },
|
||||||
|
/* EQ_DATA_HI=0x1d7a */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1d7a },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=6, EQ_DATA_LO=0x53 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc653 },
|
||||||
|
/* EQ_DATA_HI=0xc38c */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc38c },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=7, EQ_DATA_LO=0x14 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc714 },
|
||||||
|
/* EQ_DATA_HI=0x1ca3 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1ca3 },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=8, EQ_DATA_LO=0xc7 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc8c7 },
|
||||||
|
/* EQ_DATA_HI=0xc38c */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc38c },
|
||||||
|
/* +EQ_WRT, +EQ_ACC, EQ_ADR=9, EQ_DATA_LO=0x14 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc914 },
|
||||||
|
/* -EQ_ACC, -EQ_WRT */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x0000 },
|
||||||
|
{} /* Terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sub_codec cs8409_cs42l42_codec = {
|
||||||
|
.addr = CS42L42_I2C_ADDR,
|
||||||
|
.reset_gpio = CS8409_CS42L42_RESET,
|
||||||
|
.irq_mask = CS8409_CS42L42_INT,
|
||||||
|
.init_seq = cs42l42_init_reg_seq,
|
||||||
|
.init_seq_num = ARRAY_SIZE(cs42l42_init_reg_seq),
|
||||||
|
.hp_jack_in = 0,
|
||||||
|
.mic_jack_in = 0,
|
||||||
|
.paged = 1,
|
||||||
|
.suspended = 1,
|
||||||
|
.no_type_dect = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Dolphin Specific Arrays
|
||||||
|
* CS8409/ 2 X CS42L42
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
const struct hda_verb dolphin_init_verbs[] = {
|
||||||
|
{ 0x01, AC_VERB_SET_GPIO_WAKE_MASK, DOLPHIN_WAKE }, /* WAKE from GPIO 0,4 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF, 0x0080 }, /* I2C mode */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF, 0x0200 }, /* 100kHz I2C_STO = 2 */
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hda_pintbl dolphin_pincfgs[] = {
|
||||||
|
{ 0x24, 0x022210f0 }, /* ASP-1-TX-A */
|
||||||
|
{ 0x25, 0x010240f0 }, /* ASP-1-TX-B */
|
||||||
|
{ 0x34, 0x02a21050 }, /* ASP-1-RX */
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vendor specific HW configuration for CS42L42 */
|
||||||
|
static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = {
|
||||||
|
{ CS42L42_I2C_TIMEOUT, 0xB0 },
|
||||||
|
{ CS42L42_ADC_CTL, 0x00 },
|
||||||
|
{ 0x1D02, 0x06 },
|
||||||
|
{ CS42L42_ADC_VOLUME, 0x9F },
|
||||||
|
{ CS42L42_OSC_SWITCH, 0x01 },
|
||||||
|
{ CS42L42_MCLK_CTL, 0x02 },
|
||||||
|
{ CS42L42_SRC_CTL, 0x03 },
|
||||||
|
{ CS42L42_MCLK_SRC_SEL, 0x00 },
|
||||||
|
{ CS42L42_ASP_FRM_CFG, 0x13 },
|
||||||
|
{ CS42L42_FSYNC_P_LOWER, 0xFF },
|
||||||
|
{ CS42L42_FSYNC_P_UPPER, 0x00 },
|
||||||
|
{ CS42L42_ASP_CLK_CFG, 0x20 },
|
||||||
|
{ CS42L42_SPDIF_CLK_CFG, 0x0D },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_EN, 0x0C },
|
||||||
|
{ CS42L42_ASP_TX_CH_EN, 0x01 },
|
||||||
|
{ CS42L42_ASP_TX_CH_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_SZ_EN, 0x01 },
|
||||||
|
{ CS42L42_PWR_CTL1, 0x0A },
|
||||||
|
{ CS42L42_PWR_CTL2, 0x84 },
|
||||||
|
{ CS42L42_HP_CTL, 0x0D },
|
||||||
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
||||||
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
||||||
|
{ CS42L42_MIXER_ADC_VOL, 0x3f },
|
||||||
|
{ CS42L42_MIC_DET_CTL1, 0xB6 },
|
||||||
|
{ CS42L42_TIPSENSE_CTL, 0xC2 },
|
||||||
|
{ CS42L42_HS_CLAMP_DISABLE, 0x01 },
|
||||||
|
{ CS42L42_HS_SWITCH_CTL, 0xF3 },
|
||||||
|
{ CS42L42_PWR_CTL3, 0x20 },
|
||||||
|
{ CS42L42_RSENSE_CTL2, 0x00 },
|
||||||
|
{ CS42L42_RSENSE_CTL3, 0x00 },
|
||||||
|
{ CS42L42_TSENSE_CTL, 0x80 },
|
||||||
|
{ CS42L42_HS_BIAS_CTL, 0xC0 },
|
||||||
|
{ CS42L42_PWR_CTL1, 0x02, 10000 },
|
||||||
|
{ CS42L42_ADC_OVFL_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_MIXER_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_SRC_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_ASP_RX_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_ASP_TX_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_CODEC_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_SRCPL_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_VPMON_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_PLL_LOCK_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_TSRS_PLUG_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_DET_INT1_MASK, 0xff },
|
||||||
|
{ CS42L42_DET_INT2_MASK, 0xff }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = {
|
||||||
|
{ CS42L42_I2C_TIMEOUT, 0xB0 },
|
||||||
|
{ CS42L42_ADC_CTL, 0x00 },
|
||||||
|
{ 0x1D02, 0x06 },
|
||||||
|
{ CS42L42_ADC_VOLUME, 0x9F },
|
||||||
|
{ CS42L42_OSC_SWITCH, 0x01 },
|
||||||
|
{ CS42L42_MCLK_CTL, 0x02 },
|
||||||
|
{ CS42L42_SRC_CTL, 0x03 },
|
||||||
|
{ CS42L42_MCLK_SRC_SEL, 0x00 },
|
||||||
|
{ CS42L42_ASP_FRM_CFG, 0x13 },
|
||||||
|
{ CS42L42_FSYNC_P_LOWER, 0xFF },
|
||||||
|
{ CS42L42_FSYNC_P_UPPER, 0x00 },
|
||||||
|
{ CS42L42_ASP_CLK_CFG, 0x20 },
|
||||||
|
{ CS42L42_SPDIF_CLK_CFG, 0x0D },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x80 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0xA0 },
|
||||||
|
{ CS42L42_ASP_RX_DAI0_EN, 0x0C },
|
||||||
|
{ CS42L42_ASP_TX_CH_EN, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_CH_AP_RES, 0x02 },
|
||||||
|
{ CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
|
||||||
|
{ CS42L42_ASP_TX_SZ_EN, 0x00 },
|
||||||
|
{ CS42L42_PWR_CTL1, 0x0E },
|
||||||
|
{ CS42L42_PWR_CTL2, 0x84 },
|
||||||
|
{ CS42L42_HP_CTL, 0x0D },
|
||||||
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
||||||
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
||||||
|
{ CS42L42_MIXER_ADC_VOL, 0x3f },
|
||||||
|
{ CS42L42_MIC_DET_CTL1, 0xB6 },
|
||||||
|
{ CS42L42_TIPSENSE_CTL, 0xC2 },
|
||||||
|
{ CS42L42_HS_CLAMP_DISABLE, 0x01 },
|
||||||
|
{ CS42L42_HS_SWITCH_CTL, 0xF3 },
|
||||||
|
{ CS42L42_PWR_CTL3, 0x20 },
|
||||||
|
{ CS42L42_RSENSE_CTL2, 0x00 },
|
||||||
|
{ CS42L42_RSENSE_CTL3, 0x00 },
|
||||||
|
{ CS42L42_TSENSE_CTL, 0x80 },
|
||||||
|
{ CS42L42_HS_BIAS_CTL, 0xC0 },
|
||||||
|
{ CS42L42_PWR_CTL1, 0x06, 10000 },
|
||||||
|
{ CS42L42_ADC_OVFL_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_MIXER_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_SRC_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_ASP_RX_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_ASP_TX_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_CODEC_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_SRCPL_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_VPMON_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_PLL_LOCK_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_TSRS_PLUG_INT_MASK, 0xff },
|
||||||
|
{ CS42L42_DET_INT1_MASK, 0xff },
|
||||||
|
{ CS42L42_DET_INT2_MASK, 0xff }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vendor specific hw configuration for CS8409 */
|
||||||
|
const struct cs8409_cir_param dolphin_hw_cfg[] = {
|
||||||
|
/* +PLL1/2_EN, +I2C_EN */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
|
||||||
|
/* ASP1_EN=0, ASP1_STP=1 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
|
||||||
|
/* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
|
||||||
|
/* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL1, 0x0800 },
|
||||||
|
/* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL2, 0x0820 },
|
||||||
|
/* ASP1.B: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=128 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_B_TX_CTRL1, 0x0880 },
|
||||||
|
/* ASP1.B: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=160 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_B_TX_CTRL2, 0x08a0 },
|
||||||
|
/* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL1, 0x0800 },
|
||||||
|
/* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL2, 0x0800 },
|
||||||
|
/* ASP1: LCHI = 00h */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
|
||||||
|
/* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
|
||||||
|
/* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
|
||||||
|
/* ASP1/2_BEEP=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
|
||||||
|
/* ASP1_EN=1, ASP1_STP=1 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0022 },
|
||||||
|
/* -PLL2_EN */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 },
|
||||||
|
/* ASP1_xxx_EN=1, ASP1_MCLK_EN=0 */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0x5400 },
|
||||||
|
/* test mode on */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x9999 },
|
||||||
|
/* GPIO hysteresis = 30 us */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, 0xc5, 0x0000 },
|
||||||
|
/* test mode off */
|
||||||
|
{ CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x0000 },
|
||||||
|
{} /* Terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sub_codec dolphin_cs42l42_0 = {
|
||||||
|
.addr = DOLPHIN_C0_I2C_ADDR,
|
||||||
|
.reset_gpio = DOLPHIN_C0_RESET,
|
||||||
|
.irq_mask = DOLPHIN_C0_INT,
|
||||||
|
.init_seq = dolphin_c0_init_reg_seq,
|
||||||
|
.init_seq_num = ARRAY_SIZE(dolphin_c0_init_reg_seq),
|
||||||
|
.hp_jack_in = 0,
|
||||||
|
.mic_jack_in = 0,
|
||||||
|
.paged = 1,
|
||||||
|
.suspended = 1,
|
||||||
|
.no_type_dect = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sub_codec dolphin_cs42l42_1 = {
|
||||||
|
.addr = DOLPHIN_C1_I2C_ADDR,
|
||||||
|
.reset_gpio = DOLPHIN_C1_RESET,
|
||||||
|
.irq_mask = DOLPHIN_C1_INT,
|
||||||
|
.init_seq = dolphin_c1_init_reg_seq,
|
||||||
|
.init_seq_num = ARRAY_SIZE(dolphin_c1_init_reg_seq),
|
||||||
|
.hp_jack_in = 0,
|
||||||
|
.mic_jack_in = 0,
|
||||||
|
.paged = 1,
|
||||||
|
.suspended = 1,
|
||||||
|
.no_type_dect = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* CS8409 Patch Driver Structs
|
||||||
|
* Arrays Used for all projects using CS8409
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
const struct hda_quirk cs8409_fixup_tbl[] = {
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0ACF, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AD0, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AD1, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AD2, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AD3, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0B92, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0B93, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0B94, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0B95, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0B96, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0B97, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BA5, "Odin", CS8409_ODIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BA6, "Odin", CS8409_ODIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BA8, "Odin", CS8409_ODIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BAA, "Odin", CS8409_ODIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BAE, "Odin", CS8409_ODIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB2, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB3, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB4, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB5, "Warlock N3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB6, "Warlock V3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB8, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BB9, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BBA, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BBB, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BBC, "Warlock MLK", CS8409_WARLOCK_MLK),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BBD, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BD4, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BD5, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BD6, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BD7, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0BD8, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C43, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C73, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C75, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C7D, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
SND_PCI_QUIRK(0x1028, 0x0C7F, "Dolphin", CS8409_DOLPHIN),
|
||||||
|
{} /* terminator */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Dell Inspiron models with cs8409/cs42l42 */
|
||||||
|
const struct hda_model_fixup cs8409_models[] = {
|
||||||
|
{ .id = CS8409_BULLSEYE, .name = "bullseye" },
|
||||||
|
{ .id = CS8409_WARLOCK, .name = "warlock" },
|
||||||
|
{ .id = CS8409_WARLOCK_MLK, .name = "warlock mlk" },
|
||||||
|
{ .id = CS8409_WARLOCK_MLK_DUAL_MIC, .name = "warlock mlk dual mic" },
|
||||||
|
{ .id = CS8409_CYBORG, .name = "cyborg" },
|
||||||
|
{ .id = CS8409_DOLPHIN, .name = "dolphin" },
|
||||||
|
{ .id = CS8409_ODIN, .name = "odin" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hda_fixup cs8409_fixups[] = {
|
||||||
|
[CS8409_BULLSEYE] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = cs8409_cs42l42_pincfgs,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_FIXUPS,
|
||||||
|
},
|
||||||
|
[CS8409_WARLOCK] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = cs8409_cs42l42_pincfgs,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_FIXUPS,
|
||||||
|
},
|
||||||
|
[CS8409_WARLOCK_MLK] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = cs8409_cs42l42_pincfgs,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_FIXUPS,
|
||||||
|
},
|
||||||
|
[CS8409_WARLOCK_MLK_DUAL_MIC] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = cs8409_cs42l42_pincfgs,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_FIXUPS,
|
||||||
|
},
|
||||||
|
[CS8409_CYBORG] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = cs8409_cs42l42_pincfgs,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_FIXUPS,
|
||||||
|
},
|
||||||
|
[CS8409_FIXUPS] = {
|
||||||
|
.type = HDA_FIXUP_FUNC,
|
||||||
|
.v.func = cs8409_cs42l42_fixups,
|
||||||
|
},
|
||||||
|
[CS8409_DOLPHIN] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = dolphin_pincfgs,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_DOLPHIN_FIXUPS,
|
||||||
|
},
|
||||||
|
[CS8409_DOLPHIN_FIXUPS] = {
|
||||||
|
.type = HDA_FIXUP_FUNC,
|
||||||
|
.v.func = dolphin_fixups,
|
||||||
|
},
|
||||||
|
[CS8409_ODIN] = {
|
||||||
|
.type = HDA_FIXUP_PINS,
|
||||||
|
.v.pins = cs8409_cs42l42_pincfgs_no_dmic,
|
||||||
|
.chained = true,
|
||||||
|
.chain_id = CS8409_FIXUPS,
|
||||||
|
},
|
||||||
|
};
|
1484
patch_cs8409.c
Normal file
1484
patch_cs8409.c
Normal file
File diff suppressed because it is too large
Load diff
375
patch_cs8409.h
Normal file
375
patch_cs8409.h
Normal file
|
@ -0,0 +1,375 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Cirrus Logic, Inc. and
|
||||||
|
* Cirrus Logic International Semiconductor Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CS8409_PATCH_H
|
||||||
|
#define __CS8409_PATCH_H
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <sound/cs42l42.h>
|
||||||
|
#include <sound/hda_codec.h>
|
||||||
|
#include "hda_local.h"
|
||||||
|
#include "hda_auto_parser.h"
|
||||||
|
#include "hda_jack.h"
|
||||||
|
#include "hda_generic.h"
|
||||||
|
|
||||||
|
/* CS8409 Specific Definitions */
|
||||||
|
|
||||||
|
enum cs8409_pins {
|
||||||
|
CS8409_PIN_ROOT,
|
||||||
|
CS8409_PIN_AFG,
|
||||||
|
CS8409_PIN_ASP1_OUT_A,
|
||||||
|
CS8409_PIN_ASP1_OUT_B,
|
||||||
|
CS8409_PIN_ASP1_OUT_C,
|
||||||
|
CS8409_PIN_ASP1_OUT_D,
|
||||||
|
CS8409_PIN_ASP1_OUT_E,
|
||||||
|
CS8409_PIN_ASP1_OUT_F,
|
||||||
|
CS8409_PIN_ASP1_OUT_G,
|
||||||
|
CS8409_PIN_ASP1_OUT_H,
|
||||||
|
CS8409_PIN_ASP2_OUT_A,
|
||||||
|
CS8409_PIN_ASP2_OUT_B,
|
||||||
|
CS8409_PIN_ASP2_OUT_C,
|
||||||
|
CS8409_PIN_ASP2_OUT_D,
|
||||||
|
CS8409_PIN_ASP2_OUT_E,
|
||||||
|
CS8409_PIN_ASP2_OUT_F,
|
||||||
|
CS8409_PIN_ASP2_OUT_G,
|
||||||
|
CS8409_PIN_ASP2_OUT_H,
|
||||||
|
CS8409_PIN_ASP1_IN_A,
|
||||||
|
CS8409_PIN_ASP1_IN_B,
|
||||||
|
CS8409_PIN_ASP1_IN_C,
|
||||||
|
CS8409_PIN_ASP1_IN_D,
|
||||||
|
CS8409_PIN_ASP1_IN_E,
|
||||||
|
CS8409_PIN_ASP1_IN_F,
|
||||||
|
CS8409_PIN_ASP1_IN_G,
|
||||||
|
CS8409_PIN_ASP1_IN_H,
|
||||||
|
CS8409_PIN_ASP2_IN_A,
|
||||||
|
CS8409_PIN_ASP2_IN_B,
|
||||||
|
CS8409_PIN_ASP2_IN_C,
|
||||||
|
CS8409_PIN_ASP2_IN_D,
|
||||||
|
CS8409_PIN_ASP2_IN_E,
|
||||||
|
CS8409_PIN_ASP2_IN_F,
|
||||||
|
CS8409_PIN_ASP2_IN_G,
|
||||||
|
CS8409_PIN_ASP2_IN_H,
|
||||||
|
CS8409_PIN_DMIC1,
|
||||||
|
CS8409_PIN_DMIC2,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_A,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_B,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_C,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_D,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_E,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_F,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_G,
|
||||||
|
CS8409_PIN_ASP1_TRANSMITTER_H,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_A,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_B,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_C,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_D,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_E,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_F,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_G,
|
||||||
|
CS8409_PIN_ASP2_TRANSMITTER_H,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_A,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_B,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_C,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_D,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_E,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_F,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_G,
|
||||||
|
CS8409_PIN_ASP1_RECEIVER_H,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_A,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_B,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_C,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_D,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_E,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_F,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_G,
|
||||||
|
CS8409_PIN_ASP2_RECEIVER_H,
|
||||||
|
CS8409_PIN_DMIC1_IN,
|
||||||
|
CS8409_PIN_DMIC2_IN,
|
||||||
|
CS8409_PIN_BEEP_GEN,
|
||||||
|
CS8409_PIN_VENDOR_WIDGET
|
||||||
|
};
|
||||||
|
|
||||||
|
enum cs8409_coefficient_index_registers {
|
||||||
|
CS8409_DEV_CFG1,
|
||||||
|
CS8409_DEV_CFG2,
|
||||||
|
CS8409_DEV_CFG3,
|
||||||
|
CS8409_ASP1_CLK_CTRL1,
|
||||||
|
CS8409_ASP1_CLK_CTRL2,
|
||||||
|
CS8409_ASP1_CLK_CTRL3,
|
||||||
|
CS8409_ASP2_CLK_CTRL1,
|
||||||
|
CS8409_ASP2_CLK_CTRL2,
|
||||||
|
CS8409_ASP2_CLK_CTRL3,
|
||||||
|
CS8409_DMIC_CFG,
|
||||||
|
CS8409_BEEP_CFG,
|
||||||
|
ASP1_RX_NULL_INS_RMV,
|
||||||
|
ASP1_Rx_RATE1,
|
||||||
|
ASP1_Rx_RATE2,
|
||||||
|
ASP1_Tx_NULL_INS_RMV,
|
||||||
|
ASP1_Tx_RATE1,
|
||||||
|
ASP1_Tx_RATE2,
|
||||||
|
ASP2_Rx_NULL_INS_RMV,
|
||||||
|
ASP2_Rx_RATE1,
|
||||||
|
ASP2_Rx_RATE2,
|
||||||
|
ASP2_Tx_NULL_INS_RMV,
|
||||||
|
ASP2_Tx_RATE1,
|
||||||
|
ASP2_Tx_RATE2,
|
||||||
|
ASP1_SYNC_CTRL,
|
||||||
|
ASP2_SYNC_CTRL,
|
||||||
|
ASP1_A_TX_CTRL1,
|
||||||
|
ASP1_A_TX_CTRL2,
|
||||||
|
ASP1_B_TX_CTRL1,
|
||||||
|
ASP1_B_TX_CTRL2,
|
||||||
|
ASP1_C_TX_CTRL1,
|
||||||
|
ASP1_C_TX_CTRL2,
|
||||||
|
ASP1_D_TX_CTRL1,
|
||||||
|
ASP1_D_TX_CTRL2,
|
||||||
|
ASP1_E_TX_CTRL1,
|
||||||
|
ASP1_E_TX_CTRL2,
|
||||||
|
ASP1_F_TX_CTRL1,
|
||||||
|
ASP1_F_TX_CTRL2,
|
||||||
|
ASP1_G_TX_CTRL1,
|
||||||
|
ASP1_G_TX_CTRL2,
|
||||||
|
ASP1_H_TX_CTRL1,
|
||||||
|
ASP1_H_TX_CTRL2,
|
||||||
|
ASP2_A_TX_CTRL1,
|
||||||
|
ASP2_A_TX_CTRL2,
|
||||||
|
ASP2_B_TX_CTRL1,
|
||||||
|
ASP2_B_TX_CTRL2,
|
||||||
|
ASP2_C_TX_CTRL1,
|
||||||
|
ASP2_C_TX_CTRL2,
|
||||||
|
ASP2_D_TX_CTRL1,
|
||||||
|
ASP2_D_TX_CTRL2,
|
||||||
|
ASP2_E_TX_CTRL1,
|
||||||
|
ASP2_E_TX_CTRL2,
|
||||||
|
ASP2_F_TX_CTRL1,
|
||||||
|
ASP2_F_TX_CTRL2,
|
||||||
|
ASP2_G_TX_CTRL1,
|
||||||
|
ASP2_G_TX_CTRL2,
|
||||||
|
ASP2_H_TX_CTRL1,
|
||||||
|
ASP2_H_TX_CTRL2,
|
||||||
|
ASP1_A_RX_CTRL1,
|
||||||
|
ASP1_A_RX_CTRL2,
|
||||||
|
ASP1_B_RX_CTRL1,
|
||||||
|
ASP1_B_RX_CTRL2,
|
||||||
|
ASP1_C_RX_CTRL1,
|
||||||
|
ASP1_C_RX_CTRL2,
|
||||||
|
ASP1_D_RX_CTRL1,
|
||||||
|
ASP1_D_RX_CTRL2,
|
||||||
|
ASP1_E_RX_CTRL1,
|
||||||
|
ASP1_E_RX_CTRL2,
|
||||||
|
ASP1_F_RX_CTRL1,
|
||||||
|
ASP1_F_RX_CTRL2,
|
||||||
|
ASP1_G_RX_CTRL1,
|
||||||
|
ASP1_G_RX_CTRL2,
|
||||||
|
ASP1_H_RX_CTRL1,
|
||||||
|
ASP1_H_RX_CTRL2,
|
||||||
|
ASP2_A_RX_CTRL1,
|
||||||
|
ASP2_A_RX_CTRL2,
|
||||||
|
ASP2_B_RX_CTRL1,
|
||||||
|
ASP2_B_RX_CTRL2,
|
||||||
|
ASP2_C_RX_CTRL1,
|
||||||
|
ASP2_C_RX_CTRL2,
|
||||||
|
ASP2_D_RX_CTRL1,
|
||||||
|
ASP2_D_RX_CTRL2,
|
||||||
|
ASP2_E_RX_CTRL1,
|
||||||
|
ASP2_E_RX_CTRL2,
|
||||||
|
ASP2_F_RX_CTRL1,
|
||||||
|
ASP2_F_RX_CTRL2,
|
||||||
|
ASP2_G_RX_CTRL1,
|
||||||
|
ASP2_G_RX_CTRL2,
|
||||||
|
ASP2_H_RX_CTRL1,
|
||||||
|
ASP2_H_RX_CTRL2,
|
||||||
|
CS8409_I2C_ADDR,
|
||||||
|
CS8409_I2C_DATA,
|
||||||
|
CS8409_I2C_CTRL,
|
||||||
|
CS8409_I2C_STS,
|
||||||
|
CS8409_I2C_QWRITE,
|
||||||
|
CS8409_I2C_QREAD,
|
||||||
|
CS8409_SPI_CTRL,
|
||||||
|
CS8409_SPI_TX_DATA,
|
||||||
|
CS8409_SPI_RX_DATA,
|
||||||
|
CS8409_SPI_STS,
|
||||||
|
CS8409_PFE_COEF_W1, /* Parametric filter engine coefficient write 1*/
|
||||||
|
CS8409_PFE_COEF_W2,
|
||||||
|
CS8409_PFE_CTRL1,
|
||||||
|
CS8409_PFE_CTRL2,
|
||||||
|
CS8409_PRE_SCALE_ATTN1,
|
||||||
|
CS8409_PRE_SCALE_ATTN2,
|
||||||
|
CS8409_PFE_COEF_MON1, /* Parametric filter engine coefficient monitor 1*/
|
||||||
|
CS8409_PFE_COEF_MON2,
|
||||||
|
CS8409_ASP1_INTRN_STS,
|
||||||
|
CS8409_ASP2_INTRN_STS,
|
||||||
|
CS8409_ASP1_RX_SCLK_COUNT,
|
||||||
|
CS8409_ASP1_TX_SCLK_COUNT,
|
||||||
|
CS8409_ASP2_RX_SCLK_COUNT,
|
||||||
|
CS8409_ASP2_TX_SCLK_COUNT,
|
||||||
|
CS8409_ASP_UNS_RESP_MASK,
|
||||||
|
CS8409_LOOPBACK_CTRL = 0x80,
|
||||||
|
CS8409_PAD_CFG_SLW_RATE_CTRL = 0x82, /* Pad Config and Slew Rate Control (CIR = 0x0082) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* CS42L42 Specific Definitions */
|
||||||
|
|
||||||
|
#define CS8409_MAX_CODECS 8
|
||||||
|
#define CS42L42_VOLUMES (4U)
|
||||||
|
#define CS42L42_HP_VOL_REAL_MIN (-63)
|
||||||
|
#define CS42L42_HP_VOL_REAL_MAX (0)
|
||||||
|
#define CS42L42_AMIC_VOL_REAL_MIN (-97)
|
||||||
|
#define CS42L42_AMIC_VOL_REAL_MAX (12)
|
||||||
|
#define CS42L42_REG_AMIC_VOL_MASK (0x00FF)
|
||||||
|
#define CS42L42_HSTYPE_MASK (0x03)
|
||||||
|
#define CS42L42_I2C_TIMEOUT_US (20000)
|
||||||
|
#define CS42L42_I2C_SLEEP_US (2000)
|
||||||
|
#define CS42L42_PDN_TIMEOUT_US (250000)
|
||||||
|
#define CS42L42_PDN_SLEEP_US (2000)
|
||||||
|
#define CS42L42_ANA_MUTE_AB (0x0C)
|
||||||
|
#define CS42L42_FULL_SCALE_VOL_MASK (2)
|
||||||
|
#define CS42L42_FULL_SCALE_VOL_0DB (0)
|
||||||
|
#define CS42L42_FULL_SCALE_VOL_MINUS6DB (1)
|
||||||
|
|
||||||
|
/* Dell BULLSEYE / WARLOCK / CYBORG Specific Definitions */
|
||||||
|
|
||||||
|
#define CS42L42_I2C_ADDR (0x48 << 1)
|
||||||
|
#define CS8409_CS42L42_RESET GENMASK(5, 5) /* CS8409_GPIO5 */
|
||||||
|
#define CS8409_CS42L42_INT GENMASK(4, 4) /* CS8409_GPIO4 */
|
||||||
|
#define CS8409_CYBORG_SPEAKER_PDN GENMASK(2, 2) /* CS8409_GPIO2 */
|
||||||
|
#define CS8409_WARLOCK_SPEAKER_PDN GENMASK(1, 1) /* CS8409_GPIO1 */
|
||||||
|
#define CS8409_CS42L42_HP_PIN_NID CS8409_PIN_ASP1_TRANSMITTER_A
|
||||||
|
#define CS8409_CS42L42_SPK_PIN_NID CS8409_PIN_ASP2_TRANSMITTER_A
|
||||||
|
#define CS8409_CS42L42_AMIC_PIN_NID CS8409_PIN_ASP1_RECEIVER_A
|
||||||
|
#define CS8409_CS42L42_DMIC_PIN_NID CS8409_PIN_DMIC1_IN
|
||||||
|
#define CS8409_CS42L42_DMIC_ADC_PIN_NID CS8409_PIN_DMIC1
|
||||||
|
|
||||||
|
/* Dolphin */
|
||||||
|
|
||||||
|
#define DOLPHIN_C0_I2C_ADDR (0x48 << 1)
|
||||||
|
#define DOLPHIN_C1_I2C_ADDR (0x49 << 1)
|
||||||
|
#define DOLPHIN_HP_PIN_NID CS8409_PIN_ASP1_TRANSMITTER_A
|
||||||
|
#define DOLPHIN_LO_PIN_NID CS8409_PIN_ASP1_TRANSMITTER_B
|
||||||
|
#define DOLPHIN_AMIC_PIN_NID CS8409_PIN_ASP1_RECEIVER_A
|
||||||
|
|
||||||
|
#define DOLPHIN_C0_INT GENMASK(4, 4)
|
||||||
|
#define DOLPHIN_C1_INT GENMASK(0, 0)
|
||||||
|
#define DOLPHIN_C0_RESET GENMASK(5, 5)
|
||||||
|
#define DOLPHIN_C1_RESET GENMASK(1, 1)
|
||||||
|
#define DOLPHIN_WAKE (DOLPHIN_C0_INT | DOLPHIN_C1_INT)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CS8409_BULLSEYE,
|
||||||
|
CS8409_WARLOCK,
|
||||||
|
CS8409_WARLOCK_MLK,
|
||||||
|
CS8409_WARLOCK_MLK_DUAL_MIC,
|
||||||
|
CS8409_CYBORG,
|
||||||
|
CS8409_FIXUPS,
|
||||||
|
CS8409_DOLPHIN,
|
||||||
|
CS8409_DOLPHIN_FIXUPS,
|
||||||
|
CS8409_ODIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CS8409_CODEC0,
|
||||||
|
CS8409_CODEC1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CS42L42_VOL_ADC,
|
||||||
|
CS42L42_VOL_DAC,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CS42L42_ADC_VOL_OFFSET (CS42L42_VOL_ADC)
|
||||||
|
#define CS42L42_DAC_CH0_VOL_OFFSET (CS42L42_VOL_DAC)
|
||||||
|
#define CS42L42_DAC_CH1_VOL_OFFSET (CS42L42_VOL_DAC + 1)
|
||||||
|
|
||||||
|
struct cs8409_i2c_param {
|
||||||
|
unsigned int addr;
|
||||||
|
unsigned int value;
|
||||||
|
unsigned int delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cs8409_cir_param {
|
||||||
|
unsigned int nid;
|
||||||
|
unsigned int cir;
|
||||||
|
unsigned int coeff;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sub_codec {
|
||||||
|
struct hda_codec *codec;
|
||||||
|
unsigned int addr;
|
||||||
|
unsigned int reset_gpio;
|
||||||
|
unsigned int irq_mask;
|
||||||
|
const struct cs8409_i2c_param *init_seq;
|
||||||
|
unsigned int init_seq_num;
|
||||||
|
|
||||||
|
unsigned int hp_jack_in:1;
|
||||||
|
unsigned int mic_jack_in:1;
|
||||||
|
unsigned int suspended:1;
|
||||||
|
unsigned int paged:1;
|
||||||
|
unsigned int last_page;
|
||||||
|
unsigned int hsbias_hiz;
|
||||||
|
unsigned int full_scale_vol:1;
|
||||||
|
unsigned int no_type_dect:1;
|
||||||
|
|
||||||
|
s8 vol[CS42L42_VOLUMES];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cs8409_spec {
|
||||||
|
struct hda_gen_spec gen;
|
||||||
|
struct hda_codec *codec;
|
||||||
|
|
||||||
|
struct sub_codec *scodecs[CS8409_MAX_CODECS];
|
||||||
|
unsigned int num_scodecs;
|
||||||
|
|
||||||
|
unsigned int gpio_mask;
|
||||||
|
unsigned int gpio_dir;
|
||||||
|
unsigned int gpio_data;
|
||||||
|
|
||||||
|
int speaker_pdn_gpio;
|
||||||
|
|
||||||
|
struct mutex i2c_mux;
|
||||||
|
unsigned int i2c_clck_enabled;
|
||||||
|
unsigned int dev_addr;
|
||||||
|
struct delayed_work i2c_clk_work;
|
||||||
|
|
||||||
|
unsigned int playback_started:1;
|
||||||
|
unsigned int capture_started:1;
|
||||||
|
unsigned int init_done:1;
|
||||||
|
unsigned int build_ctrl_done:1;
|
||||||
|
|
||||||
|
/* verb exec op override */
|
||||||
|
int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
|
||||||
|
unsigned int *res);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
|
||||||
|
extern const struct snd_kcontrol_new cs42l42_adc_volume_mixer;
|
||||||
|
|
||||||
|
int cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo);
|
||||||
|
int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
|
||||||
|
int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
|
||||||
|
|
||||||
|
extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback;
|
||||||
|
extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture;
|
||||||
|
extern const struct hda_quirk cs8409_fixup_tbl[];
|
||||||
|
extern const struct hda_model_fixup cs8409_models[];
|
||||||
|
extern const struct hda_fixup cs8409_fixups[];
|
||||||
|
extern const struct hda_verb cs8409_cs42l42_init_verbs[];
|
||||||
|
extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[];
|
||||||
|
extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[];
|
||||||
|
extern struct sub_codec cs8409_cs42l42_codec;
|
||||||
|
|
||||||
|
extern const struct hda_verb dolphin_init_verbs[];
|
||||||
|
extern const struct cs8409_cir_param dolphin_hw_cfg[];
|
||||||
|
extern struct sub_codec dolphin_cs42l42_0;
|
||||||
|
extern struct sub_codec dolphin_cs42l42_1;
|
||||||
|
|
||||||
|
void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
|
||||||
|
void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue