Compare commits

...

No commits in common. "linux5.14" and "master" have entirely different histories.

15 changed files with 7661 additions and 4544 deletions

View file

@ -1,11 +1,10 @@
snd-hda-codec-cirrus-objs := patch_cirrus.o
obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
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"
#KBUILD_EXTRA_CFLAGS = "-DCONFIG_SND_DEBUG=1 -DMYSOUNDDEBUGFULL -DAPPLE_PINSENSE_FIXUP -DAPPLE_CODECS -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"
KBUILD_EXTRA_CFLAGS = "-DAPPLE_PINSENSE_FIXUP -DAPPLE_CODECS -DCONFIG_SND_HDA_RECONFIG=1 -Wno-unused-variable -Wno-unused-function"
ifdef KVER
KDIR := /lib/modules/$(KVER)
@ -20,5 +19,5 @@ clean:
install:
mkdir -p $(KDIR)/updates/
cp snd-hda-codec-cirrus.ko $(KDIR)/updates/
cp snd-hda-codec-cs8409.ko $(KDIR)/updates/
depmod -a

View file

@ -8,6 +8,8 @@
#ifndef __SOUND_HDA_AUTO_PARSER_H
#define __SOUND_HDA_AUTO_PARSER_H
#include "hda_local.h"
/*
* Helper for automatic pin configuration
*/
@ -35,6 +37,7 @@ struct auto_pin_cfg_item {
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;

View file

@ -9,6 +9,9 @@
#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 {
@ -183,7 +186,7 @@ struct hda_gen_spec {
struct automic_entry am_entry[MAX_AUTO_MIC_PINS];
/* for pin sensing */
/* current status; set in hda_geneic.c */
/* 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 */
@ -229,7 +232,6 @@ struct hda_gen_spec {
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 */
unsigned int obey_preferred_dacs:1; /* obey preferred_dacs assignment */
/* other internal flags */
unsigned int no_analog:1; /* digital I/O only */
@ -294,6 +296,9 @@ struct hda_gen_spec {
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 */
@ -324,7 +329,6 @@ 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);
void snd_hda_gen_reboot_notify(struct hda_codec *codec);
/* standard jack event callbacks */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
@ -335,9 +339,7 @@ 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);
#ifdef CONFIG_PM
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
#endif
unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state);
@ -350,5 +352,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
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 */

View file

@ -69,6 +69,7 @@ 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);

View file

@ -135,8 +135,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
#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_register(struct hda_codec *codec);
void snd_hda_codec_cleanup_for_unbind(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)
@ -293,6 +292,32 @@ struct hda_fixup {
} 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 */
@ -349,9 +374,10 @@ 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 snd_pci_quirk *quirk,
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,
@ -438,6 +464,15 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
#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
*/
@ -615,6 +650,8 @@ 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
*/
@ -701,7 +738,8 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
#ifdef CONFIG_SND_PROC_FS
void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
struct snd_info_buffer *buffer);
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
@ -709,6 +747,8 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
#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...) \

File diff suppressed because it is too large Load diff

3083
patch_cirrus_apple.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -1634,7 +1634,7 @@ static void setup_jack_pin_config(struct hda_codec *codec)
{
//int retval;
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
// this is likely some call of setPinConfigDefault
// 0x45 -> 0x23 (macbook pro) is the line in path - so why does it say its a mike??
@ -1753,7 +1753,7 @@ static void determine_speaker_id(struct hda_codec *codec)
// this is call AppleHDAFunctionGroup::setGPIOEnable in determineSpeakerID
if (codec->core.subsystem_id == 0x106b3900)
if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00)
{
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_MASK, 0x00000008); // 0x00171608
// snd_hda: gpio enable 1 0x08
@ -1771,13 +1771,13 @@ static void determine_speaker_id(struct hda_codec *codec)
retval = snd_hda_codec_read(codec, codec->core.afg, 0, AC_VERB_GET_GPIO_DATA, 0x00000000); // 0x001f1500
mycodec_info(codec, "command determine_speaker_id gpio data 0x%08x\n", retval);
mycodec_info(codec, "command determine_speaker_id gpio mask 0x8 data 0x%08x\n", retval);
snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_MASK, 0x0000000c); // 0x0017160c
retval = snd_hda_codec_read(codec, codec->core.afg, 0, AC_VERB_GET_GPIO_DATA, 0x00000000); // 0x001f1500
mycodec_info(codec, "command determine_speaker_id gpio data 0x%08x\n", retval);
mycodec_info(codec, "command determine_speaker_id gpio mask 0xc data 0x%08x\n", retval);
}
else
@ -1792,7 +1792,7 @@ static void determine_speaker_id(struct hda_codec *codec)
retval = snd_hda_codec_read(codec, codec->core.afg, 0, AC_VERB_GET_GPIO_DATA, 0x00000000); // 0x001f1500
mycodec_info(codec, "command determine_speaker_id gpio data 0x%08x\n", retval);
mycodec_info(codec, "command determine_speaker_id gpio mask 0x4 data 0x%08x\n", retval);
}
@ -2412,13 +2412,13 @@ static void cs42l83_mic_detect(struct hda_codec *codec)
mycodec_info(codec, "command cs42l83_mic_detect end\n");
}
static void cs42l83_tip_sense(struct hda_codec *codec)
static void cs42l83_tip_sense(struct hda_codec *codec, int invert)
{
int retval;
int newval1;
int newval2;
int newval;
int flag = 0;
//int invert = 0;
// likely in AppleHDAMikeyInternalCS8409::setupJackDetection
// - only 0x73 readMikey/writeMikey calls seen
@ -2431,14 +2431,19 @@ static void cs42l83_tip_sense(struct hda_codec *codec)
retval = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b73, 1); // snd_hda
newval1 = (retval & 0x1c);
// invert indicates inverted signal path for physical jack presence detect circuit
if (flag)
// following code translated from assembler
newval1 = (retval & 0x1c);
if (invert)
newval = (newval1 | 0xe0);
else
newval = (newval1 | 0xc0);
if (invert)
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b73, 0x00e0, 1); // snd_hda
else
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b73, 0x00c0, 1); // snd_hda
mycodec_info(codec, "command cs42l83_tip_sense end\n");

View file

@ -340,6 +340,8 @@ add_control(struct hda_gen_spec *spec, int type, const char *name,
knew->index = cidx;
if (get_amp_nid_(val))
knew->subdevice = HDA_SUBDEV_AMP_FLAG;
if (knew->access == 0)
knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
knew->private_value = val;
return knew;
}
@ -350,7 +352,11 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
const char *sfx, int cidx, unsigned long val)
{
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
int len;
len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
if (snd_BUG_ON(len >= sizeof(name)))
return -EINVAL;
if (!add_control(spec, type, name, cidx, val))
return -ENOMEM;
return 0;

View file

@ -75,7 +75,7 @@ static unsigned int hda_set_node_power_state_dbg(struct hda_codec *codec, hda_ni
}
}
else {
dev_info(hda_codec_dev(codec), "hda_set_node_power_state ERROR!! 0x%04x\n",state);
dev_info(hda_codec_dev(codec), "hda_set_node_power_state ERROR!! nid 0x%02x 0x%04x\n",nid, state);
}
if (dbgflg) mycodec_info(codec, "hda_set_node_power_state end power %d\n",state);
@ -118,15 +118,15 @@ static void hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, int fl
static inline unsigned int cs_8409_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
unsigned int retval;
snd_hda_codec_read(codec, spec->vendor_nid, 0,
snd_hda_codec_read(codec, CS8409_VENDOR_NID, 0,
AC_VERB_GET_COEF_INDEX, 0);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, idx);
retval = snd_hda_codec_read(codec, spec->vendor_nid, 0,
retval = snd_hda_codec_read(codec, CS8409_VENDOR_NID, 0,
AC_VERB_GET_PROC_COEF, 0);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, 0);
return retval;
}
@ -134,14 +134,14 @@ static inline unsigned int cs_8409_vendor_coef_get(struct hda_codec *codec, unsi
static inline void cs_8409_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
unsigned int coef)
{
struct cs_spec *spec = codec->spec;
snd_hda_codec_read(codec, spec->vendor_nid, 0,
struct cs8409_apple_spec *spec = codec->spec;
snd_hda_codec_read(codec, CS8409_VENDOR_NID, 0,
AC_VERB_GET_COEF_INDEX, 0);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, idx);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_PROC_COEF, coef);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, 0);
// appears to return 0
}
@ -150,16 +150,16 @@ static inline unsigned int cs_8409_vendor_coef_set_mask(struct hda_codec *codec,
unsigned int coef, unsigned int mask, unsigned int srcval, int srcidx)
{
// for the moment hackily add srcidx argument while debugging
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
unsigned int retval;
unsigned int mask_coef;
snd_hda_codec_read(codec, spec->vendor_nid, 0,
snd_hda_codec_read(codec, CS8409_VENDOR_NID, 0,
AC_VERB_GET_COEF_INDEX, 0);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, idx);
retval = snd_hda_codec_read(codec, spec->vendor_nid, 0,
retval = snd_hda_codec_read(codec, CS8409_VENDOR_NID, 0,
AC_VERB_GET_PROC_COEF, 0);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, idx);
mask_coef = (retval & ~mask) | coef;
if (srcval != 0)
@ -172,9 +172,9 @@ static inline unsigned int cs_8409_vendor_coef_set_mask(struct hda_codec *codec,
else
//if (mask != 0xffff)
myprintk_dbg("snd_hda_intel: cs_8409_vendor_coef_set_mask 0x%04x 0x%04x: 0x%04x (0x%04x 0x%04x 0x%04x) %d",idx,coef,mask_coef,retval,coef,mask,srcidx);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_PROC_COEF, mask_coef);
snd_hda_codec_write(codec, spec->vendor_nid, 0,
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0,
AC_VERB_SET_COEF_INDEX, 0);
// appears to return 0
// lets return the read value for checking
@ -569,7 +569,7 @@ void snd_hda_double_reset(struct hda_codec *codec)
static void clear_pins(struct hda_codec *codec)
{
//struct cs_spec *spec = codec->spec;
//struct cs8409_apple_spec *spec = codec->spec;
hda_nid_t nid;
mycodec_info(codec, "start clear_pins\n");
@ -585,7 +585,7 @@ static void clear_pins(struct hda_codec *codec)
static void read_coefs_all_loop(struct hda_codec *codec)
{
//struct cs_spec *spec = codec->spec;
//struct cs8409_apple_spec *spec = codec->spec;
int idx;
mycodec_info(codec, "start read_coefs_all\n");
for (idx = 0; idx < 130; idx++)
@ -612,6 +612,9 @@ struct hda_cvt_setup {
unsigned char dirty; /* setups should be cleared */
};
// we now setup our local cache data in the spec structure
// - cvt_setups is an opaque pointer type so we can see it here
// but we dont know how to access the data - except by re-defining hda_cvt_setup as above
/* get or create a cache entry for the given audio converter NID */
static struct hda_cvt_setup *
@ -620,8 +623,7 @@ get_hda_cvt_setup_8409(struct hda_codec *codec, hda_nid_t nid)
struct hda_cvt_setup *p;
int i;
for (i = 0; i < codec->cvt_setups.used; i++) {
p = snd_array_elem(&codec->cvt_setups, i);
snd_array_for_each(&codec->cvt_setups, i, p) {
if (p->nid == nid)
return p;
}
@ -631,9 +633,41 @@ get_hda_cvt_setup_8409(struct hda_codec *codec, hda_nid_t nid)
return p;
}
// so we actually need both versions - one using the hda_cvt_setup struct
// and one using our local hda_cvt_setup_apple struct
static struct hda_cvt_setup_apple *
get_hda_cvt_setup_apple_8409(struct hda_codec *codec, hda_nid_t nid)
{
struct cs8409_apple_spec *spec = codec->spec;
switch (nid)
{
case 0x02:
return &spec->nid_0x02;
case 0x03:
return &spec->nid_0x03;
case 0x0a:
return &spec->nid_0x0a;
case 0x22:
return &spec->nid_0x22;
case 0x23:
return &spec->nid_0x23;
case 0x1a:
return &spec->nid_0x1a;
default:
break;
}
codec_err(codec, "get_hda_cvt_setup_apple_8409: UNKNOWN NID!! 0x%02x\n", nid);
return NULL;
}
static void cs_8409_dump_stream_format(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_cvt_setup *p = NULL;
struct hda_cvt_setup_apple *p = NULL;
int i;
// use explicit search so we dont create one if doesnt exist
@ -645,34 +679,45 @@ static void cs_8409_dump_stream_format(struct hda_codec *codec, hda_nid_t nid)
}
if (p != NULL)
codec_dbg(codec, "cs_8409_dump_stream_format: NID=0x%x, cached values: stream=0x%x, channel=%d, format=0x%x\n", nid, p->stream_tag, p->channel_id, p->format_id);
mycodec_dbg(codec, "cs_8409_dump_stream_format: NID=0x%x, codec cached values: stream=0x%x, channel=%d, format=0x%x\n", nid, p->stream_tag, p->channel_id, p->format_id);
else
codec_dbg(codec, "cs_8409_dump_stream_format: NID=0x%x, cached values: NULL\n", nid);
mycodec_dbg(codec, "cs_8409_dump_stream_format: NID=0x%x, codec cached values: NULL\n", nid);
}
static void cs_8409_reset_stream_format(struct hda_codec *codec, hda_nid_t nid, int format, int doreset)
{
// note that this routine is currently not used
// this resets the cached stream format so that next
// stream setup will actually rewrite the stream format and stream id
// or if doreset set it will perform the stream update now
// also allow for only updating the stream format and not stream id
// problem - the get_hda_cvt_setup function is local to hda_codec - so need our own copy above
// NOTE we now save the stream format in our local cache as the hda_codec cache
// is cleared at end of the prepare stage and we want to store it more permanently
// really only the stream id is variable
struct hda_cvt_setup *p = NULL;
struct hda_cvt_setup_apple *papl = NULL;
u32 stream_tag_sv;
int channel_id_sv;
int format_id_sv;
p = get_hda_cvt_setup_8409(codec, nid);
// problem - the get_hda_cvt_setup function is local to hda_codec - so need our own copy above
stream_tag_sv = p->stream_tag;
channel_id_sv = p->channel_id;
format_id_sv = p->format_id;
papl = get_hda_cvt_setup_apple_8409(codec, nid);
stream_tag_sv = papl->stream_tag;
channel_id_sv = papl->channel_id;
format_id_sv = papl->format_id;
mycodec_info(codec, "cs_8409_reset_stream_format RESET for nid 0x%02x: 0x%08x id 0x%08x chan 0x%08x\n", nid, format_id_sv, stream_tag_sv, channel_id_sv);
// snd_hda_codec_setup_stream uses a caching system so only sends verbs when a change occurs
// we want to force a send here so need to clear the cached data
p = get_hda_cvt_setup_8409(codec, nid);
p->stream_tag = 0;
p->channel_id = 0;
if (format)
@ -688,6 +733,21 @@ static void cs_8409_reset_stream_format(struct hda_codec *codec, hda_nid_t nid,
// - we want to remove the Apple specific stream format/channel setup
// and just call snd_hda_setup_stream - but we need the actual stream format for this
// - hopefully getting from the hda_cvt_setup struct
// unfortunately this idea of storing in the hda_cvt_setup table turns out to be not useful
// as at end of snd_hda_codec_prepare it clears out (ie zeros) all unused/inactive cache entries
// so we have to store in a separate cache using our own copied definition for hda_cvt_setup
// hda_cvt_setup_apple
// the following 2 functions are used in the sync converter functions
// where apple essentially disables streaming (set stream id to 0) updates some vendor nid parameters
// then restores streaming
// so we store the stream info in a local variable copy and set it to the unused stream id ie stream id of 0
// then cs_8409_update_from_save_stream_format sets it back to what it was
// note that the format is unchanged for these operations
// the main reason for doing it this way is because of the caching used in snd_hda_codec_setup_stream
// - if we just sent the hda verbs then the cached data in snd_hda_codec_setup_stream
// would be inconsistent with the actual state of streaming on the nid
static void cs_8409_save_and_clear_stream_format(struct hda_codec *codec, hda_nid_t nid, struct hda_cvt_setup *savep)
{
@ -696,7 +756,7 @@ static void cs_8409_save_and_clear_stream_format(struct hda_codec *codec, hda_ni
int channel_id_sv;
int format_id_sv;
codec_dbg(codec, "cs_8409_save_and_clear_stream_format\n");
mycodec_dbg(codec, "cs_8409_save_and_clear_stream_format nid 0x%02x\n", nid);
// use this to save the stream format and clear the stream id and channel
@ -713,7 +773,7 @@ static void cs_8409_update_from_save_stream_format(struct hda_codec *codec, hda_
{
struct hda_cvt_setup *p = NULL;
codec_dbg(codec, "cs_8409_update_from_save_stream_format\n");
mycodec_dbg(codec, "cs_8409_update_from_save_stream_format nid 0x%02x\n", nid);
// so this will ensure the format is re-updated
@ -727,29 +787,52 @@ static void cs_8409_update_from_save_stream_format(struct hda_codec *codec, hda_
if (update_format_id)
p->format_id = 0;
mycodec_info(codec, "cs_8409_update_from_save_stream_format tag 0x%08x chnl 0x%08x fmt 0x%08x\n", savep->stream_tag, savep->channel_id, savep->format_id);
snd_hda_codec_setup_stream(codec, nid, savep->stream_tag, savep->channel_id, savep->format_id);
}
// so these are the crucial routines for setting our local cached copy of the stream info (in the spec structure)
// we use a different struct definition (hda_cvt_setup_apple) to keep the re-definition of hda_cvt_setup more local
// note that this stream info is only stored once per stream prepare function call
// and this routine always updates from that initial data
static void cs_8409_really_update_stream_format(struct hda_codec *codec, hda_nid_t nid, int update_format_id, int update_stream_id, unsigned int new_channel_id)
{
struct hda_cvt_setup *p = NULL;
u32 stream_tag_sv;
int channel_id_sv;
int format_id_sv;
struct hda_cvt_setup_apple *papl = NULL;
u32 stream_tag_sv = 0;
int channel_id_sv = 0;
int format_id_sv = 0;
codec_dbg(codec, "cs_8409_really_update_stream_format\n");
mycodec_dbg(codec, "cs_8409_really_update_stream_format nid 0x%02x updfmt %d updstrmid %d nchnlid %d\n", nid, update_format_id, update_stream_id, new_channel_id);
//dump_stack();
cs_8409_dump_stream_format(codec, nid);
// so here we take the cached format and save locally, clear out the cached values
// so here we take our local cached format and save locally, clear out the cached values
// then call snd_hda_codec_setup_stream with the cached values
// this will ensure we update the HDA with the stream format
// maybe now we should just update from our local stored version??
papl = get_hda_cvt_setup_apple_8409(codec, nid);
if (papl != NULL)
{
stream_tag_sv = papl->stream_tag;
channel_id_sv = papl->channel_id;
format_id_sv = papl->format_id;
}
else
{
codec_err(codec, "cs_8409_really_update_stream_format bad nid 0x%02x FAIL!!\n", nid);
return;
}
p = get_hda_cvt_setup_8409(codec, nid);
stream_tag_sv = p->stream_tag;
channel_id_sv = p->channel_id;
format_id_sv = p->format_id;
mycodec_info(codec, "cs_8409_really_update_stream_format cached tag 0x%08x chnl 0x%08x fmt 0x%08x\n", papl->stream_tag, papl->channel_id, papl->format_id);
if (update_stream_id)
{
@ -759,17 +842,30 @@ static void cs_8409_really_update_stream_format(struct hda_codec *codec, hda_nid
if (update_format_id)
p->format_id = 0;
mycodec_info(codec, "cs_8409_really_update_stream_format to update tag 0x%08x chnl 0x%08x fmt 0x%08x\n", p->stream_tag, p->channel_id, p->format_id);
if (update_stream_id == 2)
mycodec_info(codec, "cs_8409_really_update_stream_format new tag 0x%08x chnl 0x%08x fmt 0x%08x\n", stream_tag_sv, new_channel_id, format_id_sv);
else
mycodec_info(codec, "cs_8409_really_update_stream_format new tag 0x%08x chnl 0x%08x fmt 0x%08x\n", stream_tag_sv, channel_id_sv, format_id_sv);
cs_8409_dump_stream_format(codec, nid);
if (update_stream_id == 2)
snd_hda_codec_setup_stream(codec, nid, stream_tag_sv, new_channel_id, format_id_sv);
else
snd_hda_codec_setup_stream(codec, nid, stream_tag_sv, channel_id_sv, format_id_sv);
}
// remove function from compile so get error when building if use it
#if 0
static void cs_8409_setup_stream_format(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format)
{
struct hda_cvt_setup *p = NULL;
codec_dbg(codec, "cs_8409_setup_stream_format nid 0x%02x\n",nid);
// NOTE - this function should no longer be used
mycodec_dbg(codec, "cs_8409_setup_stream_format nid 0x%02x\n",nid);
cs_8409_dump_stream_format(codec, nid);
@ -785,6 +881,40 @@ static void cs_8409_setup_stream_format(struct hda_codec *codec, hda_nid_t nid,
p->channel_id = 0;
p->format_id = format;
cs_8409_dump_stream_format(codec, nid);
mycodec_dbg(codec, "end cs_8409_setup_stream_format\n");
}
#endif
static void cs_8409_store_stream_format(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format)
{
struct hda_cvt_setup_apple *papl = NULL;
mycodec_dbg(codec, "cs_8409_store_stream_format nid 0x%02x\n",nid);
cs_8409_dump_stream_format(codec, nid);
// this functions sets up our local cached stream save store
// NOTA BENE we do not do the update here - we are relying that this will be done by a call to
// cs_8409_really_update_stream_format now we have set the format correctly
papl = get_hda_cvt_setup_apple_8409(codec, nid);
if (papl != NULL)
{
// NOTA BENE - we do not set the channel id here - this will be done by cs_8409_really_update_stream_format
papl->stream_tag = stream_tag;
papl->channel_id = 0;
papl->format_id = format;
mycodec_info(codec, "cs_8409_store_stream_format cached tag 0x%08x chnl 0x%08x fmt 0x%08x\n", papl->stream_tag, papl->channel_id, papl->format_id);
}
else
codec_err(codec, "cs_8409_store_stream_format bad nid 0x%02x FAIL!!\n", nid);
mycodec_dbg(codec, "end cs_8409_store_stream_format\n");
}
@ -800,40 +930,40 @@ static void switch_input_src(struct hda_codec *codec)
struct hda_input_mux *imux = &spec->input_mux;
struct nid_path *path;
int i, c, nums;
codec_dbg(codec, "switch_input_src enter\n");
mycodec_dbg(codec, "switch_input_src enter\n");
nums = spec->num_adc_nids;
codec_dbg(codec, "switch_input_src num adc nids %d %d\n",nums,spec->dyn_adc_switch);
mycodec_dbg(codec, "switch_input_src num adc nids %d %d\n",nums,spec->dyn_adc_switch);
for (c = 0; c < nums; c++) {
codec_dbg(codec, "switch_input_src num_items %d\n",imux->num_items);
mycodec_dbg(codec, "switch_input_src num_items %d\n",imux->num_items);
for (i = 0; i < imux->num_items; i++) {
//path = get_input_path(codec, c, i);
path = snd_hda_get_path_from_idx(codec, spec->input_paths[i][c]);
if (path) {
int in;
bool active = path->active;
codec_dbg(codec, "switch_input_src path active %d\n",active);
mycodec_dbg(codec, "switch_input_src path active %d\n",active);
for (in = path->depth - 1; in >= 0; in--) {
hda_nid_t tnid = path->path[in];
codec_dbg(codec, "switch_input_src path nid %d: 0x%02x\n",in,tnid);
mycodec_dbg(codec, "switch_input_src path nid %d: 0x%02x\n",in,tnid);
}
if (path->active) {
codec_dbg(codec, "switch_input_src path nid 0x%02x deactivate\n",path->path[1]);
mycodec_dbg(codec, "switch_input_src path nid 0x%02x deactivate\n",path->path[1]);
snd_hda_activate_path(codec, path, false, false);
} else {
codec_dbg(codec, "switch_input_src path nid 0x%02x activate\n",path->path[1]);
mycodec_dbg(codec, "switch_input_src path nid 0x%02x activate\n",path->path[1]);
snd_hda_activate_path(codec, path, true, false);
}
}
else {
codec_dbg(codec, "switch_input_src path NULL\n");
mycodec_dbg(codec, "switch_input_src path NULL\n");
}
}
}
codec_dbg(codec, "switch_input_src exit\n");
mycodec_dbg(codec, "switch_input_src exit\n");
}
@ -929,6 +1059,8 @@ static void cs_8409_play_data_ssm3(struct hda_codec *codec)
// 14,3 0x106b3900
// imac subsystem ids
// 18,1 0x106b0e00
// 18,2 0x106b0f00
// 18,3 0x106b1000
// 19,1 0x106b1000
@ -940,12 +1072,12 @@ static int cs_8409_real_config(struct hda_codec *codec);
static int cs_8409_boot_setup(struct hda_codec *codec)
{
int err = 0;
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
// so it appears we break up the subsystem_id into 2 parts
// a codec vendor id (16 bits) and a subvendor id (8 bits) plus an assembly id
// so here the codec vendor is 0x106b, the subvendor id is 0x39 and the assembly id is 0x00
if (codec->core.subsystem_id == 0x106b3900 || codec->core.subsystem_id == 0x106b1000) {
if (codec->core.subsystem_id == 0x106b3900) {
if (spec->use_data) {
myprintk("snd_hda_intel: cs_8409_boot_setup pre cs_8409_data_config\n");
@ -969,6 +1101,13 @@ static int cs_8409_boot_setup(struct hda_codec *codec)
err = cs_8409_real_config(codec);
}
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
printk("snd_hda_intel: cs_8409_boot_setup pre data not implemented for subsystem id 0x%08x",codec->core.subsystem_id);
} else {
err = cs_8409_real_config(codec);
}
}
else {
printk("snd_hda_intel: UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
err = -1;
@ -979,8 +1118,9 @@ static int cs_8409_boot_setup(struct hda_codec *codec)
void cs_8409_play_setup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3900 || codec->core.subsystem_id == 0x106b1000) {
struct cs8409_apple_spec *spec = codec->spec;
myprintk_dbg("snd_hda_intel: cs_8409_play_setup\n");
if (codec->core.subsystem_id == 0x106b3900) {
if (spec->use_data) {
//cs_8409_unmute_data(codec);
//cs_8409_volup_data(codec);
@ -997,6 +1137,13 @@ void cs_8409_play_setup(struct hda_codec *codec)
cs_8409_play_real(codec);
}
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
printk("snd_hda_intel: cs_8409_play_setup data not implemented for subsystem id 0x%08x",codec->core.subsystem_id);
} else {
cs_8409_play_real(codec);
}
}
else {
printk("snd_hda_intel: UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
@ -1007,8 +1154,9 @@ void cs_8409_play_setup(struct hda_codec *codec)
void cs_8409_play_cleanup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3900 || codec->core.subsystem_id == 0x106b1000) {
struct cs8409_apple_spec *spec = codec->spec;
myprintk_dbg("snd_hda_intel: cs_8409_play_cleanup\n");
if (codec->core.subsystem_id == 0x106b3900) {
if (spec->use_data) {
cs_8409_playstop_data(codec);
} else {
@ -1023,6 +1171,13 @@ void cs_8409_play_cleanup(struct hda_codec *codec)
cs_8409_playstop_real(codec);
}
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
printk("snd_hda_intel: cs_8409_play_cleanup data not implemented for subsystem id 0x%08x",codec->core.subsystem_id);
} else {
cs_8409_playstop_real(codec);
}
}
else {
printk("snd_hda_intel: UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
@ -1035,9 +1190,9 @@ void cs_8409_play_cleanup(struct hda_codec *codec)
void cs_8409_capture_setup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600 || codec->core.subsystem_id == 0x106b3900
|| codec->core.subsystem_id == 0x106b1000) {
|| codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
//cs_8409_capture_data(codec);
} else {
@ -1053,9 +1208,9 @@ void cs_8409_capture_setup(struct hda_codec *codec)
void cs_8409_capture_cleanup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600 || codec->core.subsystem_id == 0x106b3900
|| codec->core.subsystem_id == 0x106b1000) {
|| codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
//cs_8409_capturestop_data(codec);
} else {
@ -1074,10 +1229,11 @@ static void cs_8409_cs42l83_unsolicited_response_finalize(struct hda_codec *code
static void cs_8409_perform_external_device_unsolicited_responses(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
struct unsol_item *unsol_entry = NULL;
struct unsol_item *unsol_temp = NULL;
mycodec_info(codec, "cs_8409_perform_external_device_unsolicited_responses UNSOL start\n");
if (!list_empty(&spec->unsol_list)) {
codec_info(codec, "cs_8409_perform_external_device_unsolicited_responses UNSOL start\n");
list_for_each_entry_safe(unsol_entry, unsol_temp, &spec->unsol_list, list)
{
list_del_init(&unsol_entry->list);
@ -1086,12 +1242,13 @@ static void cs_8409_perform_external_device_unsolicited_responses(struct hda_cod
spec->unsol_items_prealloc_used[unsol_entry->idx] = 0;
memset(unsol_entry, 0, sizeof(struct unsol_item));
}
mycodec_info(codec, "cs_8409_perform_external_device_unsolicited_responses UNSOL end\n");
codec_info(codec, "cs_8409_perform_external_device_unsolicited_responses UNSOL end\n");
}
}
static void cs_8409_cs42l83_unsolicited_response(struct hda_codec *codec, unsigned int res)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
// not clear if want to use the GPIO pins apparently passed in res to determine
// if want to do interrupt checking here and if no interrupts then to do
@ -1108,12 +1265,12 @@ static void cs_8409_cs42l83_unsolicited_response(struct hda_codec *codec, unsign
{
int itm;
int new_itm = -1;
mycodec_info(codec, "cs_8409_cs42l83_unsolicited_response - UNSOL BLOCKED\n");
codec_info(codec, "cs_8409_cs42l83_unsolicited_response - UNSOL BLOCKED\n");
for (itm=0; itm<10; itm++)
if (spec->unsol_items_prealloc_used[itm] == 0) { new_itm = itm; break; }
if (new_itm < 0)
{
mycodec_info(codec, "cs_8409_cs42l83_unsolicited_response - IGNORING UNSOL RESPONSE!!\n");
codec_info(codec, "cs_8409_cs42l83_unsolicited_response - IGNORING UNSOL RESPONSE!!\n");
return;
}
spec->unsol_items_prealloc_used[new_itm] = 1;
@ -1121,11 +1278,11 @@ static void cs_8409_cs42l83_unsolicited_response(struct hda_codec *codec, unsign
spec->unsol_items_prealloc[new_itm].res = res;
spec->unsol_items_prealloc[new_itm].idx = new_itm;
list_add_tail(&(spec->unsol_items_prealloc[new_itm].list), &spec->unsol_list);
mycodec_info(codec, "cs_8409_cs42l83_unsolicited_response - UNSOL response stored\n");
codec_info(codec, "cs_8409_cs42l83_unsolicited_response - UNSOL response stored\n");
return;
}
else
mycodec_info(codec, "cs_8409_cs42l83_unsolicited_response - NOT UNSOL BLOCKED\n");
codec_info(codec, "cs_8409_cs42l83_unsolicited_response - NOT UNSOL BLOCKED\n");
// so it appears we need to block unsol responses while doing unsol responses
// this is probably not the way to do this but still havent figured out how to use locking properly
@ -1148,7 +1305,7 @@ static void cs_8409_cs42l83_unsolicited_response(struct hda_codec *codec, unsign
static void cs_8409_cs42l83_unsolicited_response_finalize(struct hda_codec *codec, unsigned int res)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (spec->use_data)
cs_8409_external_device_unsolicited_response_data(codec, res);
@ -1170,7 +1327,7 @@ static void cs_8409_cs42l83_unsolicited_response_finalize(struct hda_codec *code
static void cs_8409_headset_mike_setup_nouse(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_intmike_linein_disable(codec);
@ -1181,8 +1338,8 @@ static void cs_8409_headset_mike_setup_nouse(struct hda_codec *codec)
void cs_8409_headplay_setup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3900 || codec->core.subsystem_id == 0x106b1000) {
struct cs8409_apple_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3900) {
if (spec->use_data) {
cs_8409_headplay_data(codec);
} else {
@ -1197,6 +1354,13 @@ void cs_8409_headplay_setup(struct hda_codec *codec)
cs_8409_headplay_real(codec);
}
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
printk("snd_hda_intel: cs_8409_headplay_setup data not implemented for subsystem id 0x%08x",codec->core.subsystem_id);
} else {
cs_8409_headplay_real(codec);
}
}
else {
printk("snd_hda_intel: UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
@ -1206,7 +1370,7 @@ void cs_8409_headplay_setup(struct hda_codec *codec)
//if (!list_empty(&spec->unsol_list))
//{
// mycodec_info(codec, "cs_8409_headplay_setup - performing UNSOL responses\n");
// codec_info(codec, "cs_8409_headplay_setup - performing UNSOL responses\n");
// cs_8409_perform_external_device_unsolicited_responses(codec);
//}
}
@ -1214,8 +1378,8 @@ void cs_8409_headplay_setup(struct hda_codec *codec)
void cs_8409_headplay_cleanup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3900 || codec->core.subsystem_id == 0x106b1000) {
struct cs8409_apple_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3900) {
if (spec->use_data) {
cs_8409_headplaystop_data(codec);
} else {
@ -1231,6 +1395,13 @@ void cs_8409_headplay_cleanup(struct hda_codec *codec)
cs_8409_headplaystop_real(codec);
}
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
printk("snd_hda_intel: cs_8409_headplay_cleanup data not implemented for subsystem id 0x%08x",codec->core.subsystem_id);
} else {
cs_8409_headplaystop_real(codec);
}
}
else {
printk("snd_hda_intel: UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
@ -1240,7 +1411,7 @@ void cs_8409_headplay_cleanup(struct hda_codec *codec)
//if (!list_empty(&spec->unsol_list))
//{
// mycodec_info(codec, "cs_8409_headplay_cleanup - performing UNSOL responses\n");
// codec_info(codec, "cs_8409_headplay_cleanup - performing UNSOL responses\n");
// cs_8409_perform_external_device_unsolicited_responses(codec);
//}
}
@ -1251,9 +1422,9 @@ void cs_8409_headplay_cleanup(struct hda_codec *codec)
void cs_8409_headcapture_setup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600 || codec->core.subsystem_id == 0x106b3900
|| codec->core.subsystem_id == 0x106b1000) {
|| codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
//cs_8409_headcapture_data(codec);
} else {
@ -1269,7 +1440,7 @@ void cs_8409_headcapture_setup(struct hda_codec *codec)
//if (!list_empty(&spec->unsol_list))
//{
// mycodec_info(codec, "cs_8409_headcapture_setup - performing UNSOL responses\n");
// codec_info(codec, "cs_8409_headcapture_setup - performing UNSOL responses\n");
// cs_8409_perform_external_device_unsolicited_responses(codec);
//}
}
@ -1277,9 +1448,9 @@ void cs_8409_headcapture_setup(struct hda_codec *codec)
void cs_8409_headcapture_cleanup(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600 || codec->core.subsystem_id == 0x106b3900
|| codec->core.subsystem_id == 0x106b1000) {
|| codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
if (spec->use_data) {
//cs_8409_capturestop_data(codec);
} else {
@ -1296,7 +1467,7 @@ void cs_8409_headcapture_cleanup(struct hda_codec *codec)
//if (!list_empty(&spec->unsol_list))
//{
// mycodec_info(codec, "cs_8409_headcapturestop_cleanup - performing UNSOL responses\n");
// codec_info(codec, "cs_8409_headcapturestop_cleanup - performing UNSOL responses\n");
// cs_8409_perform_external_device_unsolicited_responses(codec);
//}
}
@ -1306,15 +1477,19 @@ static void cs_8409_pcm_playback_pre_prepare_hook(struct hda_pcm_stream *hinfo,
unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream,
int action)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (action == HDA_GEN_PCM_ACT_PREPARE) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
struct timespec64 curtim;
ktime_get_real_ts64(&curtim);
myprintk("snd_hda_intel: command cs_8409_pcm_playback_pre_prepare_hook HOOK PREPARE init %d last %lld cur %lld",
spec->play_init,spec->last_play_time.tv_sec,curtim.tv_sec);
#else
struct timespec curtim;
getnstimeofday(&curtim);
#endif
myprintk("snd_hda_intel: command cs_8409_pcm_playback_pre_prepare_hook HOOK PREPARE init %d last %lld cur %lld",spec->play_init,spec->last_play_time.tv_sec,curtim.tv_sec);
if (1) {
struct hda_cvt_setup *p = NULL;
struct hda_cvt_setup_apple *p = NULL;
//int power_chk = 0;
// in the new way we set the stream up here using the passed data
@ -1322,11 +1497,17 @@ static void cs_8409_pcm_playback_pre_prepare_hook(struct hda_pcm_stream *hinfo,
// so the cs_8409_really_update_stream_format will cause the updates to occur
// note we explicitly set the channel id - dont see another way yet
cs_8409_setup_stream_format(codec, 0x02, stream_tag, format);
//cs_8409_setup_stream_format(codec, 0x02, stream_tag, format);
cs_8409_store_stream_format(codec, 0x02, stream_tag, format);
cs_8409_setup_stream_format(codec, 0x03, stream_tag, format);
//cs_8409_setup_stream_format(codec, 0x03, stream_tag, format);
cs_8409_store_stream_format(codec, 0x03, stream_tag, format);
cs_8409_setup_stream_format(codec, 0x0a, stream_tag, format);
//cs_8409_setup_stream_format(codec, 0x0a, stream_tag, format);
cs_8409_store_stream_format(codec, 0x0a, stream_tag, format);
// save number of actual stream channels
spec->stream_channels = substream->runtime->channels;
hda_check_power_state(codec, 0x1a, 1);
hda_check_power_state(codec, 0x3c, 1);
@ -1344,6 +1525,9 @@ static void cs_8409_pcm_playback_pre_prepare_hook(struct hda_pcm_stream *hinfo,
// first on Linux and we dont know at that stage if we will be playing
if (spec->have_mike)
{
// actually we always need to do cs_8409_headplay_setup - here we are about to play
// - what this possibly would allow is the apple way of doing a pre-setup
// so here we would switch between doing a full setup or a partial setup
if (spec->headset_play_format_setup_needed)
{
cs_8409_headplay_setup(codec);
@ -1361,9 +1545,10 @@ static void cs_8409_pcm_playback_pre_prepare_hook(struct hda_pcm_stream *hinfo,
cs_8409_headplay_setup(codec);
}
}
else
else {
cs_8409_play_setup(codec);
myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook setup play called");
}
myprintk("snd_hda_intel: command cs_8409_pcm_playback_pre_prepare_hook setup play called");
hda_check_power_state(codec, 0x1a, 2);
hda_check_power_state(codec, 0x3c, 2);
@ -1404,7 +1589,7 @@ static void cs_8409_pcm_playback_pre_prepare_hook(struct hda_pcm_stream *hinfo,
static void cs_8409_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream, int action)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
// so finally getting a handle on ordering here
// we need to do the OSX setup in the OPEN section
@ -1420,16 +1605,20 @@ static void cs_8409_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_c
if (action == HDA_GEN_PCM_ACT_OPEN) {
//struct hda_cvt_setup *p = NULL;
//struct hda_cvt_setup_apple *p = NULL;
myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook open");
myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook open end");
} else if (action == HDA_GEN_PCM_ACT_PREPARE) {
// so this comes AFTER the stream format, frequency setup verbs are sent for the pcm stream
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
struct timespec64 curtim;
ktime_get_real_ts64(&curtim);
myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook HOOK PREPARE init %d last %lld cur %lld",
spec->play_init,spec->last_play_time.tv_sec,curtim.tv_sec);
#else
struct timespec curtim;
getnstimeofday(&curtim);
#endif
myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook HOOK PREPARE init %d last %lld cur %lld",spec->play_init,spec->last_play_time.tv_sec,curtim.tv_sec);
//int power_chk = 0;
//power_chk = snd_hda_codec_read(codec, codec->core.afg, 0, AC_VERB_GET_POWER_STATE, 0);
//myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook power check 0x01 2 %d", power_chk);
@ -1438,7 +1627,7 @@ static void cs_8409_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_c
spec->block_unsol = 0;
if (!list_empty(&spec->unsol_list))
{
mycodec_info(codec, "cs_8409_playback_pcm_hook - performing UNSOL responses\n");
codec_info(codec, "cs_8409_playback_pcm_hook - performing UNSOL responses\n");
cs_8409_perform_external_device_unsolicited_responses(codec);
}
spec->playing = 1;
@ -1457,19 +1646,16 @@ static void cs_8409_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_c
// note that so far only the headphone chip seems to generate unsol responses usually
spec->block_unsol = 1;
// so dont think need to anything about capturing here
if (spec->headset_play_format_setup_needed == 0)
{
cs_8409_headplay_cleanup(codec);
spec->headset_play_format_setup_needed = 1;
}
}
else
cs_8409_play_cleanup(codec);
myprintk("snd_hda_intel: command cs_8409_playback_pcm_hook done play down");
spec->block_unsol = 0;
if (!list_empty(&spec->unsol_list))
{
mycodec_info(codec, "cs_8409_playback_pcm_hook - performing UNSOL responses\n");
codec_info(codec, "cs_8409_playback_pcm_hook - performing UNSOL responses\n");
cs_8409_perform_external_device_unsolicited_responses(codec);
}
// not sure of this position yet
@ -1489,7 +1675,7 @@ static void cs_8409_pcm_capture_pre_prepare_hook(struct hda_pcm_stream *hinfo, s
unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream,
int action)
{
struct cs_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = codec->spec;
if (action == HDA_GEN_PCM_ACT_PREPARE) {
myprintk("snd_hda_intel: command cs_8409_pcm_capture_pre_prepare_hook HOOK PREPARE init %d",spec->capture_init);
@ -1509,7 +1695,8 @@ static void cs_8409_pcm_capture_pre_prepare_hook(struct hda_pcm_stream *hinfo, s
// I think this is the same for intmike or headset mike
cs_8409_setup_stream_format(codec, hinfo->nid, stream_tag, format);
//cs_8409_setup_stream_format(codec, hinfo->nid, stream_tag, format);
cs_8409_store_stream_format(codec, hinfo->nid, stream_tag, format);
// for the moment have junky test here
@ -1549,13 +1736,46 @@ static void cs_8409_pcm_capture_pre_prepare_hook(struct hda_pcm_stream *hinfo, s
static void cs_8409_capture_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream, int action)
{
struct cs_spec *spec = codec->spec;
//struct cs8409_apple_spec *spec = codec->spec;
struct cs8409_apple_spec *spec = NULL;
myprintk_dbg("snd_hda_intel: command cs_8409_capture_pcm_hook HOOK init called");
//dump_stack();
myprintk_dbg("snd_hda_intel: command cs_8409_capture_pcm_hook HOOK init post stack");
// - so this seems to be the critical issue - this can apparently be called with a NULL codec!!!
// only thing to do seems to be to return!!
if (codec == NULL) {
struct hda_codec *badptr = NULL;
printk("snd_hda_intel: command cs_8409_capture_pcm_hook HOOK init - CODEC NULL");
// so if we are here it looks as tho we have been called from call_hp_automute
// - in which the codec is the 1st arg
badptr = (struct hda_codec *) hinfo;
spec = badptr->spec;
printk("snd_hda_intel: cs_8409_capture_pcm_hook - pcm_playback_hook %p", spec->gen.pcm_playback_hook);
printk("snd_hda_intel: cs_8409_capture_pcm_hook - pcm_capture_hook %p", spec->gen.pcm_capture_hook);
printk("snd_hda_intel: cs_8409_capture_pcm_hook - hp_automute_hook %p", spec->gen.hp_automute_hook);
printk("snd_hda_intel: cs_8409_capture_pcm_hook - line_automute_hook %p", spec->gen.line_automute_hook);
printk("snd_hda_intel: cs_8409_capture_pcm_hook - line_automute_hook %p", spec->gen.mic_autoswitch_hook);
printk("snd_hda_intel: command cs_8409_capture_pcm_hook HOOK init - CODEC NULL exit");
return;
}
else
myprintk_dbg("snd_hda_intel: command cs_8409_capture_pcm_hook HOOK init - CODEC NOT NULL");
//dump_stack();
spec = codec->spec;
// so now no setup is done here - we only check for unsolicited responses
// - we do do cleanup for the CLEANUP action
if (action == HDA_GEN_PCM_ACT_OPEN) {
//struct hda_cvt_setup *p = NULL;
//struct hda_cvt_setup_apple *p = NULL;
myprintk("snd_hda_intel: command cs_8409_capture_pcm_hook open");
myprintk("snd_hda_intel: command cs_8409_capture_pcm_hook open end");
@ -1567,7 +1787,7 @@ static void cs_8409_capture_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_co
spec->block_unsol = 0;
if (!list_empty(&spec->unsol_list))
{
mycodec_info(codec, "cs_8409_capture_pcm_hook - performing UNSOL responses\n");
codec_info(codec, "cs_8409_capture_pcm_hook - performing UNSOL responses\n");
cs_8409_perform_external_device_unsolicited_responses(codec);
}
spec->capturing = 1;
@ -1605,7 +1825,7 @@ static void cs_8409_capture_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_co
spec->block_unsol = 0;
if (!list_empty(&spec->unsol_list))
{
mycodec_info(codec, "cs_8409_capture_pcm_hook - performing UNSOL responses\n");
codec_info(codec, "cs_8409_capture_pcm_hook - performing UNSOL responses\n");
cs_8409_perform_external_device_unsolicited_responses(codec);
}
// not sure of this position yet
@ -1624,7 +1844,7 @@ static void cs_8409_capture_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_co
// this version runs all explicit commands as logged on OSX
static int cs_8409_data_config(struct hda_codec *codec)
{
//struct cs_spec *spec = codec->spec;
//struct cs8409_apple_spec *spec = codec->spec;
//hda_nid_t beep_nid = spec->beep_nid;
unsigned int tmpstate1 = -1;
@ -1656,7 +1876,7 @@ static int cs_8409_data_config(struct hda_codec *codec)
// this version runs the setup using functions based on the setup using the logged data
static int cs_8409_real_config(struct hda_codec *codec)
{
//struct cs_spec *spec = codec->spec;
//struct cs8409_apple_spec *spec = codec->spec;
//hda_nid_t beep_nid = spec->beep_nid;
unsigned int tmpstate1 = -1;

File diff suppressed because it is too large Load diff

View file

@ -546,6 +546,7 @@ static void cs42l83_power_hs_bias_off(struct hda_codec *codec)
static void cs42l83_enable_hsbias_auto_clamp_on(struct hda_codec *codec)
{
//int updval;
//int retval;
mycodec_i2c_local_info(codec, "cs42l83_enable_hsbias_auto_clamp_on\n");
@ -560,15 +561,22 @@ static void cs42l83_enable_hsbias_auto_clamp_on(struct hda_codec *codec)
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x7003
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7003 i2c data 0x0003
// explicit coding
cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, 0x0003, 1); // snd_hda
// bit coding
//updval = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
//updval &= 0x3f;
//cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, updval, 1); // snd_hda
}
static void cs42l83_enable_hsbias_auto_clamp_off(struct hda_codec *codec)
{
//int retval;
int updval;
int retval;
mycodec_i2c_local_info(codec, "cs42l83_enable_hsbias_auto_clamp_off\n");
@ -580,7 +588,45 @@ static void cs42l83_enable_hsbias_auto_clamp_off(struct hda_codec *codec)
// register 0x1b70 - HSBIAS Sense and Hi-Z Autocontrol
// changed from 0x03 to 0x03 (HS Sense Bias trip 52 microamps
// set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps)
// set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps (0x03 -> 0x06) )
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x7003
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7003 i2c data 0x0003
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7046 i2c data 0x0046
// explicit coding
//cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
//cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, 0x0003, 1); // snd_hda
//cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, 0x0046, 1); // snd_hda
// bit coding
retval = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
updval = retval & 0x3f;
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, updval, 1); // snd_hda
updval = (retval & 0xb8) | 0x46;
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, updval, 1); // snd_hda
}
static void cs42l83_enable_hsbias_auto_clamp_off0(struct hda_codec *codec)
{
//int retval;
mycodec_i2c_local_info(codec, "cs42l83_enable_hsbias_auto_clamp_off0\n");
// in AppleHDAMikeyInternalCS4208::handleTypeDetectUR
// in AppleHDAMikeyInternalCS8409::setupButtonDetection
// AppleHDAMikeyInternalCS8409::enableHSBIASautoclamp
// register 0x1b70 - HSBIAS Sense and Hi-Z Autocontrol
// changed from 0x03 to 0x03 (HS Sense Bias trip 52 microamps
// set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps (0x03 -> 0x06) )
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x7003
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7003 i2c data 0x0003
@ -702,7 +748,7 @@ static void cs42l83_enable_hsbias_auto_clamp_off1(struct hda_codec *codec)
// register 0x1b70 - HSBIAS Sense and Hi-Z Autocontrol
// changed from 0x46 to 0x06
// set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps)
// then set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps (0x06 -> 0x06) )
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x7046
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7006 i2c data 0x0006
@ -904,6 +950,7 @@ static void cs42l83_configure_int_mclk(struct hda_codec *codec)
static void cs42l83_headset_power_on_on_nouse(struct hda_codec *codec)
{
// this function replaced by cs42l83_power_onoff
mycodec_i2c_local_info(codec, "cs42l83_headset_power_on_on_nouse\n");
@ -1131,6 +1178,8 @@ static void cs42l83_headset_rcv_enable_on(struct hda_codec *codec)
{
int retval;
// this function has been replaced by cs42l83_buffers_onoff
mycodec_i2c_local_info(codec, "cs42l83_headset_rcv_enable_on\n");
// AppleHDATDM_CS42L83::enable
@ -1328,7 +1377,7 @@ static void cs42l83_enable_hsbias_auto_clamp_off3(struct hda_codec *codec)
// register 0x1b70 - HSBIAS Sense and Hi-Z Autocontrol
// changed from 0xc6 to 0x06
// set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps)
// then set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps (0x06 ->0x06) )
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x70c6
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7006 i2c data 0x0006
@ -1538,6 +1587,7 @@ static void cs42l83_power_off_codec_input(struct hda_codec *codec)
static void cs42l83_headset_rcv_enable_off(struct hda_codec *codec)
{
// this function has been replaced by cs42l83_buffers_onoff
mycodec_i2c_local_info(codec, "cs42l83_headset_rcv_enable_off\n");
@ -1557,6 +1607,7 @@ static void cs42l83_headset_rcv_enable_off(struct hda_codec *codec)
static void cs42l83_headset_power_off(struct hda_codec *codec)
{
// this function replaced by cs42l83_power_onoff
mycodec_i2c_local_info(codec, "cs42l83_headset_power_off\n");
@ -1847,7 +1898,7 @@ static void cs42l83_enable_hsbias_auto_clamp_off2(struct hda_codec *codec)
// register 0x1b70 - HSBIAS Sense and Hi-Z Autocontrol
// changed from 0x46 to 0x06
// set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps)
// then set to 0x46 (Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps (0x06 ->0x06) )
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x7046
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x7006 i2c data 0x0006
@ -1860,25 +1911,31 @@ static void cs42l83_enable_hsbias_auto_clamp_off2(struct hda_codec *codec)
}
static void cs42l83_enable_hsbias_auto_clamp_on3(struct hda_codec *codec)
static void cs42l83_hsbias_sense_on(struct hda_codec *codec)
{
int updval;
//int retval;
mycodec_i2c_local_info(codec, "cs42l83_enable_hsbias_auto_clamp_on3\n");
mycodec_i2c_local_info(codec, "cs42l83_hsbias_sense_on\n");
// in AppleHDAMikeyInternalCS8409::setupButtonDetection
// AppleHDAMikeyInternalCS8409::enableHSBIASautoclamp
// in AppleHDAMikeyInternalCS8409::handleButtonDetectUR
// register 0x1b70 - HSBIAS Sense and Hi-Z Autocontrol
// changed from 0x46 to 0xc6
// set to 0xc6 (HS Bias Sense Enable (0x80) Tip Sense Enable (0x40) HS Sense Bias trip 93 microamps (0x06 ->0x06) )
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7000 i2c data 0x7046
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x1b lo 0x70c6 i2c data 0x00c6
cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, 0x00c6, 1); // snd_hda
// explicit coding
//cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
//cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, 0x00c6, 1); // snd_hda
// bit coding
updval = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b70, 1); // snd_hda
updval |= 0x80;
cs_8409_vendor_i2cWrite(codec, 0x90, 0x1b70, updval, 1); // snd_hda
}

623
patch_cs8409-tables.c Normal file
View 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,
},
};

1503
patch_cs8409.c Normal file

File diff suppressed because it is too large Load diff

515
patch_cs8409.h Normal file
View file

@ -0,0 +1,515 @@
/* 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;
};
#ifdef APPLE_CODECS
struct unsol_item {
struct list_head list;
unsigned int idx;
unsigned int res;
};
struct hda_cvt_setup_apple {
hda_nid_t nid;
u8 stream_tag;
u8 channel_id;
u16 format_id;
unsigned char active; /* cvt is currently used */
unsigned char dirty; /* setups should be cleared */
};
#endif
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;
#ifdef APPLE_CODECS
unsigned int linein_jack_in:1;
#endif
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;
#ifdef APPLE_CODECS
// additional data for Apple 8409 system
unsigned int spdif_detect:1;
unsigned int spdif_present:1;
unsigned int sense_b:1;
hda_nid_t vendor_nid;
/* digital beep */
hda_nid_t beep_nid;
/* for MBP SPDIF control */
int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
// so it appears we have "concurrency" in the linux HDA code
// in that if unsolicited responses occur which perform extensive verbs
// the hda verbs are intermixed with eg extensive start playback verbs
// on OSX we appear to have blocks of verbs during which unsolicited responses
// are logged but the unsolicited verbs occur after the verb block
// this flag is used to flag such verb blocks and the list will store the
// responses
// we use a pre-allocated list - if we have more than 10 outstanding unsols
// we will drop
// not clear if mutexes would be the way to go
int block_unsol;
struct list_head unsol_list;
struct unsol_item unsol_items_prealloc[10];
int unsol_items_prealloc_used[10];
// add in specific nids for the intmike and linein as they seem to swap
// between macbook pros (14,3) and imacs (18,3)
int intmike_nid;
int linein_nid;
int intmike_adc_nid;
int linein_amp_nid;
// the following flag bits also need swapping
int reg9_intmike_dmic_mo;
int reg9_linein_dmic_mo;
int reg82_intmike_dmic_scl;
int reg82_linein_dmic_scl;
// add explicit stream format store entries as per hda_codec using a local definition
// of hda_cvt_setup (which is local to hda_codec.c)
// also use explicit nid versions
// (except that means either need explicit functions for each nid or have to lookup
// nid each time want to use in a generic function with nid argument)
struct hda_cvt_setup_apple nid_0x02;
struct hda_cvt_setup_apple nid_0x03;
struct hda_cvt_setup_apple nid_0x0a;
struct hda_cvt_setup_apple nid_0x22;
struct hda_cvt_setup_apple nid_0x23;
struct hda_cvt_setup_apple nid_0x1a;
// new item to deal with jack presence as Apple (and now Dell) seems to have barfed
// the HDA spec by using a separate headphone chip
int jack_present;
// save the type of headphone connected
int headset_type;
// if headphone has mike or not
int have_mike;
// if headphone has buttons or not
int have_buttons;
// current stream channel count
int stream_channels;
// set when playing for plug/unplug events while playing
int playing;
// set when capturing for plug/unplug events while capturing
int capturing;
// changing coding - OSX sets up the format on plugin
// then does some minimal setup when start play
// initial coding delayed any format setup till actually play
// this works for no mike but not for mike - we need to initialize
// the mike on plugin
// this flag will be set when we have done the format setup
// so know if need to do it on play or not
// now need 2 flags - one for play and one for capture
int headset_play_format_setup_needed;
int headset_capture_format_setup_needed;
int headset_presetup_done;
int use_data;
// this is new item for dealing with headset plugins
// so can distinguish which phase we are in if have multiple interrupts
// not really used now have analyzed interrupts properly
int headset_phase;
// another dirty hack item to manage the different headset enable codes
int headset_enable;
int play_init;
int capture_init;
// new item to limit times we redo unmute/play
struct timespec64 last_play_time;
// record the first play time - we have a problem there
// some initial plays that I dont understand - so skip any setup
// till sometime after the first play
struct timespec64 first_play_time;
#endif
/* 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