snd-hda-codec-cs8409/patch_cirrus_real84.h
Alexander Egorenkov 8315f6ad70 CS8409 TAS5764L support
Signed-off-by: Alexander Egorenkov <egorenar-dev@posteo.net>
2022-10-21 08:36:10 +02:00

5954 lines
270 KiB
C

static int tdm_in_use(struct hda_codec *codec, int where_flag)
{
int coef_ret = 0;
int coef_idx = 0;
// re-implementation of AppleHDATDMBusManagerCS8409::tdmInUse
mycodec_info(codec, "command tdmInUse start %d\n", where_flag);
// note on OSX the coef get functions returns a status value with read value stored in passed address
// on linux it seems -1 is an error return
coef_ret = cs_8409_vendor_coef_get(codec, 0x19);
//if (coef_ret == -1) error;
coef_idx = 0x1a;
do {
if ((short)coef_ret >= 0) {
mycodec_info(codec, "command tdmInUse 1 end %d\n", where_flag);
return 1;
}
coef_ret = cs_8409_vendor_coef_get(codec, coef_idx);
//if (coef_ret == -1) error;
coef_idx++;
} while (coef_idx <= 0x57);
mycodec_info(codec, "command tdmInUse 0 end %d\n", where_flag);
return 0;
}
static int cs42l83_headphone_sense(struct hda_codec *codec)
{
int retval = 0;
// AppleHDATDM_Codec::getHeadphonePinSense(bool*, unsigned int*)
// register 0x1b77 - Detect Status 1
// value 0x96 0x80 HP plugged bias 0x16
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7700 i2c data 0x7796
retval = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b77, 1); // snd_hda
mycodec_info(codec, "cs42l83_headphone_sense - 0x%04x\n", retval);
return retval;
}
static int read_gpio_status_check(struct hda_codec *codec)
{
int retval;
// should these be done powered down??
// lets check power state here
retval = snd_hda_codec_read(codec, codec->core.afg, 0, AC_VERB_GET_GPIO_DATA, 0x00000000); // 0x001f1500
mycodec_info(codec, "command read_gpio_status_check %x\n", retval);
return retval;
}
static void cs_8409_intmike_format_setup_format33_nouse(struct hda_codec *codec)
{
int retval;
int ret_coef9 = 0;
int new_coef9 = 0;
struct cs8409_apple_spec *spec = codec->spec;
// 0x44 -> 0x22 is internal (I think) mike input (macbook pro)
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x02224033
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x02224033
// snd_hda: stream format 34 [('CHAN', 4), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
}
static void cs_8409_intmike_format_setup_format_nouse(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x02224031
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x02224031
// snd_hda: stream format 34 [('CHAN', 2), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
}
static void cs_8409_intmike_format_setup_enable(struct hda_codec *codec, int hda_format, int powered_down)
{
int retval;
int ret_coef9 = 0;
int new_coef9 = 0;
struct cs8409_apple_spec *spec = codec->spec;
// 0x44 -> 0x22 is internal (I think) mike input (macbook pro)
// now updated to not write the Apple format but use my format setting routines
// (remember we have limited the allowed formats to acceptable ones)
// note that apparently we can set the format with the nid powered down but for setting the
// stream id the nid has to be powered up
// this seems to be used a lot in plugin/unplug headset in a powered down state
// - but when capturing no power changes done
// for some very strange reason we setup a 4 channel format after unplug of headset with mike
// - otherwise its 2 channel - pass the format to allow for this
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x02224033
// snd_hda: stream format 34 [('CHAN', 4), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_STREAM_FORMAT, hda_format); // 0x02224033
// now assuming have saved the stream info prior to calling this function
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10515); // 0x022f0500
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02270500
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 10518); // 0x022f0500
//if (powered_down) hda_set_node_power_state(codec, 0x22, AC_PWRST_D0);
if (powered_down) hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x02270610
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 1)]
// using the stored stream parameters update nid 0x22 stream parameters
// we have limited the allowed formats so should only have working formats here
//cs_8409_really_update_stream_format(codec, 0x22, 1, 1, 0);
cs_8409_really_update_stream_format(codec, spec->intmike_adc_nid, 1, 1, 0);
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02270503
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10521); // 0x022f0500
//if (powered_down) hda_set_node_power_state(codec, 0x22, AC_PWRST_D3);
if (powered_down) hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
// snd_hda: # AppleHDAWidgetCS8409::setConnectionSelect:
ret_coef9 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0009, 0x0000, 0x000000b3, 0 ); // AppleHDAWidgetCS8409::setConnectionSelect coef read 10523
//new_coef9 = (ret_coef9 | 0x20); // note most of the time it just seems to copy the value because bit 0x20 already set on input
// // only on boot does this get set
new_coef9 = (ret_coef9 | spec->reg9_intmike_dmic_mo); // note most of the time it just seems to copy the value because bit 0x20 already set on input
// only on boot does this get set
myprintk_dbg("snd_hda_intel: masked cs_8409_intmike_format_setup_enable coef 0x09 update 0x%04x 0x%04x \n", ret_coef9, new_coef9);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0009, 0x00b3, 0x00000000, 10527 ); // AppleHDAWidgetCS8409::setConnectionSelect coef write 10527
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0009, new_coef9, 0x00000000, 0 ); // AppleHDAWidgetCS8409::setConnectionSelect coef write 10527
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CONNECT_SEL, 0x00000000); // 0x02270100
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CONNECT_SEL, 0x00000000); // 0x02270100
}
static void cs_8409_volume_set(struct hda_codec *codec, hda_nid_t nid, int volume)
{
int retgain;
int newgain;
retgain = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000); // 0x022b2000
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x6000;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02236027
retgain = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000); // 0x022b0000
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x5000;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02235027
}
static void cs_8409_volume_mute(struct hda_codec *codec, hda_nid_t nid)
{
int retgain;
int newgain;
retgain = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000); // 0x022b2000
newgain = (retgain & 0x7f) | 0x80 | 0x6000;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02236000
retgain = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000); // 0x022b0000
newgain = (retgain & 0x7f) | 0x80 | 0x5000;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02235027
}
static void cs_8409_volume_unmute(struct hda_codec *codec, hda_nid_t nid)
{
int retgain;
int newgain;
retgain = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000); // 0x022b2000
newgain = (retgain & 0x7f) | 0x6000;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02236000
retgain = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000); // 0x022b0000
newgain = (retgain & 0x7f) | 0x5000;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02235027
}
static void cs_8409_intmike_volume_set(struct hda_codec *codec, int volume)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_set(codec, spec->intmike_adc_nid, volume);
}
static void cs_8409_linein_volume_set(struct hda_codec *codec, int volume)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_set(codec, spec->linein_amp_nid, volume);
}
static void cs_8409_intmike_volume_unmute(struct hda_codec *codec)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_unmute(codec, spec->intmike_adc_nid);
}
static void cs_8409_linein_volume_unmute(struct hda_codec *codec)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_unmute(codec, spec->linein_amp_nid);
}
static void cs_8409_intmike_volume_mute(struct hda_codec *codec)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_mute(codec, spec->intmike_adc_nid);
}
static void cs_8409_linein_volume_mute(struct hda_codec *codec)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_mute(codec, spec->linein_amp_nid);
}
static void cs_8409_intmike_volume_setup_new(struct hda_codec *codec, int volume)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_set(codec, spec->intmike_adc_nid, volume);
cs_8409_volume_mute(codec, spec->intmike_adc_nid);
cs_8409_volume_set(codec, spec->intmike_nid, 0x00);
}
static void cs_8409_linein_volume_setup_new(struct hda_codec *codec, int volume)
{
struct cs8409_apple_spec *spec = codec->spec;
cs_8409_volume_set(codec, spec->linein_amp_nid, volume);
cs_8409_volume_mute(codec, spec->linein_amp_nid);
cs_8409_volume_set(codec, spec->linein_nid, 0x00);
}
static void cs_8409_intmike_volume_setup(struct hda_codec *codec, int volume)
{
int retgain;
int newgain;
struct cs8409_apple_spec *spec = codec->spec;
// plausibly AppleHDAWidget::setWidgetAmplifierGain
//retgain = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000033, 0); // 0x022b2000
retgain = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000033, 0); // 0x022b2000
// snd_hda: amp gain/mute 34 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 34 0x0033 mute 0 gain 0x33 51
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x6000;
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02236027
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006027); // 0x02236027
// snd_hda: amp gain/mute 34 0x6027 mute 0 gain 0x27 39 index 0x00 left 1 right 0 output 0 input 1 left input
//retgain = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000033, 0); // 0x022b0000
retgain = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000033, 0); // 0x022b0000
// snd_hda: amp gain/mute 34 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 34 0x0033 mute 0 gain 0x33 51
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x5000;
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x02235027
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005027); // 0x02235027
// snd_hda: amp gain/mute 34 0x5027 mute 0 gain 0x27 39 index 0x00 left 0 right 1 output 0 input 1 right input
// mute
// plausibly AppleHDAWidget::setWidgetAmplifierMute
//retgain = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000027, 0); // 0x022b2000
retgain = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000027, 0); // 0x022b2000
// snd_hda: amp gain/mute 34 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 34 0x0027 mute 0 gain 0x27 39
newgain = (retgain & 0x7f) | 0x80 | 0x6000;
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x022360a7
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060a7); // 0x022360a7
// snd_hda: amp gain/mute 34 0x60a7 mute 1 gain 0x27 39 index 0x00 left 1 right 0 output 0 input 1 left input
//retgain = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000027, 0); // 0x022b0000
retgain = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000027, 0); // 0x022b0000
// snd_hda: amp gain/mute 34 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 34 0x0027 mute 0 gain 0x27 39
newgain = (retgain & 0x7f) | 0x80 | 0x5000;
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x022350a7
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050a7); // 0x022350a7
// snd_hda: amp gain/mute 34 0x50a7 mute 1 gain 0x27 39 index 0x00 left 0 right 1 output 0 input 1 right input
// this is working on node 0x44 macbook pro
// plausibly AppleHDAWidget::setWidgetAmplifierGain
//retgain = snd_hda_codec_read_check(codec, 0x44, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000000, 0); // 0x044b2000
retgain = snd_hda_codec_read_check(codec, spec->intmike_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000000, 0); // 0x044b2000
// snd_hda: amp gain/mute 68 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 68 0x0000 mute 0 gain 0x0 0
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x6000;
snd_hda_codec_write(codec, spec->intmike_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x04436000
//snd_hda_codec_write(codec, 0x44, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006000); // 0x04436000
// snd_hda: amp gain/mute 68 0x6000 mute 0 gain 0x0 0 index 0x00 left 1 right 0 output 0 input 1 left input
//retgain = snd_hda_codec_read_check(codec, 0x44, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000000, 0); // 0x044b0000
retgain = snd_hda_codec_read_check(codec, spec->intmike_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000000, 0); // 0x044b0000
// snd_hda: amp gain/mute 68 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 68 0x0000 mute 0 gain 0x0 0
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x5000;
snd_hda_codec_write(codec, spec->intmike_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x04435000
//snd_hda_codec_write(codec, 0x44, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005000); // 0x04435000
// snd_hda: amp gain/mute 68 0x5000 mute 0 gain 0x0 0 index 0x00 left 0 right 1 output 0 input 1 right input
}
static void cs_8409_linein_volume_setup(struct hda_codec *codec, int volume)
{
int retgain;
int newgain;
struct cs8409_apple_spec *spec = codec->spec;
// so as far as I can see the 1st section sets the gain and the second section sets the mute
// it appears we do masked updates
//volume = 0x27;
// plausibly AppleHDAWidget::setWidgetAmplifierGain
//retgain = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000b3, 0); // 0x023b2000
retgain = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000b3, 0); // 0x023b2000
// snd_hda: amp gain/mute 35 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 35 0x00b3 mute 1 gain 0x33 51
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x6000;
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060a7); // 0x023360a7
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060a7); // 0x023360a7
// snd_hda: amp gain/mute 35 0x60a7 mute 1 gain 0x27 39 index 0x00 left 1 right 0 output 0 input 1 left input
//retgain = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000b3, 0); // 0x023b0000
retgain = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000b3, 0); // 0x023b0000
// snd_hda: amp gain/mute 35 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 35 0x00b3 mute 1 gain 0x33 51
newgain = (retgain & 0x80) | (volume & 0x7f) | 0x5000;
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x023350a7
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050a7); // 0x023350a7
// snd_hda: amp gain/mute 35 0x50a7 mute 1 gain 0x27 39 index 0x00 left 0 right 1 output 0 input 1 right input
// mute
// plausibly AppleHDAWidget::setWidgetAmplifierMute
//retgain = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000a7, 0); // 0x023b2000
retgain = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000a7, 0); // 0x023b2000
// snd_hda: amp gain/mute 35 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 35 0x00a7 mute 1 gain 0x27 39
newgain = (retgain & 0x7f) | 0x80 | 0x6000;
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x023360a7
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060a7); // 0x023360a7
// snd_hda: amp gain/mute 35 0x60a7 mute 1 gain 0x27 39 index 0x00 left 1 right 0 output 0 input 1 left input
//retgain = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000a7, 0); // 0x023b0000
retgain = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000a7, 0); // 0x023b0000
// snd_hda: amp gain/mute 35 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 35 0x00a7 mute 1 gain 0x27 39
newgain = (retgain & 0x7f) | 0x80 | 0x5000;
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, newgain); // 0x023350a7
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050a7); // 0x023350a7
// snd_hda: amp gain/mute 35 0x50a7 mute 1 gain 0x27 39 index 0x00 left 0 right 1 output 0 input 1 right input
// this is working on node 0x45 macbook pro
// plausibly AppleHDAWidget::setWidgetAmplifierGain
//retgain = snd_hda_codec_read_check(codec, 0x45, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000000, 0); // 0x045b2000
retgain = snd_hda_codec_read_check(codec, spec->linein_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x00000000, 0); // 0x045b2000
// snd_hda: amp gain/mute 69 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 69 0x0000 mute 0 gain 0x0 0
snd_hda_codec_write(codec, spec->linein_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006000); // 0x04536000
//snd_hda_codec_write(codec, 0x45, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006000); // 0x04536000
// snd_hda: amp gain/mute 69 0x6000 mute 0 gain 0x0 0 index 0x00 left 1 right 0 output 0 input 1 left input
//retgain = snd_hda_codec_read_check(codec, 0x45, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000000, 0); // 0x045b0000
retgain = snd_hda_codec_read_check(codec, spec->linein_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x00000000, 0); // 0x045b0000
// snd_hda: amp gain/mute 69 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 69 0x0000 mute 0 gain 0x0 0
snd_hda_codec_write(codec, spec->linein_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005000); // 0x04535000
//snd_hda_codec_write(codec, 0x45, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005000); // 0x04535000
// snd_hda: amp gain/mute 69 0x5000 mute 0 gain 0x0 0 index 0x00 left 0 right 1 output 0 input 1 right input
}
static void cs_8409_intmike_stream_on_nid(struct hda_codec *codec)
{
int retval;
int reg_coef82 = 0;
int new_coef82 = 0;
struct cs8409_apple_spec *spec = codec->spec;
reg_coef82 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0082, 0x0000, 0x00005400, 0 ); // coef read 10544
//new_coef82 = (reg_coef82 | 0x1);
new_coef82 = (reg_coef82 | spec->reg82_intmike_dmic_scl);
myprintk_dbg("snd_hda_intel: masked cs_8409_intmike_stream_on_nid coef 0x0082 update 0x%04x 0x%04x \n", reg_coef82, new_coef82);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, 0x5401, 0x00000000, 10548 ); // coef write 10548
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, new_coef82, 0x00000000, 0 ); // coef write 10548
//retval = snd_hda_codec_read_check(codec, 0x44, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x044f0700
retval = snd_hda_codec_read_check(codec, spec->intmike_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x044f0700
snd_hda_codec_write(codec, spec->intmike_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x04470720
//snd_hda_codec_write(codec, 0x44, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x04470720
// snd_hda: 68 ['AC_PINCTL_IN_EN']
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x00170503
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D3);
}
static void cs_8409_intmike_format_setup_disable(struct hda_codec *codec)
{
int retval;
int reg_coef82 = 0;
int new_coef82 = 0;
struct cs8409_apple_spec *spec = codec->spec;
// set to defaults and disable input
// note here we really reset to 0 format in addition to stream id 0/channel id 0
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12217); // 0x022f0500
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02270500
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 12220); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02270503
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12223); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x02220000
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x02220000
// snd_hda: stream format 34 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
// AppleHDAWidgetCS8409::configurePinForIO(bool)??
reg_coef82 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0082, 0x0000, 0x0000a801, 0 ); // coef read 12226
//new_coef82 = (reg_coef82 & 0xfffffffe);
new_coef82 = (reg_coef82 & ~spec->reg82_intmike_dmic_scl);
myprintk_dbg("snd_hda_intel: masked cs_8409_intmike_format_setup_disable coef 0x0082 update 0x%04x 0x%04x \n", reg_coef82, new_coef82);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, 0xa800, 0x00000000, 12230 ); // coef write 12230
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, new_coef82, 0x00000000, 0 ); // coef write 12230
//retval = snd_hda_codec_read_check(codec, 0x44, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000020, 0); // 0x044f0700
retval = snd_hda_codec_read_check(codec, spec->intmike_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000020, 0); // 0x044f0700
snd_hda_codec_write(codec, spec->intmike_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x04470700
//snd_hda_codec_write(codec, 0x44, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x04470700
// snd_hda: 68 []
}
static void cs_8409_linein_format_setup_disable(struct hda_codec *codec)
{
int retval;
int reg_coef82 = 0;
int new_coef82 = 0;
struct cs8409_apple_spec *spec = codec->spec;
// 0x45 -> 0x23 is line input (macbook pro)
// set to defaults and disable input
// note here we really reset to 0 format in addition to stream id 0/channel id 0
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12248); // 0x023f0500
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02370500
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 12251); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
// snd_hda: conv stream channel map 35 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02370503
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12254); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D3);
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x02320000
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x02320000
// snd_hda: stream format 35 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
reg_coef82 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0082, 0x0000, 0x0000a800, 0 ); // coef read 12257
//new_coef82 = (reg_coef82 & 0xfffffffd);
new_coef82 = (reg_coef82 & ~spec->reg82_linein_dmic_scl);
myprintk_dbg("snd_hda_intel: masked cs_8409_linein_format_setup_disable coef 0x0082 update 0x%04x 0x%04x \n", reg_coef82, new_coef82);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, 0xa800, 0x00000000, 12261 ); // coef write 12261
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, new_coef82, 0x00000000, 0 ); // coef write 12261
//retval = snd_hda_codec_read_check(codec, 0x45, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x045f0700
retval = snd_hda_codec_read_check(codec, spec->linein_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x045f0700
snd_hda_codec_write(codec, spec->linein_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x04570700
//snd_hda_codec_write(codec, 0x45, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x04570700
// snd_hda: 69 []
}
static void cs_8409_intmike_stream_conn_off(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
// 0x44 -> 0x22 is internal (I think) mike input (macbook pro)
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x022f0600
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x022f0600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12160); // 0x022f0500
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02270500
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 12163); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02270503
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12166); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
// this seems to be updating the coef index associated with setConnectionSelect
// unable to figure where this is coming from currently
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0033, 0xffff, 0x00000033, 0, 12168 ); // coef write mask 12168
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0000, 0x0000, 0x00000033, 0x0033, 0 ); // coef write mask 12168
}
static void cs_8409_linein_stream_conn_off(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// Im thinking of a bugfix here to turn off bit 0x80 of index 0x0009
// 0x45 -> 0x23 is line input (macbook pro)
retval = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x023f0600
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x023f0600
// snd_hda: conv stream channel map 35 [('CHAN', 0), ('STREAMID', 0)]
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12175); // 0x023f0500
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02370500
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 12178); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
// snd_hda: conv stream channel map 35 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02370503
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12181); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D3);
// this seems to be updating the coef index associated with setConnectionSelect
// unable to figure where this is coming from currently
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0033, 0xffff, 0x00000033, 0, 12183 ); // coef write mask 12183
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0000, 0x0000, 0x00000033, 0x0033, 0 ); // coef write mask 12183
// possible correct mask to use
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0000, 0x0080, 0x00000033, 0, 0 ); // coef write mask 12183
}
static void cs_8409_intmike_stream_off_nid(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12189); // 0x022f0500
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02270500
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 12192); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02270503
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12195); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
}
static void cs_8409_linein_stream_off_nid(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12197); // 0x023f0500
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02370500
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 12200); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
// snd_hda: conv stream channel map 35 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02370503
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 12203); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D3);
}
static void cs_8409_intmike_volume_mute_nouse(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// nodes 0x44 is connected to 0x22 which is labelled mic input (macbook pro)
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x00170500
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000a7, 0); // 0x022b2000
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000a7, 0); // 0x022b2000
// snd_hda: amp gain/mute 34 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 34 0x00a7 mute 1 gain 0x27 39
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060b3); // 0x022360b3
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060b3); // 0x022360b3
// snd_hda: amp gain/mute 34 0x60b3 mute 1 gain 0x33 51 index 0x00 left 1 right 0 output 0 input 1 left input
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000a7, 0); // 0x022b0000
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000a7, 0); // 0x022b0000
// snd_hda: amp gain/mute 34 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 34 0x00a7 mute 1 gain 0x27 39
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050b3); // 0x022350b3
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050b3); // 0x022350b3
// snd_hda: amp gain/mute 34 0x50b3 mute 1 gain 0x33 51 index 0x00 left 0 right 1 output 0 input 1 right input
}
static void cs_8409_linein_volume_mute_nouse(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// nodes 0x45 which are connected to 0x23 is labelled as line input (macbook pro)
retval = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000a7, 0); // 0x023b2000
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000a7, 0); // 0x023b2000
// snd_hda: amp gain/mute 35 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 35 0x00a7 mute 1 gain 0x27 39
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060b3); // 0x023360b3
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000060b3); // 0x023360b3
// snd_hda: amp gain/mute 35 0x60b3 mute 1 gain 0x33 51 index 0x00 left 1 right 0 output 0 input 1 left input
retval = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000a7, 0); // 0x023b0000
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000a7, 0); // 0x023b0000
// snd_hda: amp gain/mute 35 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 35 0x00a7 mute 1 gain 0x27 39
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050b3); // 0x023350b3
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x000050b3); // 0x023350b3
// snd_hda: amp gain/mute 35 0x50b3 mute 1 gain 0x33 51 index 0x00 left 0 right 1 output 0 input 1 right input
}
static void cs_8409_intmike_volume_unmute_nouse(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// nodes 0x44 is connected to 0x22 which is labelled mic input (macbook pro)
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000b3, 0); // 0x022b2000
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000b3, 0); // 0x022b2000
// snd_hda: amp gain/mute 34 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 34 0x00b3 mute 1 gain 0x33 51
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006033); // 0x02236033
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006033); // 0x02236033
// snd_hda: amp gain/mute 34 0x6033 mute 0 gain 0x33 51 index 0x00 left 1 right 0 output 0 input 1 left input
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000b3, 0); // 0x022b0000
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000b3, 0); // 0x022b0000
// snd_hda: amp gain/mute 34 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 34 0x00b3 mute 1 gain 0x33 51
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005033); // 0x02235033
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005033); // 0x02235033
// snd_hda: amp gain/mute 34 0x5033 mute 0 gain 0x33 51 index 0x00 left 0 right 1 output 0 input 1 right input
}
static void cs_8409_linein_volume_unmute_nouse(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// nodes 0x45 which are connected to 0x23 is labelled as line input (macbook pro)
retval = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000b3, 0); // 0x023b2000
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00002000, 0x000000b3, 0); // 0x023b2000
// snd_hda: amp gain/mute 35 0x2000 index 0x00 left/right 1 left output/input 0 input
// snd_hda: amp gain/mute 35 0x00b3 mute 1 gain 0x33 51
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006033); // 0x02336033
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00006033); // 0x02336033
// snd_hda: amp gain/mute 35 0x6033 mute 0 gain 0x33 51 index 0x00 left 1 right 0 output 0 input 1 left input
retval = snd_hda_codec_read_check(codec, spec->linein_amp_nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000b3, 0); // 0x023b0000
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_AMP_GAIN_MUTE, 0x00000000, 0x000000b3, 0); // 0x023b0000
// snd_hda: amp gain/mute 35 0x0000 index 0x00 left/right 0 right output/input 0 input
// snd_hda: amp gain/mute 35 0x00b3 mute 1 gain 0x33 51
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005033); // 0x02335033
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x00005033); // 0x02335033
// snd_hda: amp gain/mute 35 0x5033 mute 0 gain 0x33 51 index 0x00 left 0 right 1 output 0 input 1 right input
}
static void cs_8409_setup_TDM_sample_rate(struct hda_codec *codec)
{
// codes from windows cs4208_38.inf file
// 0x0001 undocumented (0x0066 = ASP1/2_EN = 1, ASP1/2_STP = 1 ie ASP1_EN = 0x40, ASP2_EN = 0x20, ASP1_STP = 0x4, ASP2_STP = 0x2)
// 0x0005 0x0001 SCDIV 1:4 (0x005a = ASP1: MCEN = 0, FSD = 010 (0x40), SCPOL_IN/OUT = 1 (0x10), SCDIV = 1:4 ie 0x0-0xf)
// 0x0004 0x08ff SC_SRCSEL? = PLL1, LCPR = 0xff (0x28FF = (ASP1: MC/SC_SRCSEL = PLL1, LCPR = FFh), 0x2801 = (ASP1: MC/SC_SRCSEL = PLL1, LCPR = 01h))
// snd_hda: # AppleHDATDMBusManagerCS8409::setSampleRate:
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0001, 0x0200, 0xffff, 0x00000200, 0, 25 ); // coef write mask 25
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0005, 0x0001, 0xffff, 0x00000001, 0, 31 ); // coef write mask 31
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0004, 0x08ff, 0xffff, 0x000008ff, 0, 37 ); // coef write mask 37
// we need to use proper masked versions here - in particular for register 1 which seems to be some form of enable control
// for the subsystems and bits 0x7f need to pass thro here
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0001, 0x0200, 0x0380, 0x00000200, 0, 0 ); // coef write mask 25
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0005, 0x0001, 0x0007, 0x00000001, 0, 0 ); // coef write mask 31
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0004, 0x08ff, 0x01ff, 0x000008ff, 0, 0 ); // coef write mask 37
}
static void cs_8409_setup_TDM_proper_amps12(struct hda_codec *codec)
{
int ret_coef0 = 0;
int new_coef0 = 0;
int ret_coef1 = 0;
int new_coef1 = 0;
int ret_coef71 = 0;
int new_coef71 = 0;
// codes from windows cs4208_38.inf file
// 0x0019 0x0800 = (ASP1.A: TX.LAP = 0, TX.LSZ = 24 bits, TX.LCS = 0)
// 0x001a 0x0820 = (ASP1.A: TX.RAP = 0, TX.RSZ = 24 bits, TX.RCS = 32)
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 44
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0019, 0x0800, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 48
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001a, 0x0000, 0x00008820, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 52
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x001a, 0x0820, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 56
// codes from windows cs4208_38.inf file
// 0x0000 0xb000 = PLL2_EN (0x2000) PLL1_EN (0x1000) I2C disabled
// 0x0004 0x08ff SC_SRCSEL? = PLL1, LCPR = 0xff (0x28FF = (ASP1: MC/SC_SRCSEL = PLL1, LCPR = FFh), 0x2801 = (ASP1: MC/SC_SRCSEL = PLL1, LCPR = 01h))
// 0x0000 0x9000 = PLL1_EN (0x1000) I2C disabled
ret_coef0 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0000, 0x0000, 0x00009000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 60
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, 0xb000, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 64
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0004, 0x0000, 0x000008ff, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 68
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0004, 0x08ff, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 72
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, 0x9000, 0x00000000, 76 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 76
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, 0xb000, 0x00000000, 76 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 76
// it seems we re-write what we read just above here - if never plugin headphones its 0x9000
// after headphone plugin its 0xb0000 - even after unplugging headphones!!
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, ret_coef0, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 76
// codes from windows cs4208_38.inf file
// 0x0003 0x8000 = (ASP1: LCHI = 00h)
// 0x0005 0x0001 = SCDIV = 1:4 (0x005A = (ASP1: MCEN = 0, FSD = 010 (0x40), SCPOL_IN/OUT = 1 (0x10), SCDIV = 1:4))
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0003, 0x8000, 0xffff, 0x00008000, 0, 0 ); // coef write mask 80
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0005, 0x0001, 0xffff, 0x00000001, 0, 0 ); // coef write mask 86
// codes from windows cs4208_38.inf file
// 0x0082 0x5401 = ASP1_xxx_EN (0x4000) ASP1_xxx_EN (0x1000) ASP1_xxx_EN (0x400) DMIC1_SCL_EN = 1 (0xFC01 = (ASP1/2_xxx_EN = 1, ASP1/2_MCLK_EN = 0, DMIC1_SCL_EN = 1))
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x5401, 0xffff, 0x00000001, 0, 92 ); // coef write mask 92
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x5400, 0x0000, 0x00000001, 0x5401, 0 ); // coef write mask 92
// codes from windows cs4208_38.inf file
// 0x0002 0x0280 = ASP2_BUS_IDLE (0x02) GPIO_I2C (0x0A80 = (ASP1/2_BUS_IDLE = 10, +GPIO_I2C))
// no evidence this is anything other than 0x0280 yet
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0002, 0x0280, 0xffff, 0x00000280, 0, 0 ); // coef write mask 98
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000200, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 104
new_coef1 = (ret_coef1 & 0xffff) | 0x20;
myprintk_dbg("snd_hda_intel: masked cs_8409_setup_TDM_proper_amps12 coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0220, 0x00000000, 108 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 108
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 108
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00000800, 112 ); // coef read 112
tdm_in_use(codec, 1);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006b, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 117
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 121
new_coef71 = (ret_coef71 & 0xffff) | 0x400f;
myprintk_dbg("snd_hda_intel: masked cs_8409_setup_TDM_proper_amps12 coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x400f, 0x00000000, 125 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 125
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, new_coef71, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 125
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 128
}
static void cs_8409_setup_TDM_amps12(struct hda_codec *codec, int setrate, int nullformat)
{
int retval;
int ret_coef1 = 0;
int new_coef1 = 0;
// this seems to be setup for node 0x02 chain - which seems to use node 0x24 and amps 0x64 and 0x62 (or 0x28 0x2a)
//snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x00224033
// snd_hda: stream format 2 [('CHAN', 4), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x00270610
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 1)]
if (nullformat)
{
// note that 0x4033 is Apples fixed format - but this is for boot stage when we have
// not defined any format yet so just use it - we overwrite below when actually play
snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x00224033
snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00270600
}
else
{
// using the stored stream parameters update nid 0x2 stream parameters
// we have limited the allowed formats so should only have working formats here
cs_8409_really_update_stream_format(codec, 0x02, 1, 2, 0);
}
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000200, 0 ); // coef read 16
new_coef1 = (ret_coef1 & 0xffff); // not clear what this is setting - no difference between read and write
// however if used in different places the actual value may be different
myprintk_dbg("snd_hda_intel: masked cs_8409_setup_TDM_amps12 coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0200, 0x00000000, 20 ); // coef write 20
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 0 ); // coef write 20
if (setrate)
cs_8409_setup_TDM_sample_rate(codec);
cs_8409_setup_TDM_proper_amps12(codec);
// enable output node 0x24
//retval = snd_hda_codec_read_check(codec, 0x24, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 132); // 0x024f0700
retval = snd_hda_codec_read(codec, 0x24, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000); // 0x024f0700
snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000040); // 0x02470740
// snd_hda: 36 ['AC_PINCTL_OUT_EN']
}
static void play_setup_TDM_amps12(struct hda_codec *codec, int setrate)
{
cs_8409_setup_TDM_amps12(codec, setrate, 0);
}
static void cs_8409_setup_amp_max(struct hda_codec *codec, int amp_address, int amp_volume, int channel);
static void cs_8409_setup_amp_ssm3(struct hda_codec *codec, int amp_address, int amp_volume, int channel);
static void cs_8409_setup_amp_tas576(struct hda_codec *codec, int amp_address, int amp_volume, int channel, int amp_enable);
static void cs_8409_setup_amp_tas576_amp0(struct hda_codec *codec, int amp_volume, int amp_enable);
static void cs_8409_setup_amp_tas576_amp1(struct hda_codec *codec, int amp_volume, int amp_enable);
static void cs_8409_setup_amp_tas576_amp2(struct hda_codec *codec, int amp_volume, int amp_enable);
static void cs_8409_setup_amp_tas576_amp3(struct hda_codec *codec, int amp_volume, int amp_enable);
static void cs_8409_setup_amps12(struct hda_codec *codec, int amps_enable)
{
if (codec->core.subsystem_id == 0x106b3900) {
// use reduced volume - from 0x01 to 0x30 - now passing as argument
// change channel mapping - make a standard left/right pair
// so 1st 2 channels are tweeters, 2nd 2 channels are woofers
cs_8409_setup_amp_max(codec, 0x64, 0x01, 0x00);
cs_8409_setup_amp_max(codec, 0x62, 0x01, 0x02);
// use reduced volume - from 0x01 to 0x30 - now passing as argument
//cs_8409_setup_amp_max(codec, 0x64, 0x30, 0x00);
//cs_8409_setup_amp_max(codec, 0x62, 0x30, 0x02);
// original mapping:
//cs_8409_setup_amp_max(codec, 0x64, 0x30, 0x00);
//cs_8409_setup_amp_max(codec, 0x62, 0x30, 0x01);
//cs_8409_setup_amp_max(codec, 0x64, 0x01, 0x00);
//cs_8409_setup_amp_max(codec, 0x62, 0x01, 0x01);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
//setup_node_alpha_ssm3(codec);
// use reduced volume - from 0x01 to 0x30 - now passing as argument
// change channel mapping - make a standard left/right pair
// so 1st 2 channels are tweeters, 2nd 2 channels are woofers
cs_8409_setup_amp_ssm3(codec, 0x28, 0x48, 0x00);
cs_8409_setup_amp_ssm3(codec, 0x2a, 0x48, 0x02);
// use reduced volume - from 0x48 to 0x80 - same reduction as for MAXs -24dB
//cs_8409_setup_amp_ssm3(codec, 0x28, 0x80, 0x00);
//cs_8409_setup_amp_ssm3(codec, 0x2a, 0x80, 0x02);
// original mapping:
//cs_8409_setup_amp_ssm3(codec, 0x28, 0x80, 0x00);
//cs_8409_setup_amp_ssm3(codec, 0x2a, 0x80, 0x01);
//cs_8409_setup_amp_ssm3(codec, 0x28, 0x48, 0x00);
//cs_8409_setup_amp_ssm3(codec, 0x2a, 0x48, 0x01);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
// NOTE that the TAS57642 amps setup during boot seems to skip the actual speaker power on
// hence the addition of the amps_enable parameter
// use reduced volume - from 0xcf to 0x9f - same reduction as for MAXs -24dB (0.5dB steps)
// change channel mapping - make a standard left/right pair
// so 1st 2 channels are tweeters, 2nd 2 channels are woofers
cs_8409_setup_amp_tas576(codec, 0xd8, 0xcf, 0x00, amps_enable);
cs_8409_setup_amp_tas576(codec, 0xda, 0xcf, 0x02, amps_enable);
// use reduced volume - from 0xcf to 0x9f - same reduction as for MAXs -24dB (0.5dB steps)
//cs_8409_setup_amp_tas576(codec, 0xd8, 0x9f, 0x00, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xda, 0x9f, 0x02, amps_enable);
// original mapping:
//cs_8409_setup_amp_tas576(codec, 0xd8, 0x9f, 0x00, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xda, 0x9f, 0x01, amps_enable);
//cs_8409_setup_amp_tas576_amp0(codec, 0x9f, amps_enable);
//cs_8409_setup_amp_tas576_amp1(codec, 0x9f, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xd8, 0xcf, 0x00, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xda, 0xcf, 0x01, amps_enable);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
}
static void play_setup_amps12(struct hda_codec *codec)
{
cs_8409_setup_amps12(codec, 1);
}
static void cs_8409_setup_TDM_proper_amps34(struct hda_codec *codec)
{
int ret_coef71 = 0;
int new_coef71 = 0;
// codes from windows cs4208_38.inf file
// 0x001b 0x0840 = (ASP1.B: TX.LAP = 0, TX.LSZ = 24 bits, TX.LCS = 64)
// 0x001c 0x0860 = (ASP1.B: TX.RAP = 0, TX.RSZ = 24 bits, TX.RCS = 96)
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001b, 0x0000, 0x00008840, 0 ); // coef read 1407
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x001b, 0x0840, 0x00000000, 0 ); // coef write 1411
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001c, 0x0000, 0x00008860, 0 ); // coef read 1415
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x001c, 0x0860, 0x00000000, 0 ); // coef write 1419
// the following actually reads from 0x19 to 0x57 in a loop if the snd_hda_coef_item returns 0 till the read value
// does not have the word sign bit set (ie 0x8000) or finish all 0x57
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00000800, 1423 ); // coef read 1423
tdm_in_use(codec, 2);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006b, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 1428
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000400f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 1432
new_coef71 = (ret_coef71 & 0xffff) | 0x400f;
myprintk_dbg("snd_hda_intel: masked cs_8409_setup_TDM_proper_amps34 coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x400f, 0x00000000, 1436 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 1436
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, new_coef71, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 1436
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 1439
}
static void cs_8409_setup_TDM_amps34(struct hda_codec *codec, int nullformat)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// this seems to be setup for node 0x03 chain - which seems to use node 0x25 and amps 0x74 and 0x72 (or 0x2c and 0x2e)
//snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x00324033
// snd_hda: stream format 3 [('CHAN', 4), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000012); // 0x00370612
// snd_hda: conv stream channel map 3 [('CHAN', 2), ('STREAMID', 1)]
if (nullformat)
{
// note that 0x4033 is Apples fixed format - but this is for boot stage when we have
// not defined any format yet so just use it - we overwrite below when actually play
// note this updates the channel but not stream id????
snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x00224033
snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000002); // 0x00270602
}
else
{
// using the stored stream parameters update nid 0x3 stream parameters
// we have limited the allowed formats so should only have working formats here
// now realised if we want to pass 2 channel streams to driver then we need to apply same
// fixup as in snd_hda_multi_out_analog_prepare ie set the channel id of the second nid
// to same as first nid for 2 channel inputs - rather than 2 if have a 4 channel stream
mydev_info(hda_codec_dev(codec), "cs_8409_setup_TDM_amps34: stream channels %d\n", spec->stream_channels);
if (spec->stream_channels == 2)
cs_8409_really_update_stream_format(codec, 0x03, 1, 2, 0);
else
cs_8409_really_update_stream_format(codec, 0x03, 1, 2, 2);
}
cs_8409_setup_TDM_proper_amps34(codec);
// enable output on node 0x25
//retval = snd_hda_codec_read_check(codec, 0x25, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 1443); // 0x025f0700
retval = snd_hda_codec_read(codec, 0x25, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000); // 0x025f0700
snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000040); // 0x02570740
// snd_hda: 37 ['AC_PINCTL_OUT_EN']
}
static void play_setup_TDM_amps34(struct hda_codec *codec)
{
cs_8409_setup_TDM_amps34(codec, 0);
}
static void cs_8409_setup_amps34(struct hda_codec *codec, int amps_enable)
{
if (codec->core.subsystem_id == 0x106b3900) {
// use reduced volume - from 0x01 to 0x30 - now passing as argument
// change channel mapping - make a standard left/right pair
// so 1st 2 channels are tweeters, 2nd 2 channels are woofers
cs_8409_setup_amp_max(codec, 0x74, 0x01, 0x01);
cs_8409_setup_amp_max(codec, 0x72, 0x01, 0x03);
// use reduced volume - from 0x01 to 0x30 - now passing as argument
//cs_8409_setup_amp_max(codec, 0x74, 0x30, 0x01);
//cs_8409_setup_amp_max(codec, 0x72, 0x30, 0x03);
// original mapping:
//cs_8409_setup_amp_max(codec, 0x74, 0x30, 0x02);
//cs_8409_setup_amp_max(codec, 0x72, 0x30, 0x03);
//cs_8409_setup_amp_max(codec, 0x74, 0x01, 0x02);
//cs_8409_setup_amp_max(codec, 0x72, 0x01, 0x03);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
//setup_node_alpha_ssm3(codec);
// use reduced volume - from 0x48 to 0x80 - same reduction as for MAXs -24dB
// change channel mapping - make a standard left/right pair
// so 1st 2 channels are tweeters, 2nd 2 channels are woofers
cs_8409_setup_amp_ssm3(codec, 0x2c, 0x48, 0x01);
cs_8409_setup_amp_ssm3(codec, 0x2e, 0x48, 0x03);
// use reduced volume - from 0x48 to 0x80 - same reduction as for MAXs -24dB
//cs_8409_setup_amp_ssm3(codec, 0x2c, 0x80, 0x01);
//cs_8409_setup_amp_ssm3(codec, 0x2e, 0x80, 0x03);
// original mapping:
//cs_8409_setup_amp_ssm3(codec, 0x2c, 0x80, 0x02);
//cs_8409_setup_amp_ssm3(codec, 0x2e, 0x80, 0x03);
//cs_8409_setup_amp_ssm3(codec, 0x2c, 0x48, 0x02);
//cs_8409_setup_amp_ssm3(codec, 0x2e, 0x48, 0x03);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
// NOTE that the TAS57642 amps setup during boot seems to skip the actual speaker power on
// hence the addition of the amps_enable parameter
// use reduced volume - from 0x48 to 0x80 - same reduction as for MAXs -24dB
// change channel mapping - make a standard left/right pair
// so 1st 2 channels are tweeters, 2nd 2 channels are woofers
cs_8409_setup_amp_tas576(codec, 0xdc, 0xcf, 0x01, amps_enable);
cs_8409_setup_amp_tas576(codec, 0xde, 0xcf, 0x03, amps_enable);
// use reduced volume - from 0xcf to 0x9f - same reduction as for MAXs -24dB (0.5dB steps)
//cs_8409_setup_amp_tas576(codec, 0xdc, 0x9f, 0x01, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xde, 0x9f, 0x03, amps_enable);
// original mapping:
//cs_8409_setup_amp_tas576(codec, 0xdc, 0x9f, 0x02, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xde, 0x9f, 0x03, amps_enable);
//cs_8409_setup_amp_tas576_amp2(codec, 0x9f, amps_enable);
//cs_8409_setup_amp_tas576_amp3(codec, 0x9f, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xdc, 0xcf, 0x02, amps_enable);
//cs_8409_setup_amp_tas576(codec, 0xde, 0xcf, 0x03, amps_enable);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
}
static void play_setup_amps34(struct hda_codec *codec)
{
cs_8409_setup_amps34(codec, 1);
}
static void cs_8409_sync_converters_on(struct hda_codec *codec, int nullformat)
{
int retval;
struct hda_cvt_setup p2;
struct hda_cvt_setup p3;
// this stops streaming on nodes 0x2 and 0x3 by switching to stream index 0
// then updates vendor node coef index 0x0017 twice
// first with 0x1 for node 0x2 and then with 0x2 for node 0x3
// giving a final 0x3
// then sets up ready for streaming again
// so coef index 0x17 is likely turning on the TDM stream
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
// remove normal channel mapping
// snd_hda: # AppleHDAFunctionGroupCS8409::syncConverters:
//retval = snd_hda_codec_read_check(codec, 0x02, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000010, 2714); // 0x002f0600
//retval = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONV, 0x00000000); // 0x002f0600
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 1)]
//snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00270600
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 0)]
cs_8409_save_and_clear_stream_format(codec, 0x02, &p2);
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0017, 0x0001, 0xffff, 0x00000000, 0, 0 ); // coef write mask 2716
// snd_hda: # AppleHDAFunctionGroupCS8409::syncConverters:
//retval = snd_hda_codec_read_check(codec, 0x03, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000012, 2722); // 0x003f0600
//retval = snd_hda_codec_read(codec, 0x03, 0, AC_VERB_GET_CONV, 0x00000000); // 0x003f0600
// snd_hda: conv stream channel map 3 [('CHAN', 2), ('STREAMID', 1)]
//snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00370600
// snd_hda: conv stream channel map 3 [('CHAN', 0), ('STREAMID', 0)]
cs_8409_save_and_clear_stream_format(codec, 0x03, &p3);
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0017, 0x0003, 0xffff, 0x00000001, 0, 0 ); // coef write mask 2724
// and reset back to normal channel mapping
//snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x00270610
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 1)]
//snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000012); // 0x00370612
// snd_hda: conv stream channel map 3 [('CHAN', 2), ('STREAMID', 1)]
if (nullformat)
{
snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00270600
snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000002); // 0x00270602
}
else
{
cs_8409_update_from_save_stream_format(codec, 0x02, &p2, 1, 0);
cs_8409_update_from_save_stream_format(codec, 0x03, &p3, 1, 0);
}
}
static void play_sync_converters_on(struct hda_codec *codec)
{
cs_8409_sync_converters_on(codec, 0);
}
static void cs_8409_setup_amp_max(struct hda_codec *codec, int amp_address, int amp_volume, int channel)
{
//int retval;
// NOTA BENE - reduced volume from 0x01 to 0x30 - seems to fit with linux levels much better
// this is semi arbitrary - just hears about OK - not based on rational analysis of amp gains
// HPFDCBlocker new as of June 2019
// snd_hda: # i2cWrite:
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x1c01 i2c data 0x0001 reg anal: DigitalFilter : HPFDCBlocker
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x1008 i2c data 0x0008 reg anal: PCMClockSetup : 256 Bclks
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x14e4 i2c data 0x00e4 reg anal: PCMModeConfig : 32 bits TDM mode 2
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x1501 i2c data 0x0001 reg anal: PCMRXEnablesA
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x1600 i2c data 0x0000 reg anal: PCMRXEnablesB
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x1800 i2c data 0x0000 reg anal: MonoMixChannelSource
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x2d01 i2c data 0x0001 reg anal: DigitalVolCtrl
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x2e05 i2c data 0x0005 reg anal: PathGain
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x4a21 i2c data 0x0021 reg anal: SpeakerEnable : AmpEnabled
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x4d07 i2c data 0x0007 reg anal: RestartBehavior
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x5534 i2c data 0x0034 reg anal: LimiterAttackRelease
// snd_hda i2cRead i2c address 0x64 i2c reg 0x1100 i2c data 0x1107 reg anal: PCMSampleSetup : 44.1kHz
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x1107 i2c data 0x0007 reg anal: PCMSampleSetup : 44.1kHz
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x093f i2c data 0x003f reg anal: InterruptClears0
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x0a7f i2c data 0x007f reg anal: InterruptClears1
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x0f0e i2c data 0x000e reg anal: IRQClear1
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x5001 i2c data 0x0001 reg anal: GlobalEnable : Enable
cs_8409_vendor_i2cWrite(codec, amp_address, 0x001c, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0010, 0x0008, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0014, 0x00e4, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0015, (1<<channel), 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0016, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0018, channel, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0019, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x002d, amp_volume, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x002e, 0x0005, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x004a, 0x0021, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x004d, 0x0007, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0055, 0x0034, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0011, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0011, 0x0007, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0009, 0x003f, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x000a, 0x007f, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x000f, 0x000e, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0050, 0x0001, 0); // snd_hda
}
static void cs_8409_setup_amp_ssm3(struct hda_codec *codec, int amp_address, int amp_volume, int channel)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0500 i2c data 0x0000 reg anal: SAIControl2 : ChipSlot 1 SlotByTDMRReg 24 bit Audio
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0111 i2c data 0x0011 reg anal: GainEdgeControl : 12.6V FSGainMap LowEMI
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0348 i2c data 0x0048 reg anal: DACVolume : -3.0dB
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0451 i2c data 0x0051 reg anal: SAIControl1 : TDMPCMMode 24 BClks per Chip Delay1 PulsedSync Falling
// snd_hda i2cRead i2c address 0x28 i2c reg 0x0200 i2c data 0x0232 reg anal: DACControl : 32-48kHz SampleRate DACLowPower DACHighPass DACSoftVol
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0232 i2c data 0x0032 reg anal: DACControl : 32-48kHz SampleRate DACLowPower DACHighPass DACSoftVol
// snd_hda i2cRead i2c address 0x28 i2c reg 0x0200 i2c data 0x0232 reg anal: DACControl : 32-48kHz SampleRate DACLowPower DACHighPass DACSoftVol
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0232 i2c data 0x0032 reg anal: DACControl : 32-48kHz SampleRate DACLowPower DACHighPass DACSoftVol
// snd_hda i2cWrite i2c address 0x28 i2c reg 0x0000 i2c data 0x0000 reg anal: PowerControl : PowerOn BVSenseOn
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0005, channel, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0001, 0x0011, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0003, amp_volume, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0004, 0x0051, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0002, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0002, 0x0032, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0002, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0002, 0x0032, 1); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0000, 0x0000, 1); // snd_hda
}
static void cs_8409_setup_amp_tas576(struct hda_codec *codec, int amp_address, int amp_volume, int channel, int amp_enable)
{
//int retval;
// this data from the TAS5760md spec sheet (closest one I can find)
// there are a number of inconsistencies
// first - the MAX/SSM amps are mono amps but the TAS5760md seems to be a stereo amp
// (there is a PBTL mode which can use both amps to drive a single speaker which
// may be whats going on - now this can be set in hardware but its does not appear to be done in software)
// - note that the HDA node setup seems to be 4 channel audio as 2 left channels (node 0x02) and 2 right channels (0x03)
// hence 4 mono amps required
// some regs seem valid - others not
// reg 0x01 does seem to be the power control and is used to enable/disable the amps and values are consistent
// reg 0x04 is labelled the Left Volume but there are no reg 0x05 Right Volume setup calls at all
// reg 0x03 is labelled Volume Control and the Fade may be right
// but the low order mute bits dont make sense - simply seems to index the amps ie 0,1,2,3
// - which according to tas5760 docs would be no mute, mute left, mute right, mute all
// what makes more sense is that its indexing the individual channels of the 4 channel TDM stream
// so yes I think this is being used in PBTL mode to drive a single speaker with reg 0x04 being
// the volume control and reg 0x03 low order bits determining which channel to use
// NOTE that the TAS57642 amps setup during boot seems to skip the actual speaker power on
// hence the addition of the amp_enable parameter
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0200 i2c data 0x0204 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0300 i2c data 0x0380 reg anal: Volume Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0380 i2c data 0x0080 reg anal: Volume Control : Fade, Muted??
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0600 i2c data 0x0651 reg anal: Analog Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0655 i2c data 0x0055 reg anal: Analog Control : PWM Rate x16, Gain 22.6dB
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0800 i2c data 0x0808 reg anal: Fault Config & Error
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0818 i2c data 0x0018 reg anal: Fault Config & Error : Threshold 75%, Clock Error??
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x04cf i2c data 0x00cf reg anal: Left Chan Vol Control : 0dB
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x1300 i2c data 0x1300 reg anal: Undocumented
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x1300 i2c data 0x0000 reg anal: Undocumented
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0200 i2c data 0x0244 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
// here we have read/write pairs suggesting this is done as masked i2c writes
// but we have no idea what the masks are
cs_8409_vendor_i2cRead(codec, amp_address, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0002, 0x0044, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0003, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0003, 0x0080|channel, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0006, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0006, 0x0055, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0008, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0008, 0x0018, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0004, amp_volume, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0013, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0013, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0002, 0x0044, 0); // snd_hda
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x01fd i2c data 0x00fd reg anal: Power Control : Not sleep, Spkr Amp On
if (amp_enable)
{
cs_8409_vendor_i2cRead(codec, amp_address, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0001, 0x00fd, 0); // snd_hda
}
}
static void cs_8409_setup_amp_tas576_amp0(struct hda_codec *codec, int amp_volume, int amp_enable)
{
//int retval;
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0200 i2c data 0x0204 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0300 i2c data 0x0380 reg anal: Volume Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0380 i2c data 0x0080 reg anal: Volume Control : Fade, Not Muted??
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0600 i2c data 0x0651 reg anal: Analog Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0655 i2c data 0x0055 reg anal: Analog Control : PWM Rate x16, Gain 22.6dB
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0800 i2c data 0x0808 reg anal: Fault Config & Error
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0818 i2c data 0x0018 reg anal: Fault Config & Error : Threshold 75%, Clock Error??
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x04cf i2c data 0x00cf reg anal: Left Chan Vol Control : 0dB
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x1300 i2c data 0x1300 reg anal: Undocumented
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x1300 i2c data 0x0000 reg anal: Undocumented
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0200 i2c data 0x0244 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0002, 0x0044, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0003, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0003, 0x0080, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0006, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0006, 0x0055, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0008, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0008, 0x0018, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0004, 0x00cf, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0013, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0013, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0002, 0x0044, 0); // snd_hda
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x01fd i2c data 0x00fd reg anal: Power Control : Not sleep, Spkr Amp On
if (amp_enable)
{
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0001, 0x00fd, 0); // snd_hda
}
}
static void cs_8409_setup_amp_tas576_amp1(struct hda_codec *codec, int amp_volume, int amp_enable)
{
//int retval;
// snd_hda i2cRead i2c address 0xda i2c reg 0x0200 i2c data 0x0204 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xda i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
// snd_hda i2cRead i2c address 0xda i2c reg 0x0300 i2c data 0x0380 reg anal: Volume Control
// snd_hda i2cWrite i2c address 0xda i2c reg 0x0380 i2c data 0x0081 reg anal: Volume Control : Fade, Left Muted??
// snd_hda i2cRead i2c address 0xda i2c reg 0x0600 i2c data 0x0651 reg anal: Analog Control
// snd_hda i2cWrite i2c address 0xda i2c reg 0x0655 i2c data 0x0055 reg anal: Analog Control : PWM Rate x16, Gain 22.6dB
// snd_hda i2cRead i2c address 0xda i2c reg 0x0800 i2c data 0x0808 reg anal: Fault Config & Error
// snd_hda i2cWrite i2c address 0xda i2c reg 0x0818 i2c data 0x0018 reg anal: Fault Config & Error : Threshold 75%, Clock Error??
// snd_hda i2cWrite i2c address 0xda i2c reg 0x04cf i2c data 0x00cf reg anal: Left Chan Vol Control : 0dB
// snd_hda i2cRead i2c address 0xda i2c reg 0x1300 i2c data 0x1300 reg anal: Undocumented
// snd_hda i2cWrite i2c address 0xda i2c reg 0x1300 i2c data 0x0000 reg anal: Undocumented
// snd_hda i2cRead i2c address 0xda i2c reg 0x0200 i2c data 0x0244 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xda i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
cs_8409_vendor_i2cRead(codec, 0xda, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0002, 0x0044, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xda, 0x0003, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0003, 0x0081, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xda, 0x0006, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0006, 0x0055, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xda, 0x0008, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0008, 0x0018, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0004, 0x00cf, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xda, 0x0013, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0013, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xda, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0002, 0x0044, 0); // snd_hda
// snd_hda i2cRead i2c address 0xda i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xda i2c reg 0x01fd i2c data 0x00fd reg anal: Power Control : Not sleep, Spkr Amp On
if (amp_enable)
{
cs_8409_vendor_i2cRead(codec, 0xda, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0001, 0x00fd, 0); // snd_hda
}
}
static void cs_8409_setup_amp_tas576_amp2(struct hda_codec *codec, int amp_volume, int amp_enable)
{
//int retval;
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0200 i2c data 0x0204 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0300 i2c data 0x0380 reg anal: Volume Control
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x0380 i2c data 0x0082 reg anal: Volume Control : Fade, Right Muted??
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0600 i2c data 0x0651 reg anal: Analog Control
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x0655 i2c data 0x0055 reg anal: Analog Control : PWM Rate x16, Gain 22.6dB
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0800 i2c data 0x0808 reg anal: Fault Config & Error
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x0818 i2c data 0x0018 reg anal: Fault Config & Error : Threshold 75%, Clock Error??
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x04cf i2c data 0x00cf reg anal: Left Chan Vol Control : 0dB
// snd_hda i2cRead i2c address 0xdc i2c reg 0x1300 i2c data 0x1300 reg anal: Undocumented
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x1300 i2c data 0x0000 reg anal: Undocumented
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0200 i2c data 0x0244 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0002, 0x0044, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0003, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0003, 0x0082, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0006, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0006, 0x0055, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0008, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0008, 0x0018, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0004, 0x00cf, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0013, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0013, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0002, 0x0044, 0); // snd_hda
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x01fd i2c data 0x00fd reg anal: Power Control : Not sleep, Spkr Amp On
if (amp_enable)
{
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0001, 0x00fd, 0); // snd_hda
}
}
static void cs_8409_setup_amp_tas576_amp3(struct hda_codec *codec, int amp_volume, int amp_enable)
{
//int retval;
// snd_hda i2cRead i2c address 0xde i2c reg 0x0200 i2c data 0x0204 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xde i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
// snd_hda i2cRead i2c address 0xde i2c reg 0x0300 i2c data 0x0380 reg anal: Volume Control
// snd_hda i2cWrite i2c address 0xde i2c reg 0x0380 i2c data 0x0083 reg anal: Volume Control : Fade, Left and Right Muted??
// snd_hda i2cRead i2c address 0xde i2c reg 0x0600 i2c data 0x0651 reg anal: Analog Control
// snd_hda i2cWrite i2c address 0xde i2c reg 0x0655 i2c data 0x0055 reg anal: Analog Control : PWM Rate x16, Gain 22.6dB
// snd_hda i2cRead i2c address 0xde i2c reg 0x0800 i2c data 0x0808 reg anal: Fault Config & Error
// snd_hda i2cWrite i2c address 0xde i2c reg 0x0818 i2c data 0x0018 reg anal: Fault Config & Error : Threshold 75%, Clock Error??
// snd_hda i2cWrite i2c address 0xde i2c reg 0x04cf i2c data 0x00cf reg anal: Left Chan Vol Control : 0dB
// snd_hda i2cRead i2c address 0xde i2c reg 0x1300 i2c data 0x1300 reg anal: Undocumented
// snd_hda i2cWrite i2c address 0xde i2c reg 0x1300 i2c data 0x0000 reg anal: Undocumented
// snd_hda i2cRead i2c address 0xde i2c reg 0x0200 i2c data 0x0244 reg anal: Digital Control
// snd_hda i2cWrite i2c address 0xde i2c reg 0x0244 i2c data 0x0044 reg anal: Digital Control : I2S format, Undocumented
cs_8409_vendor_i2cRead(codec, 0xde, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0002, 0x0044, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xde, 0x0003, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0003, 0x0083, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xde, 0x0006, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0006, 0x0055, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xde, 0x0008, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0008, 0x0018, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0004, 0x00cf, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xde, 0x0013, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0013, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, 0xde, 0x0002, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0002, 0x0044, 0); // snd_hda
// snd_hda i2cRead i2c address 0xde i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xde i2c reg 0x01fd i2c data 0x00fd reg anal: Power Control : Not sleep, Spkr Amp On
if (amp_enable)
{
cs_8409_vendor_i2cRead(codec, 0xde, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0001, 0x00fd, 0); // snd_hda
}
}
static void cs_8409_sync_converters_off(struct hda_codec *codec, int nullformat)
{
int retval;
struct hda_cvt_setup p2;
struct hda_cvt_setup p3;
// this stops streaming on nodes 0x2 and 0x3 by switching to stream index 0
// then updates vendor node coef index 0x0017 twice
// first with 0x2 for node 0x1 and then with 0x0 for node 0x2
// giving a final 0x0
// then sets up ready for streaming again
// so coef index 0x17 is likely turning off the TDM stream
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
// remove normal channel mapping
// snd_hda: # AppleHDAFunctionGroupCS8409::syncConverters:
//retval = snd_hda_codec_read_check(codec, 0x02, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000010, 4); // 0x002f0600
//retval = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONV, 0x00000000); // 0x002f0600
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 1)]
//snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00270600
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 0)]
cs_8409_save_and_clear_stream_format(codec, 0x02, &p2);
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0017, 0x0002, 0xffff, 0x00000003, 0, 0 ); // coef write mask 6
// snd_hda: # AppleHDAFunctionGroupCS8409::syncConverters:
//retval = snd_hda_codec_read_check(codec, 0x03, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000012, 12); // 0x003f0600
//retval = snd_hda_codec_read(codec, 0x03, 0, AC_VERB_GET_CONV, 0x00000000); // 0x003f0600
// snd_hda: conv stream channel map 3 [('CHAN', 2), ('STREAMID', 1)]
//snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00370600
// snd_hda: conv stream channel map 3 [('CHAN', 0), ('STREAMID', 0)]
cs_8409_save_and_clear_stream_format(codec, 0x03, &p3);
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0017, 0x0000, 0xffff, 0x00000002, 0, 0 ); // coef write mask 14
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0017, 0x0000, 0x00000000, 0 ); // coef read 20
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0018, 0x0000, 0x00000000, 0 ); // coef read 24
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0001, 0x0220, 0xffff, 0x00000220, 0, 0 ); // coef write mask 28
// and reset back to normal channel mapping
//snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x00270610
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 1)]
//snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000012); // 0x00370612
// snd_hda: conv stream channel map 3 [('CHAN', 2), ('STREAMID', 1)]
if (nullformat)
{
snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00270600
snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00370602
}
else
{
cs_8409_update_from_save_stream_format(codec, 0x02, &p2, 1, 0);
cs_8409_update_from_save_stream_format(codec, 0x03, &p3, 1, 0);
}
}
static void playstop_sync_converters_off(struct hda_codec *codec)
{
cs_8409_sync_converters_off(codec, 0);
}
static void cs_8409_disable_amp_max(struct hda_codec *codec, int amp_address);
static void cs_8409_disable_amp_ssm3(struct hda_codec *codec, int amp_address);
static void cs_8409_disable_amp_tas576(struct hda_codec *codec, int amp_address);
static void cs_8409_disable_amp_tas576_amp0(struct hda_codec *codec);
static void cs_8409_disable_amp_tas576_amp1(struct hda_codec *codec);
static void cs_8409_disable_amp_tas576_amp2(struct hda_codec *codec);
static void cs_8409_disable_amp_tas576_amp3(struct hda_codec *codec);
static void cs_8409_disable_amps12(struct hda_codec *codec)
{
if (codec->core.subsystem_id == 0x106b3900) {
cs_8409_disable_amp_max(codec, 0x64);
cs_8409_disable_amp_max(codec, 0x62);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
//setup_node_alpha_ssm3(codec);
cs_8409_disable_amp_ssm3(codec, 0x28);
cs_8409_disable_amp_ssm3(codec, 0x2a);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
//cs_8409_disable_amp_tas576(codec, 0xd8);
//cs_8409_disable_amp_tas576(codec, 0xda);
cs_8409_disable_amp_tas576_amp0(codec);
cs_8409_disable_amp_tas576_amp1(codec);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
}
static void playstop_disable_amps12(struct hda_codec *codec)
{
cs_8409_disable_amps12(codec);
}
static void cs_8409_disable_TDM_proper_amps12(struct hda_codec *codec)
{
//int retval;
int ret_coef71 = 0;
int new_coef71 = 0;
// this seems to be setup for node 0x02 chain - which seems to use node 0x24 and amps 0x64 and 0x62 (or 0x28 and 0x2a)
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00000800, 0 ); // coef read 341
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0019, 0x8800, 0x00000000, 0 ); // coef write 345
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001a, 0x0000, 0x00000820, 0 ); // coef read 349
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x001a, 0x8820, 0x00000000, 0 ); // coef write 353
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 357 ); // coef read 357
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001a, 0x0000, 0x00008820, 361 ); // coef read 361
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001b, 0x0000, 0x00000840, 365 ); // coef read 365
tdm_in_use(codec, 30);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006b, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 370
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000400f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 374
new_coef71 = (ret_coef71 & 0xffff);
myprintk_dbg("snd_hda_intel: masked cs_8409_disable_TDM_proper_amps12 coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x400f, 0x00000000, 378 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 378
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, new_coef71, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 378
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 381
}
static void cs_8409_disable_TDM_amps12(struct hda_codec *codec)
{
int retval;
cs_8409_disable_TDM_proper_amps12(codec);
// set to defaults and disable output
// note here we really reset to 0 format in addition to stream id 0/channel id 0
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00270600
// snd_hda: conv stream channel map 2 [('CHAN', 0), ('STREAMID', 0)]
snd_hda_codec_write(codec, 0x02, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x00220000
// snd_hda: stream format 2 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//retval = snd_hda_codec_read_check(codec, 0x24, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000040, 387); // 0x024f0700
retval = snd_hda_codec_read(codec, 0x24, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000); // 0x024f0700
snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x02470700
// snd_hda: 36 []
}
static void playstop_disable_TDM_amps12(struct hda_codec *codec)
{
cs_8409_disable_TDM_amps12(codec);
}
static void cs_8409_disable_amps34(struct hda_codec *codec)
{
if (codec->core.subsystem_id == 0x106b3900) {
cs_8409_disable_amp_max(codec, 0x74);
cs_8409_disable_amp_max(codec, 0x72);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
//setup_node_alpha_ssm3(codec);
cs_8409_disable_amp_ssm3(codec, 0x2c);
cs_8409_disable_amp_ssm3(codec, 0x2e);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
//cs_8409_disable_amp_tas576(codec, 0xdc);
//cs_8409_disable_amp_tas576(codec, 0xde);
cs_8409_disable_amp_tas576_amp2(codec);
cs_8409_disable_amp_tas576_amp3(codec);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
}
static void playstop_disable_amps34(struct hda_codec *codec)
{
cs_8409_disable_amps34(codec);
}
static void cs_8409_disable_TDM_proper_amps34(struct hda_codec *codec)
{
//int retval;
int ret_coef1 = 0;
int new_coef1 = 0;
// AppleHDATDMBusManagerCS8409::disableTDMPath
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001b, 0x0000, 0x00000840, 0 ); // coef read 694
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x001b, 0x8840, 0x00000000, 0 ); // coef write 698
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001c, 0x0000, 0x00000860, 0 ); // coef read 702
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x001c, 0x8860, 0x00000000, 0 ); // coef write 706
// AppleHDATDMBusManagerCS8409::disableTDMPath
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x0001, 0xffff, 0x00005401, 0, 710 ); // coef write mask 710
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x0000, 0x5400, 0x00005401, 0x0001, 0 ); // coef write mask 710
// AppleHDATDMBusManagerCS8409::disableTDMPath
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000220, 0 ); // coef read 716
new_coef1 = (ret_coef1 & 0xffdf); // clear out 0x20 bit
myprintk_dbg("snd_hda_intel: masked cs_8409_disable_TDM_proper_amps34 coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0200, 0x00000000, 720 ); // coef write 720
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 0 ); // coef write 720
// AppleHDATDMBusManagerCS8409::setupTDMPath or disableTDMPath calls AppleHDATDMBusManagerCS8409::configureTDMUR
// AppleHDATDMBusManagerCS8409::configureTDMUR only place calls this
// this is AppleHDATDMBusManagerCS8409::tdmInUse
// which reads from 0x19 to 0x57 in a loop if the snd_hda_coef_item returns 0 till the read value
// does not have the word sign bit set (ie 0x8000) or finish all 0x57
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 724 ); // coef read 724
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x001a, 0x0000, 0x00008820, 728 ); // coef read 728
// ....
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0056, 0x0000, 0x00008000, 968 ); // coef read 968
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0057, 0x0000, 0x00008000, 972 ); // coef read 972
tdm_in_use(codec, 40);
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x00000000, 0 ); // coef write 977
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00000000);
}
static void cs_8409_disable_TDM_amps34(struct hda_codec *codec)
{
int retval;
cs_8409_disable_TDM_proper_amps34(codec);
// set to defaults and disable output
// note here we really reset to 0 format in addition to stream id 0/channel id 0
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00370600
// snd_hda: conv stream channel map 3 [('CHAN', 0), ('STREAMID', 0)]
snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x00320000
// snd_hda: stream format 3 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//retval = snd_hda_codec_read_check(codec, 0x25, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000040, 986); // 0x025f0700
retval = snd_hda_codec_read(codec, 0x25, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000); // 0x025f0700
snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x02570700
// snd_hda: 37 []
}
static void playstop_disable_TDM_amps34(struct hda_codec *codec)
{
cs_8409_disable_TDM_amps34(codec);
}
static void cs_8409_disable_amp_max(struct hda_codec *codec, int amp_address)
{
//int retval;
// interrupt read/state read new as of June 2019
// snd_hda: # i2cWrite:
// snd_hda i2cWrite i2c address 0x64 i2c reg 0x5000 i2c data 0x0000 reg anal: GlobalEnable : Disable
// snd_hda i2cRead i2c address 0x64 i2c reg 0x0300 i2c data 0x0300 reg anal: InterruptState0
// snd_hda i2cRead i2c address 0x64 i2c reg 0x0400 i2c data 0x0400 reg anal: InterruptState1
// snd_hda i2cRead i2c address 0x64 i2c reg 0x0c00 i2c data 0x0c00 reg anal: State1
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0050, 0x0000, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0003, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x0004, 0); // snd_hda
cs_8409_vendor_i2cRead(codec, amp_address, 0x000c, 0); // snd_hda
}
static void cs_8409_disable_amp_ssm3(struct hda_codec *codec, int amp_address)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cWrite i2c address 0x2c i2c reg 0x0001 i2c data 0x0001 reg anal: PowerControl : PowerDown BVSenseOn
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0000, 0x0001, 1); // snd_hda
}
static void cs_8409_disable_amp_tas576(struct hda_codec *codec, int amp_address)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x01fc i2c data 0x00fc reg anal: Power Control : Not sleep, Spkr Amp Shutdown
cs_8409_vendor_i2cRead(codec, amp_address, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, amp_address, 0x0001, 0x00fc, 0); // snd_hda
}
static void cs_8409_disable_amp_tas576_amp0(struct hda_codec *codec)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cRead i2c address 0xd8 i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xd8 i2c reg 0x01fc i2c data 0x00fc reg anal: Power Control : Not sleep, Spkr Amp Shutdown
cs_8409_vendor_i2cRead(codec, 0xd8, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xd8, 0x0001, 0x00fc, 0); // snd_hda
}
static void cs_8409_disable_amp_tas576_amp1(struct hda_codec *codec)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cRead i2c address 0xda i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xda i2c reg 0x01fc i2c data 0x00fc reg anal: Power Control : Not sleep, Spkr Amp Shutdown
cs_8409_vendor_i2cRead(codec, 0xda, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xda, 0x0001, 0x00fc, 0); // snd_hda
}
static void cs_8409_disable_amp_tas576_amp2(struct hda_codec *codec)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cRead i2c address 0xdc i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xdc i2c reg 0x01fc i2c data 0x00fc reg anal: Power Control : Not sleep, Spkr Amp Shutdown
cs_8409_vendor_i2cRead(codec, 0xdc, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xdc, 0x0001, 0x00fc, 0); // snd_hda
}
static void cs_8409_disable_amp_tas576_amp3(struct hda_codec *codec)
{
//int retval;
// snd_hda: # i2cWrite:
// snd_hda i2cRead i2c address 0xde i2c reg 0x0100 i2c data 0x01fc reg anal: Power Control
// snd_hda i2cWrite i2c address 0xde i2c reg 0x01fc i2c data 0x00fc reg anal: Power Control : Not sleep, Spkr Amp Shutdown
cs_8409_vendor_i2cRead(codec, 0xde, 0x0001, 0); // snd_hda
cs_8409_vendor_i2cWrite(codec, 0xde, 0x0001, 0x00fc, 0); // snd_hda
}
static void playstop_disable_amp_max(struct hda_codec *codec, int amp_address)
{
cs_8409_disable_amp_max(codec, amp_address);
}
static void cs_8409_inputs_power_nids_on(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 2785); // 0x022f0500
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 2786); // 0x023f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D0);
}
static void cs_8409_inputs_power_nids_off(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10741); // 0x022f0500
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10742); // 0x023f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D3);
}
static void cs_8409_plugin_handle_detect(struct hda_codec *codec);
static void cs_8409_headset_amp_format_setup_disable(struct hda_codec *codec, int full);
static void cs43l83_headset_amp_format_setup(struct hda_codec *codec, int set_stream_id, int full);
static void cs_8409_perform_external_device_unsolicited_responses(struct hda_codec *codec);
static void cs_8409_plugin_complete_detect(struct hda_codec *codec);
static void cs42l83_headset_play_setup_on(struct hda_codec *codec);
static void cs42l83_headset_mike_format_setup_enable(struct hda_codec *codec, int nullformat, int full);
static void cs_8409_headset_mike_buttons_enable(struct hda_codec *codec);
static int cs_8409_boot_setup_real(struct hda_codec *codec)
{
int headset_on_boot = 0, retval;
struct cs8409_apple_spec *spec = codec->spec;
//hda_nid_t beep_nid = spec->beep_nid;
mycodec_info(codec, "command cs_8409_boot_setup_real start\n");
setup_reset_and_clear(codec);
// read parameters from all nodes - excluding VirtualWidgets
// the loop over node counts calls AppleHDAWidgetFactory::createAppleHDAWidget(DevIdStruct*)
// which Im assuming calls the initForNodeID functions
init_read_all_nodes(codec);
read_vendor_node(codec);
init_read_coefs(codec);
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000000);
hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
read_virtual_widgets(codec);
init_for_node_vendor(codec);
// this is determineSpeakerID
// this does not make sense - this just checks GPIO pin(s)??
determine_speaker_id(codec);
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x00170503
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D3);
// why is this commented??
//setup_jack_pin_config(codec);
enable_i2c(codec);
if (codec->core.subsystem_id == 0x106b3900) {
enable_GPIforUR(codec, 0x5);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
enable_GPIforUR(codec, 0xd);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
enable_GPIforUR(codec, 0xd);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
if (codec->core.subsystem_id == 0x106b3900) {
cs42l83_external_control_GPIO(codec, 0x7);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
cs42l83_external_control_GPIO(codec, 0xf);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
cs42l83_external_control_GPIO(codec, 0xf);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
// we have confirmed that the disabling all the cs42l83 setup does not affect the amps
cs42l83_reset(codec);
//cs42l83_external_control_GPIO2_clear_2(codec);
//cs42l83_external_control_GPIO2_set_2(codec);
if (codec->core.subsystem_id == 0x106b3900) {
cs42l83_external_control_GPIO(codec, 0x7);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
cs42l83_external_control_GPIO(codec, 0xf);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
cs42l83_external_control_GPIO(codec, 0xf);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
cs42l83_device_id(codec);
cs42l83_inithw(codec);
if (codec->core.subsystem_id == 0x106b3900) {
//setup_amps_reset(codec);
setup_amps_reset_i2c_max(codec);
}
else if (codec->core.subsystem_id == 0x106b3300 || codec->core.subsystem_id == 0x106b3600) {
//setup_amps_reset_i2c_ssm3
setup_amps_reset_i2c_ssm3(codec);
}
else if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00) {
//setup_amps_reset(codec);
setup_amps_reset_i2c_tas576(codec);
}
else {
dev_info(hda_codec_dev(codec), "UNKNOWN subsystem id 0x%08x",codec->core.subsystem_id);
}
//read_gpio_status(codec);
retval = read_gpio_status_check(codec);
cs42l83_mic_detect(codec);
// apparently the imacs use an inverted circuit for physical sensing of jack being plugged in
if (codec->core.subsystem_id == 0x106b1000 || codec->core.subsystem_id == 0x106b0f00 || codec->core.subsystem_id == 0x106b0e00)
cs42l83_tip_sense(codec, 1);
else
cs42l83_tip_sense(codec, 0);
cs42l83_plugin_interrupt_setup(codec);
// should check here if have headphones plugged in
// likely additional code here if we did boot with headphones plugged in
//cs42l83_headphone_sense_data(codec);
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real headphone ALREADY PLUGGED IN!!\n");
// store for after init
headset_on_boot = 1;
}
// cs_8409_intmike_format_setup_enable is done before we get a capture prepare
// so we need to store some dummy initial setup
// unlike OSX make it a stream id of 0
// (note this only updates our local cached data - need a cs_8409_really_update_stream_format to actually update nid)
cs_8409_store_stream_format(codec, spec->intmike_adc_nid, 0, 0x4031);
//setup_intmike_nid(codec);
//cs_8409_intmike_format_setup_format(codec);
cs_8409_intmike_format_setup_enable(codec, 0x4031, 1);
cs_8409_intmike_volume_setup(codec, 0x27);
cs_8409_intmike_stream_on_nid(codec);
//setup_intmike_format_resetup(codec);
//cs_8409_intmike_format_setup_format_nouse(codec);
//cs_8409_really_update_stream_format(codec, 0x22, 1, 0, 0);
cs_8409_really_update_stream_format(codec, spec->intmike_adc_nid, 1, 0, 0);
//setup_linein_nid(codec);
cs_8409_linein_volume_setup(codec, 0x27);
cs_8409_linein_format_setup_disable(codec);
//setup_intmike_stream_conn_off_nid(codec);
cs_8409_intmike_stream_conn_off(codec);
//setup_linein_stream_conn_off_nid(codec);
cs_8409_linein_stream_conn_off(codec);
//setup_intmike_stream_off_nid(codec);
cs_8409_intmike_stream_off_nid(codec);
//setup_linein_stream_off_nid(codec);
cs_8409_linein_stream_off_nid(codec);
//setup_intmike_vol1(codec);
cs_8409_intmike_volume_mute_nouse(codec);
//setup_linein_vol1(codec);
cs_8409_linein_volume_mute_nouse(codec);
//setup_intmike_vol2(codec);
cs_8409_intmike_volume_unmute_nouse(codec);
//setup_linein_vol2(codec);
cs_8409_linein_volume_unmute_nouse(codec);
if (headset_on_boot)
{
// so the big question is what to do about unsolicited responses
// should we disable them in this boot section
// and if so when should we re-enable them
// I suspect at some point the code for headset already plugged in
// switches to unsolicited response code
// so I think we need to enable unsol response at this stage and block it till end of this function
// - because we seem to get an UNSOL response in the middle of this code
spec->block_unsol = 1;
// Im guessing the following code should be done explicitly
// because we have not seen a cs42l83_read_status_and_clear_interrupt/cs42l83_disambiguate_ur_from_int
// for some reason the stream id is set to 0 here
cs43l83_headset_amp_format_setup(codec, 0, 0);
//#2880: cs42l83_configure_int_mclk
//#3152: cs42l83_power_onoff
//#3216: cs42l83_configure_serial_port
//#3376: cs42l83_output_set_input_sample_rate
//#3504: cs42l83_setup_audio_output
//#3680: cs42l83_buffers_onoff
// this is essentially from cs42l83_headset_play_setup_on
cs42l83_configure_int_mclk(codec);
//cs42l83_headset_power_on_on_nouse(codec);
cs42l83_power_onoff(codec, 1);
cs42l83_configure_serial_port(codec);
cs42l83_output_set_input_sample_rate(codec);
cs42l83_setup_audio_output(codec);
// headset_setup_SPDIF_output(codec); - presumably if is SPDIF setup
//cs42l83_headset_rcv_enable_on(codec);
cs42l83_buffers_onoff(codec, 1);
// so we seem to get an UNSOL response at this point
// - Im thinking we need to store this response
// and now turn off - this is now cs42l83_headset_disable
//#3698: cs42l83_buffers_onoff
//#3714: cs42l83_headset_power_off
cs42l83_buffers_onoff(codec, 0);
cs42l83_power_onoff(codec, 0);
cs_8409_headset_amp_format_setup_disable(codec, 1);
// and back on again
// we dont set stream id, do full TDM setup and not enable the pin
// then set stream id, turn on pin but partial TDM setup
cs43l83_headset_amp_format_setup(codec, 0, 1);
cs43l83_headset_amp_format_setup(codec, 1, 0);
//#3920: cs42l83_configure_int_mclk
//#4192: cs42l83_power_onoff
//#4256: cs42l83_configure_serial_port
//#4416: cs42l83_output_set_input_sample_rate
//#4544: cs42l83_setup_audio_output
//#4720: cs42l83_buffers_onoff
// this is essentially from cs42l83_headset_play_setup_on
cs42l83_configure_int_mclk(codec);
//cs42l83_headset_power_on_on_nouse(codec);
cs42l83_power_onoff(codec, 1);
cs42l83_configure_serial_port(codec);
cs42l83_output_set_input_sample_rate(codec);
cs42l83_setup_audio_output(codec);
// headset_setup_SPDIF_output(codec); - presumably if is SPDIF setup
//cs42l83_headset_rcv_enable_on(codec);
cs42l83_buffers_onoff(codec, 1);
//#4738: cs42l83_headphone_sense
// this may be the same as one of the multiple headphone sense calls seen if no headset plugged in
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real headphone still plugged in!!\n");
cs42l83_buffers_onoff(codec, 0);
cs42l83_power_onoff(codec, 0);
cs_8409_headset_amp_format_setup_disable(codec, 1);
cs_8409_intmike_volume_unmute_nouse(codec);
cs_8409_linein_volume_unmute_nouse(codec);
cs_8409_intmike_volume_unmute_nouse(codec);
cs_8409_linein_volume_unmute_nouse(codec);
cs_8409_inputs_power_nids_off(codec);
// so I think we need to try performing the unsol responses here
// - because we get a call to cs42l83_read_status_and_clear_interrupt/cs42l83_disambiguate_ur_from_int here
// well all the evidence is altho these routines are called they dont actually do anything
// - the cs_8409_read_status_and_clear_interrupt call does not see a TIP SENSE interrupt
// (cf actually plugging in headphones post-boot)
// - calling these routines does clear the interrupt - which may be its only function
// we need to update headset_phase so we dont ignore headset unsol responses in the following call
spec->headset_phase = 1;
// I think we need to block here - because clearing the interrupts causes interrupts!!
// this is similar to cs_8409_cs42l83_unsolicited_response where we block
// before calling the perform function
spec->block_unsol = 1;
cs_8409_perform_external_device_unsolicited_responses(codec);
spec->block_unsol = 0;
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot headphone REMOVED - UNIMPLEMENTED!!\n");
}
// so now just going to continue with the logged boot code
// we get a lot of checks the headset is still plugged in
// Im assuming if these detect the headset has been removed other things may happen
// - this would likely be setting up the amps
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot headphone REMOVED 2 - UNIMPLEMENTED!!\n");
}
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
cs_8409_intmike_volume_unmute(codec);
cs_8409_linein_volume_unmute(codec);
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot headphone REMOVED 3 - UNIMPLEMENTED!!\n");
}
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
//#5328: cs42l83_headset_button_detect_interrupts_off
//#5392: cs42l83_headset_set_hpout_clamp_disable
// these 2 functions seem to be this function
// - additional code is setting jack_present and an msleep
cs_8409_plugin_handle_detect(codec);
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot headphone REMOVED 4 - UNIMPLEMENTED!!\n");
}
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
// so there are 4 gpio status reads here
// why 4??
retval = read_gpio_status_check(codec);
retval = read_gpio_status_check(codec);
retval = read_gpio_status_check(codec);
retval = read_gpio_status_check(codec);
// why - this just sets nid 0x22 format???
cs_8409_intmike_format_setup_format_nouse(codec);
//cs_8409_really_update_stream_format(codec, 0x22, 1, 0, 0);
//cs_8409_linein_volume_setup_new(codec, 0x27)
cs_8409_linein_volume_setup(codec, 0x27);
cs_8409_linein_format_setup_disable(codec);
cs_8409_intmike_stream_conn_off(codec);
cs_8409_linein_stream_conn_off(codec);
cs_8409_intmike_stream_off_nid(codec);
cs_8409_linein_stream_off_nid(codec);
cs_8409_intmike_volume_mute(codec);
cs_8409_linein_volume_mute(codec);
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot headphone REMOVED 5 - UNIMPLEMENTED!!\n");
}
// we see a delay here - this is I think the equivalent of the 1800 msleep
// in cs_8409_headset_plugin_event
// should we just make it 1800??
msleep(1500); // what we actually see is 1470
// the cs_8409_plugin_complete_detect function seems to encapsulate what happens next
// - this functions ends with initiating headset detection
//#5551: cs42l83_headphone_sense
//#5567: cs42l83_complete_jack_detect
//#5631: cs42l83_power_hs_bias_on
//#5727: cs42l83_enable_hs_auto_int_on
//#5759: cs42l83_unplug_interrupt_setup
//#5807: cs42l83_set_hpout_pulldown_off
//#5839: cs42l83_headset_detect_on
cs_8409_plugin_complete_detect(codec);
spec->block_unsol = 1;
// testing status checks to see if we get an interrupt
// so at this point the status is still 0x27 - no interrupt
// can we just use the msleep??
retval = read_gpio_status_check(codec);
msleep(1);
// but here the status is 0x26 ie interrupt
//retval = read_gpio_status_check(codec);
// I think we need to block here - because clearing the interrupts causes interrupts!!
// this is similar to cs_8409_cs42l83_unsolicited_response where we block
// before calling the perform function
// so next we should get some unsol responses
//#5923: cs42l83_read_status_and_clear_interrupt
//#6117: cs42l83_disambiguate_ur_from_int
//#6165: cs_8409_headset_type_detect_event
//#6165: cs42l83_enable_hs_auto_int_off
//#6197: cs42l83_headset_type
//#6213: cs42l83_unplug_headset_detect_off
//#6277: cs42l83_set_hpout_pulldown_onoff
//#6309: cs42l83_set_hpout_clamp_enable
//#6341: cs42l83_enable_hsbias_auto_clamp_on
//#6373: cs42l83_enable_hsbias_auto_clamp_off
//#6421: cs42l83_power_hs_bias_off
//#6517: cs42l83_setup_button_detect
//#6709: cs42l83_power_hs_bias_button_on
//#6805: cs42l83_enable_hsbias_auto_clamp_off1
cs_8409_perform_external_device_unsolicited_responses(codec);
retval = read_gpio_status_check(codec);
// so the delay here seems to be around 130 ms
// with delay of 1 ms dont see any interrupts
msleep(130);
retval = read_gpio_status_check(codec);
//#6857: cs42l83_read_status_and_clear_interrupt
//#7051: cs42l83_disambiguate_ur_from_int
// cs_8409_headset_button_detect_event
//#7099: cs42l83_handle_button_detect
//#7243: cs42l83_mike_connected
// cs_8409_perform_external_device_unsolicited_responses then calls cs_8409_plugin_event_continued
// - but here we have a divergence from plugin post-boot
// fixed up cs_8409_plugin_event_continued to only do things for plugin post-boot
// - at boot we drop back to here
// NOTA BENE - MUST set up the button interrupts here now - otherwise buttons wont work
cs_8409_perform_external_device_unsolicited_responses(codec);
//#7553: cs_8409_enable_headset_streaming
//#7553: cs43l83_headset_amp_format_setup
//#7417: cs42l83_headset_play_setup_on
//#7417: cs42l83_configure_int_mclk
//#7689: cs42l83_power_onoff
//#7753: cs42l83_configure_serial_port
//#7913: cs42l83_output_set_input_sample_rate
//#8041: cs42l83_setup_audio_output
//#8217: cs42l83_buffers_onoff
cs43l83_headset_amp_format_setup(codec, 1, 1);
cs42l83_headset_play_setup_on(codec);
// and yet again turn off
//#8233: cs42l83_buffers_onoff
//#8249: cs42l83_power_onoff
//#8279: cs_8409_headset_amp_format_setup_disable
cs42l83_buffers_onoff(codec, 0);
cs42l83_power_onoff(codec, 0);
cs_8409_headset_amp_format_setup_disable(codec, 1);
// and back on again
// we dont set stream id, do full TDM setup and not enable the pin
// then set stream id, turn on pin but partial TDM setup
cs43l83_headset_amp_format_setup(codec, 0, 1);
cs43l83_headset_amp_format_setup(codec, 1, 0);
//#8455: cs42l83_headset_play_setup_on
//#8455: cs42l83_configure_int_mclk
//#8727: cs42l83_power_onoff
//#8791: cs42l83_configure_serial_port
//#8951: cs42l83_output_set_input_sample_rate
//#9079: cs42l83_setup_audio_output
//#9255: cs42l83_buffers_onoff
cs42l83_headset_play_setup_on(codec);
//#9273: cs42l83_headphone_sense
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
if ((retval & 0x80))
{
//#9287: cs_8409_intmike_stream_conn_off_disable
//#9299: cs_8409_linein_stream_conn_off
cs_8409_intmike_stream_conn_off(codec);
cs_8409_linein_stream_conn_off(codec);
// snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
// snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
// snd_hda: conv stream channel map 35 [('CHAN', 0), ('STREAMID', 0)]
snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
//#9324: cs_8409_intmike_volume_setup
//#9357: cs_8409_intmike_format_setup_disable
//#9324: cs_8409_linein_volume_setup
//#9401: cs_8409_linein_format_setup_disable
//#9412: cs42l83_headset_mike_format_setup_enable
//#9451: cs42l83_input_set_output_sample_rate
//#9579: cs42l83_mike_setup_audio_input
//#9643: cs42l83_mike_enable
cs_8409_intmike_volume_setup(codec, 0x27);
cs_8409_intmike_format_setup_disable(codec);
cs_8409_linein_volume_setup(codec, 0x27);
cs_8409_linein_format_setup_disable(codec);
// as the following relates to the headset mike
// Im guessing we should only do it if we have a mike
// spec->have_mike should have been set above
// by the unsol response function cs_8409_headset_type_detect_event
if (spec->have_mike)
{
// this is part of cs_8409_enable_headset_mike_streaming
// whats missing is no actual cs42l83 power on calls
// or unmuting input
cs42l83_headset_mike_format_setup_enable(codec, 0, 1);
cs42l83_input_set_output_sample_rate(codec);
cs42l83_mike_setup_audio_input(codec);
cs42l83_mike_enable(codec);
// and disable it all!!
// this is part of cs_8409_disable_headset_mike_streaming
// as usual disabling this duplicate setup
//#9675: cs42l83_mike_disable
//#9705: cs42l83_headset_mike_format_setup_disable
//cs42l83_mike_disable(codec);
//cs42l83_headset_mike_format_setup_disable(codec);
//#9738: cs42l83_headset_mike_format_setup_enable
//#9738: cs42l83_headset_mike_format_setup_enable
//#9810: cs42l83_input_set_output_sample_rate
//#9938: cs42l83_mike_setup_audio_input
//#10002: cs42l83_mike_enable
// why duplicate setup - 1st dont set stream id/pin
// 2nd set stream id and pin
//cs42l83_headset_mike_format_setup_enable(codec, 0, 0);
//cs42l83_headset_mike_format_setup_enable(codec, 0, 1);
//cs42l83_input_set_output_sample_rate(codec);
//cs42l83_mike_setup_audio_input(codec);
//cs42l83_mike_enable(codec);
//// this doesnt make sense double read of nid 0x3c then double set??
//retval = snd_hda_codec_read_check(codec, 0x3c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000020, 25649); // 0x03cf0700
//retval = snd_hda_codec_read_check(codec, 0x3c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000020, 25650); // 0x03cf0700
//snd_hda_codec_write(codec, 0x3c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x03c70720
//// snd_hda: 60 ['AC_PINCTL_IN_EN']
//snd_hda_codec_write(codec, 0x3c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x03c70720
//// snd_hda: 60 ['AC_PINCTL_IN_EN']
// is this a good position to switch the inputs??
// just before enable buttons is where we switch inputs on plugin
// note that this is just telling Alsa the input source has changed
// - no changes to audio setup at all
switch_input_src(codec);
//#10040: cs_8409_headset_mike_buttons_enable
//#10040: cs42l83_configure_headset_button_interrupts
//#10088: cs42l83_enable_hsbias_auto_clamp_off2
//#10136: cs42l83_enable_hsbias_auto_clamp_on3
cs_8409_headset_mike_buttons_enable(codec);
// we get some calls to cs42l83_read_status_and_clear_interrupt/cs42l83_disambiguate_ur_from_int here
// clear out any stored unsol responses
// I think we need to block here - because clearing the interrupts causes interrupts!!
// this is similar to cs_8409_cs42l83_unsolicited_response where we block
// before calling the perform function
spec->block_unsol = 1;
cs_8409_perform_external_device_unsolicited_responses(codec);
spec->block_unsol = 0;
}
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot headphone REMOVED 6 - UNIMPLEMENTED!!\n");
}
spec->block_unsol = 0;
dev_info(hda_codec_dev(codec), "cs_8409_boot_setup_real boot CURRENT IMPLEMENTATION END!!\n");
}
else
{
// NOTE - OSX sets a stream format here but a null (ie 0) stream id
// on linux we set the OSX format - it will be updated with actual stream format later
//setup_TDM_6462(codec);
cs_8409_setup_TDM_amps12(codec, 1, 1);
//amps_enable2_6462(codec);
cs_8409_setup_amps12(codec, 0);
//setup_TDM_7472(codec);
cs_8409_setup_TDM_amps34(codec, 1);
//amps_enable2_7472(codec);
cs_8409_setup_amps34(codec, 0);
//sync_converters(codec);
cs_8409_sync_converters_on(codec, 1);
//sync_converters1(codec);
cs_8409_sync_converters_off(codec, 1);
//amps_disable_6462(codec);
cs_8409_disable_amps12(codec);
//putative_tdm_disable_6462(codec);
cs_8409_disable_TDM_amps12(codec);
//amps_disable_7472(codec);
cs_8409_disable_amps34(codec);
//putative_tdm_disable_7472(codec);
cs_8409_disable_TDM_amps34(codec);
// I think Im going to disable the following as we appear to have a stream id here
// but under linux we do not have a stream at all at this boot stage
if (0)
{
// this is not quite correct - cs_8409_setup_TDM_amps12 will write a null stream id etc
// but the actual logged version does not - although does update format
// this may be because Apple is caching the stream format/id similar to linux and
// at this point we have already set a null stream id - but because the above disable also
// cleared the format we get a re-setup of the the format
//putative_enable1_TDM_6462(codec);
cs_8409_setup_TDM_amps12(codec, 1, 1);
//amps_disable2_6462(codec);
cs_8409_disable_amps12(codec);
// see above notes for putative_enable1_TDM_6462
//putative_enable1_TDM_7472(codec);
cs_8409_setup_TDM_amps34(codec, 1);
//amps_disable2_7472(codec);
cs_8409_disable_amps34(codec);
// so this does not set the channel id for node 0x03 to 0x2 but cs_8409_sync_converters_on does
// is this significant??
// does suggest this function reads the initial stream id then rewrites at the end
//sync_converters2(codec);
cs_8409_sync_converters_on(codec, 1);
// so this also not quite same - we actually have a stream id here on OSX
// but at the boot stage dont think we have this in linux
//enable2_TDM2_6462(codec);
cs_8409_setup_TDM_amps12(codec, 1, 1);
//amps_enable2_6462(codec);
cs_8409_setup_amps12(codec, 0);
// see above
//enable2_TDM2_7472(codec);
cs_8409_setup_TDM_amps34(codec, 1);
//amps_enable2_7472(codec);
cs_8409_setup_amps34(codec, 0);
//sync_converters3(codec);
cs_8409_sync_converters_on(codec, 1);
// I dont get this - sync_converters3 sets the stream id/channel id to non-zero
// but here when we read the stream id/channel id its 0??
//sync_converters4(codec);
cs_8409_sync_converters_off(codec, 1);
//amps_disable3_6462(codec);
cs_8409_disable_amps12(codec);
//putative_disable3_TDM_6462(codec);
cs_8409_disable_TDM_amps12(codec);
//amps_disable3_7472(codec);
cs_8409_disable_amps34(codec);
//putative_disable3_TDM_7472(codec);
cs_8409_disable_TDM_amps34(codec);
}
// this is best guess what these volume functions are doing
// as from the log there is no change in output volume or muting
// - but if already unmuted thats what you would expect
//setup_mic_vol2(codec);
//setup_intmike_vol3(codec);
cs_8409_intmike_volume_unmute_nouse(codec);
//setup_linein_vol3(codec);
cs_8409_linein_volume_unmute_nouse(codec);
//setup_mic_vol3(codec);
//setup_intmike_vol4(codec);
cs_8409_intmike_volume_unmute_nouse(codec);
//setup_linein_vol4(codec);
cs_8409_linein_volume_unmute_nouse(codec);
//setup_mic_vol3(codec);
//setup_input_power_nids_off(codec);
cs_8409_inputs_power_nids_off(codec);
//read_gpio_status1(codec);
//read_gpio_status2(codec);
//read_gpio_status3(codec);
// why 3 reads here - they seem to return the exact same data each time
retval = read_gpio_status_check(codec);
retval = read_gpio_status_check(codec);
retval = read_gpio_status_check(codec);
//cs42l83_headphone_sense1(codec);
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 1 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
//setup_mic_vol4(codec);
//setup_intmike_vol5(codec);
cs_8409_intmike_volume_unmute_nouse(codec);
//setup_linein_vol5(codec);
cs_8409_linein_volume_unmute_nouse(codec);
//setup_mic_vol5(codec);
//setup_intmike_vol6(codec);
cs_8409_intmike_volume_unmute_nouse(codec);
//setup_linein_vol6(codec);
cs_8409_linein_volume_unmute_nouse(codec);
//cs42l83_headphone_sense2(codec);
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 2 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
//cs42l83_headphone_sense3(codec);
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_boot_setup_real headphone sense 3 0x%x %s\n", retval, ((retval & 0x80)?"plugged in":"not plugged in"));
//setup_intmike_nid1(codec);
//cs_8409_intmike_format_setup_format_nouse(codec);
//cs_8409_really_update_stream_format(codec, 0x22, 1, 0, 0);
cs_8409_really_update_stream_format(codec, spec->intmike_adc_nid, 1, 0, 0);
//setup_linein_vol7(codec);
cs_8409_linein_volume_setup(codec, 0x27);
//setup_linein_nid1(codec);
cs_8409_linein_format_setup_disable(codec);
//setup_intmike_stream_conn_off_nid1(codec);
cs_8409_intmike_stream_conn_off(codec);
//setup_linein_stream_conn_off_nid1(codec);
cs_8409_linein_stream_conn_off(codec);
//setup_intmike_stream_off_nid1(codec);
cs_8409_intmike_stream_off_nid(codec);
//setup_linein_stream_off_nid1(codec);
cs_8409_linein_stream_off_nid(codec);
//setup_intmike_vol10(codec);
//cs_8409_volume_set(codec, 0x22, 0x33);
cs_8409_volume_set(codec, spec->intmike_adc_nid, 0x33);
//setup_linein_vol10(codec);
//cs_8409_volume_set(codec, 0x23, 0x33);
cs_8409_volume_set(codec, spec->linein_amp_nid, 0x33);
}
mycodec_info(codec, "command cs_8409_boot_setup_real end\n");
return 0;
}
static void cs_8409_play_real(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// so I have seen an UNSOL response in cs_8409_playstop_real
// which suggests need to block responses here
spec->block_unsol = 1;
//cs_8409_play_data(codec);
mycodec_info(codec, "command cs_8409_play_real start");
retval = snd_hda_codec_read_check(codec, 0x00, 0, AC_VERB_PARAMETERS, 0x00000000, 0x10138409, 1); // 0x000f0000
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x00170500
hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
play_setup_TDM_amps12(codec, 1);
play_setup_amps12(codec);
play_setup_TDM_amps34(codec);
play_setup_amps34(codec);
play_sync_converters_on(codec);
cs_8409_perform_external_device_unsolicited_responses(codec);
spec->block_unsol = 0;
mycodec_info(codec, "command cs_8409_play_real end");
}
static void cs_8409_amps_disable_streaming(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "cs_8409_amps_disable_streaming start\n");
playstop_sync_converters_off(codec);
playstop_disable_amps12(codec);
playstop_disable_TDM_amps12(codec);
playstop_disable_amps34(codec);
playstop_disable_TDM_amps34(codec);
// for some reason Apple duplicates the amp disable here??
playstop_disable_amps12(codec);
playstop_disable_amps34(codec);
mycodec_info(codec, "cs_8409_amps_disable_streaming end\n");
}
static void cs_8409_playstop_real(struct hda_codec *codec)
{
//int retval;
struct cs8409_apple_spec *spec = codec->spec;
// so I have seen an UNSOL response in cs_8409_playstop_real
// which suggests need to block responses here
spec->block_unsol = 1;
mycodec_info(codec, "command cs_8409_playstop_real start");
//cs_8409_playstop_data(codec);
cs_8409_amps_disable_streaming(codec);
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x00170503
hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D3);
// weird - why set the inputs to powered off when stop playing??
cs_8409_inputs_power_nids_off(codec);
cs_8409_perform_external_device_unsolicited_responses(codec);
spec->block_unsol = 0;
mycodec_info(codec, "command cs_8409_playstop_real end");
}
static void cs_8409_capture_real(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// so I have seen an UNSOL response in cs_8409_playstop_real
// which suggests need to block responses here
spec->block_unsol = 1;
//cs_8409_capture_data(codec);
mycodec_info(codec, "command cs_8409_capture_real start");
retval = snd_hda_codec_read_check(codec, 0x00, 0, AC_VERB_PARAMETERS, 0x00000000, 0x10138409, 1); // 0x000f0000
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x00170500
hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
// NOTE - there are big ordering issues here
// - here we setup the speaker output before the internal mike
// - this maybe because Quicktime defaults to enabling play when recording
// unfortunately looks as tho linux tends to open the capture stream before the playback stream
// - so going to ignore this here
cs_8409_inputs_power_nids_on(codec);
//cs_8409_intmike_format_setup_format(codec);
cs_8409_intmike_format_setup_enable(codec, 0x4031, 0);
cs_8409_intmike_volume_setup(codec, 0x27);
cs_8409_intmike_stream_on_nid(codec);
cs_8409_intmike_volume_unmute(codec);
cs_8409_linein_volume_unmute(codec);
// so here we get AMP_GAIN_MUTE setups but nothing changes
// - so either this is a volume update with no change or unmute with no change
// - which to do with??
//cs_8409_intmike_volume_setup - (no change)
//cs_8409_linein_volume_setup - (no change)
cs_8409_perform_external_device_unsolicited_responses(codec);
spec->block_unsol = 0;
mycodec_info(codec, "command cs_8409_capture_real end");
}
static void cs_8409_intmike_stream_reset_nid_on(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// OK dont get this - we turn the stream back on for the internal mike
// - but assume pin is OK??
// now think these 2 functions are resetting to original state - which happens
// to be stream on for intmike and stream off for linein
// NOT PROPERLY FUNCTIONAL YET!!!!!
// retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000000, 23); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x02270610
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x02270610
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 1)]
}
static void cs_8409_linein_stream_reset_nid_off(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// OK dont get this - we turn the stream off for the linein
// - but assume pin is OK??
// retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000000, 25); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02370600
// snd_hda: conv stream channel map 35 [('CHAN', 0), ('STREAMID', 0)]
}
static void cs_8409_capturestop_real(struct hda_codec *codec)
{
//int retval;
struct cs8409_apple_spec *spec = codec->spec;
// so I have seen an UNSOL response in cs_8409_playstop_real
// which suggests need to block responses here
spec->block_unsol = 1;
mycodec_info(codec, "command cs_8409_capturestop_real start");
//cs_8409_capturestop_data(codec);
cs_8409_intmike_stream_conn_off(codec);
cs_8409_linein_stream_conn_off(codec);
// this I think is re-setting to pre-capture state
// THIS NEEDS FIXING!!!
cs_8409_intmike_stream_reset_nid_on(codec);
cs_8409_linein_stream_reset_nid_off(codec);
cs_8409_intmike_volume_set(codec, 0x27);
cs_8409_intmike_volume_mute(codec);
// we also reset the pin - however no change to volume or unmute
// so cant say if should just set unmute or set volume to 0
// just choosing one
//cs_8409_volume_set(codec, 0x44, 0x00);
cs_8409_volume_set(codec, spec->intmike_nid, 0x00);
cs_8409_intmike_format_setup_disable(codec);
cs_8409_linein_volume_set(codec, 0x27);
cs_8409_linein_volume_mute(codec);
// we also reset the pin - however no change to volume or unmute
// so cant say if should just set unmute or set volume to 0
// just choosing one
//cs_8409_volume_set(codec, 0x45, 0x00);
cs_8409_volume_set(codec, spec->linein_nid, 0x00);
cs_8409_linein_format_setup_disable(codec);
cs_8409_inputs_power_nids_off(codec);
// using Quicktime we get a play disable when we stop recording
//cs_8409_sync_converters_off
//cs_8409_disable_amps12
//cs_8409_disable_TDM_amps12
//cs_8409_disable_amps34
//cs_8409_disable_TDM_amps34
//cs_8409_disable_amps12
//cs_8409_disable_amps34
cs_8409_perform_external_device_unsolicited_responses(codec);
spec->block_unsol = 0;
mycodec_info(codec, "command cs_8409_capturestop_real end");
}
// this is the function which handles unsolicited responses
// - which seem to be enabled by default on the 8409 and set to be from GPIO pin 1
// which seems to be handling the cs42l83
static int cs_8409_read_status_and_clear_interrupt(struct hda_codec *codec);
static int cs42l83_disambiguate_ur_from_int(struct hda_codec *codec);
static void cs_8409_interrupt_action(struct hda_codec *codec, int int_response);
static void cs_8409_external_device_unsolicited_response(struct hda_codec *codec)
{
int retval;
int retval_int;
int ret_disambig;
int int_response;
int int_masked;
int intcnt = 0;
retval = read_gpio_status_check(codec);
if ((retval & 0x01) == 0x01)
{
mycodec_info(codec, "cs_8409_external_device_unsolicited_response - interrupt clear\n");
return;
}
mycodec_info(codec, "cs_8409_external_device_unsolicited_response - interrupt set\n");
// so retval_int is a bit shifted combination of a number of primary interrupt status registers
retval_int = cs_8409_read_status_and_clear_interrupt(codec);
// and ret_disambig is the same bit shifted combination of a number of primary interrupt mask registers
ret_disambig = cs42l83_disambiguate_ur_from_int(codec);
// move prints to after so not spaced by other prints
codec_info(codec, "cs_8409_external_device_unsolicited_response - UNSOL interrupt 0x%08x\n",retval_int);
codec_info(codec, "cs_8409_external_device_unsolicited_response - UNSOL disambig 0x%08x\n",ret_disambig);
// determine masked interrupts
int_masked = (ret_disambig & retval_int);
codec_info(codec, "cs_8409_external_device_unsolicited_response - UNSOL masked 0x%08x\n",int_masked);
// determine unmasked interrupts
int_response = ((~ret_disambig) & retval_int);
codec_info(codec, "cs_8409_external_device_unsolicited_response - UNSOL unmasked 0x%08x\n",int_response);
intcnt = hweight_long(int_response);
codec_info(codec, "cs_8409_external_device_unsolicited_response - UNSOL number interrupt actions %d\n", intcnt);
// do we call a mapping function here??
if (int_response != 0) {
cs_8409_interrupt_action(codec, int_response);
}
else
codec_info(codec, "cs_8409_external_device_unsolicited_response - UNSOL NO unmasked interrupt\n");
return;
}
static int cs42l83_read_status_and_clear_interrupt(struct hda_codec *codec);
static int cs_8409_read_status_and_clear_interrupt(struct hda_codec *codec)
{
int retval = 0;
int retint = 0;
int last_retint = 0;
int loopmax = 11;
int loopcnt = 0;
// AppleHDAFunctionGroupCS8409::readStatusAndClearInterrupt
mycodec_info(codec, "cs_8409_read_status_and_clear_interrupt start\n");
retval = read_gpio_status_check(codec);
if ((retval & 0x01) == 0x01)
{
mycodec_info(codec, "cs_8409_read_status_and_clear_interrupt - interrupt %d clear\n",loopcnt);
return 0;
}
// so this function causes an unsol response because of clearing the interrupt
// what this means is we need to add a check in the unsol response callbacks
// to ignore GPIO 1 changes from 0 to 1 - 1 seems to be the default
// and a 1 to 0 transition means interrupt has been triggered
while (1)
{
retint = cs42l83_read_status_and_clear_interrupt(codec);
codec_info(codec, "cs_8409_read_status_and_clear_interrupt - UNSOL status 0x%08x\n",retint);
retval = read_gpio_status_check(codec);
if (loopcnt >= loopmax)
{
dev_info(hda_codec_dev(codec), "cs_8409_read_status_and_clear_interrupt - ERROR - max count exceeded\n");
break;
}
loopcnt++;
if ((retval & 0x01) == 0x01)
{
codec_info(codec, "cs_8409_read_status_and_clear_interrupt - interrupt %d clear\n",loopcnt);
break;
}
last_retint = retint;
// so this code definitely has a 10 IOSleep sleep call ie 10 ms
// but from the logs it is much closer to 50 ms
// IOSleep(10);
//usleeprange(10000,12000);
msleep(10);
}
codec_info(codec, "cs_8409_read_status_and_clear_interrupt 0x%08x end\n",retint);
return retint;
}
static int cs42l83_read_status_and_clear_interrupt(struct hda_codec *codec)
{
int retval;
int retval_det1;
int retval_det2;
int retval_cdc;
// AppleHDATDM_CS42L83::readStatusAndClearInterrupt
// so I think Ive finally figured whats going on with interrupts and the 8409
// cs42l83 interrupts trigger a state change on GPIO pin 1 which is set to
// trigger an Unsolicited Response (UR) (enableGPIforUR function)
// so we get a UR from high(1) (default) to low(0) when the interrupt is set
// plus a UR from low(0) to high(1) when the interrupt is cleared
// interrupt clearing seems to be triggered by reading registers in this routine (hence the name)
// Im now pretty certain 0x1b7b and 0x1b7c indicate which interrupt of
// 0x1b79 and 0x1b7a (Detect Interrupt Mask 1 and Detect Interrupt Mask 2)
// was triggered
// Im suspecting the 0x1b7b (maybe 0x1b7c) which are undocumented
// - the other registers seem to be flagged as status registers
// 0x1b7b is listed in figure 4-45 as an interrupt register but otherwise undocumented!!
// moved to above
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x00170500
hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
// note that a lot of i2cPagedRead followed by i2cPagedWrite are likely AppleHDATDMDevice::maskWriteReg
// ie read from register and mask of bits and set certain bits without affecting others
// we do not know the mask being used from the HDA commands!!
// finally know what ASP refers to in lot of Cirrus docs - Audio Serial Port
// register 0x1b7b - this is undocumented for 42l42 but labelled in fig 4-45 as Detect Interrupt 1 Status
// Detect Interrupt 1 Status
// value 0x40 (TIP_SENSE_PLUG interrupt from 0xa0 TIP_SENSE_PLUG unmasked)
// register 0x1b7c - this is undocumented for 42l42 (reserved)
// Detect Interrupt 2 Status
// value 0x00 (none ie inverse of 0xff state of 0x1b7a)
// register 0x1308 - Codec Interrupt Status
// value 0x01 - Headset disabled, Powered down
// register 0x1301 - ADC Overflow Interrupt Status
// register 0x1302 - Mixer Interrupt Status
// register 0x1303 - SRC Interrupt Status
// register 0x1304 - ASP RX Interrupt Status
// register 0x1305 - ASP TX Interrupt Status
// register 0x130b - SRC Partial Lock Interrupt Status
// register 0x130d - VP Monitor Interrupt Status
// register 0x130e - PLL Lock Interrupt Status
// register 0x130f - Tip/Ring Sense Plug/Unplug Interrupt Status
// value 0x00
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7b00 i2c data 0x7b40
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7c00 i2c data 0x7c00
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0800 i2c data 0x0801
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0100 i2c data 0x0100
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0200 i2c data 0x0200
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0300 i2c data 0x030c
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0400 i2c data 0x0400
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0500 i2c data 0x0500
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0b00 i2c data 0x0b60
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0d00 i2c data 0x0d01
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0e00 i2c data 0x0e00
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0f00 i2c data 0x0f00
mycodec_info(codec, "cs42l83_read_status_and_clear_interrupt start\n");
// note that these functions contain power on/power off calls
retval_det1 = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b7b, 1); // snd_hda
retval_det2 = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b7c, 1); // snd_hda
retval_cdc = cs_8409_vendor_i2cRead(codec, 0x90, 0x1308, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x1301, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x1302, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x1303, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x1304, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x1305, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x130b, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x130d, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x130e, 1); // snd_hda
cs_8409_vendor_i2cRead(codec, 0x90, 0x130f, 1); // snd_hda
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x00170503
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D3);
mycodec_info(codec, "cs42l83_read_status_and_clear_interrupt end\n");
retval = 0;
retval = ((retval_det1 & 0xff) << 16) | ((retval_det2 & 0xff) << 8) | (retval_cdc & 0xff);
return retval;
}
static int cs42l83_disambiguate_ur_from_int(struct hda_codec *codec)
{
int retval_det1;
int retval_det2;
int retval_cdc;
int retval;
// from AppleHDAFunctionGroupCS8409::externalDeviceUnsolicitedResponse
// AppleHDATDM_CS42L83::disambiguateURfromINT
//snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x00170500
hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
// register 0x1b79 - Detect Interrupt Mask 1
// value 0xa0 TIP_SENSE_PLUG unmasked
// register 0x1b7a - Detect Interrupt Mask 2
// value 0xff all masked
// register 0x131b - Codec Interrupt Mask
// value 0x3 all masked
mycodec_info(codec, "cs42l83_disambiguate_ur_from_int start\n");
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7900 i2c data 0x79a0
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x1b lo 0x7a00 i2c data 0x7aff
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x1b00 i2c data 0x1b03
retval_det1 = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b79, 1); // snd_hda
retval_det2 = cs_8409_vendor_i2cRead(codec, 0x90, 0x1b7a, 1); // snd_hda
retval_cdc = cs_8409_vendor_i2cRead(codec, 0x90, 0x131b, 1); // snd_hda
mycodec_info(codec, "cs42l83_disambiguate_ur_from_int end\n");
// there is a bunch of code here presumably figuring out what happened
retval = 0;
retval = ((retval_det1 & 0xff) << 16) | ((retval_det2 & 0xff) << 8) | (retval_cdc & 0xff);
return retval;
}
static void cs42l83_set_power_state_on(struct hda_codec *codec, int instate)
{
int retval;
int loopcnt;
mycodec_info(codec, "cs42l83_set_power_state_on start\n");
// likely in AppleHDATDM_CS42L83::enable
// (only place AppleHDATDM_CS42L83::setPowerState is called from is AppleHDATDM_CS42L83::enable)
// AppleHDATDM_CS42L83::setPowerState
// register 0x1101 - Power Down Control 1
// register 0x130b - SRC Partial Lock Interrupt Status
// seems to me this powers on either the input path ie mike (instate=1)
// or output path ie headphones (instate=0)
// I think that the use of cs_8409_vendor_i2cWriteMask means that we can
// call this function multiple times and set both input and output power on
// because only the bits in the mask are affected
// codec headphone (digital in/audio out)
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x11 lo 0x0100 i2c data 0x01fe
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x11 lo 0x019e i2c data 0x009e
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0b00 i2c data 0x0b60
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x11 lo 0x0100 i2c data 0x019e
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x11 lo 0x0196 i2c data 0x0096
// codec capture (audio in/digital out)
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x11 lo 0x0100 i2c data 0x0196
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x11 lo 0x0116 i2c data 0x0016
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x13 lo 0x0b00 i2c data 0x0b24
// snd_hda i2cPagedRead i2c address 0x90 i2c reg hi 0x11 lo 0x0100 i2c data 0x0116
// snd_hda i2cPagedWrite i2c address 0x90 i2c reg hi 0x11 lo 0x0112 i2c data 0x0012
if (instate)
{
// power setup for codec (0x01) and output (0x80)
// this converts 0xfe to 0x7e (or 0x96 to 0x16)
cs_8409_vendor_i2cWriteMask(codec, 0x90, 0x1101, 0x81, 0x0, 1); // snd_hda
loopcnt = 0;
while (loopcnt < 0x14)
{
retval = cs_8409_vendor_i2cRead(codec, 0x90, 0x130b, 1); // snd_hda
if ((retval & 0x1) == 0x1)
break;
loopcnt++;
// IOSleep(2);
msleep(2);
}
// power setup for ADC (0x04)
// this converts 0x7e to 0x7a (or 0x16 to 0x12)
cs_8409_vendor_i2cWriteMask(codec, 0x90, 0x1101, 0x04, 0x0, 1); // snd_hda
}
else
{
// power setup for codec (0x01), input (0x40) and mixer (0x20)
//cs_8409_vendor_i2cRead(codec, 0x90, 0x1101, 1); // snd_hda
//cs_8409_vendor_i2cWrite(codec, 0x90, 0x1101, 0x009e, 1); // snd_hda
// this converts 0xfe to 0x9e
cs_8409_vendor_i2cWriteMask(codec, 0x90, 0x1101, 0x61, 0x0, 1); // snd_hda
loopcnt = 0;
while (loopcnt < 0x14)
{
retval = cs_8409_vendor_i2cRead(codec, 0x90, 0x130b, 1); // snd_hda
if ((retval & 0x4) == 0x4)
break;
loopcnt++;
// IOSleep(2);
msleep(2);
}
// power setup for headphone (0x08)
//cs_8409_vendor_i2cRead(codec, 0x90, 0x1101, 1); // snd_hda
//cs_8409_vendor_i2cWrite(codec, 0x90, 0x1101, 0x0096, 1); // snd_hda
// this converts 0x9e to 0x96
cs_8409_vendor_i2cWriteMask(codec, 0x90, 0x1101, 0x08, 0x0, 1); // snd_hda
}
mycodec_info(codec, "cs42l83_set_power_state_on end\n");
}
static void cs42l83_headset_amp_setup_TDM_sample_rate(struct hda_codec *codec)
{
// snd_hda: # AppleHDATDMBusManagerCS8409::setSampleRate:
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0001, 0x0200, 0xffff, 0x00000200, 0, 3892 ); // coef write mask 3892
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0008, 0x0042, 0xffff, 0x00000040, 0, 3898 ); // coef write mask 3898
//snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0007, 0x10ff, 0xffff, 0x000010ff, 0, 3904 ); // coef write mask 3904
// we need to use proper masked versions here - in particular for register 1 which seems to be enabling the Audio Serial Port
// for the subsystems and bits 0x7f need to pass thro here
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0001, 0x0200, 0x0380, 0x00000200, 0, 0 ); // coef write mask 25
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0008, 0x0042, 0x0007, 0x00000040, 0, 0 ); // coef write mask 3898
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0007, 0x10ff, 0x01ff, 0x000010ff, 0, 0 ); // coef write mask 3904
}
static void cs42l83_headset_amp_setup_TDM_proper(struct hda_codec *codec, int full)
{
//int retval;
int ret_coef0 = 0;
int new_coef0 = 0;
int ret_coef1 = 0;
int new_coef1 = 0;
int ret_coef71 = 0;
int new_coef71 = 0;
if (full)
{
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000200, 0 ); // coef read 3810
new_coef1 = (ret_coef1 & 0xffff); // not clear what this is setting - no difference between read and write so far
// however if used in different places the actual value may be different
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_amp_setup_TDM_proper coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0200, 0x00000000, 3814 ); // coef write 3814
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 3814 ); // coef write 3814
}
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0015, 0xaaaa, 0xffff, 0x0000aaaa, 0, 0 ); // coef write mask 3819
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0014, 0x0100, 0xffff, 0x00000000, 0, 0 ); // coef write mask 3825
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0029, 0x0000, 0x00008000, 0 ); // coef read 3832
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0029, 0x0800, 0x00000000, 0 ); // coef write 3836
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x002a, 0x0000, 0x00008000, 0 ); // coef read 3840
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x002a, 0x0820, 0x00000000, 0 ); // coef write 3844
if (full)
{
ret_coef0 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0000, 0x0000, 0x00009000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 3848
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, 0xb000, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 3852
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0007, 0x0000, 0x000028ff, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef read 3856
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0007, 0x10ff, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 3860
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, 0xb000, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 3864
// NOTA BENE - here we update from 0x9000 to 0xb000 - which is then never removed - even after unplugging headphones!!
new_coef0 = ret_coef0 | 0x2000;
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0000, new_coef0, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::setupTDMPath coef write 76
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0006, 0x8000, 0xffff, 0x00008000, 0, 0 ); // coef write mask 3868
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0008, 0x0040, 0xffff, 0x00000000, 0, 0 ); // coef write mask 3874
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0xa801, 0xffff, 0x00000001, 0, 3880 ); // coef write mask 3880
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0xa800, 0x0000, 0x00000001, 0xa801, 0 ); // coef write mask 3880
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0002, 0x0280, 0xffff, 0x00000280, 0, 0 ); // coef write mask 3886
cs42l83_headset_amp_setup_TDM_sample_rate(codec);
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000200, 0 ); // coef read 3910
new_coef1 = (ret_coef1 & 0xffff) | 0x40;
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_amp_setup_TDM_proper coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0240, 0x00000000, 3914 ); // coef write 3914
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 0 ); // coef write 3914
}
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 3918 ); // coef read 3918
tdm_in_use(codec, 1);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 3987
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 3991
new_coef71 = (ret_coef71 & 0xffff) | 0x800f;
myprintk_dbg("snd_hda_intel: masked play_setup_TDM_proper_full_headphone coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x800f, 0x00000000, 3995 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 3995
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, new_coef71, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 3995
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 3998
}
static void cs43l83_headset_amp_format_setup(struct hda_codec *codec, int set_stream_id, int full)
{
int retval;
mycodec_info(codec, "cs43l83_headset_amp_format_setup set_stream_id %d full %d\n", set_stream_id, full);
//snd_hda_codec_write(codec, 0x0a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x00a24031
// snd_hda: stream format 10 [('CHAN', 2), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
if (set_stream_id)
{
//snd_hda_codec_write(codec, 0x0a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x00a70610
// snd_hda: conv stream channel map 10 [('CHAN', 0), ('STREAMID', 1)]
// using the stored stream parameters update nid 0x0a stream parameters
// we have limited the allowed formats so should only have working formats here
cs_8409_really_update_stream_format(codec, 0x0a, 1, 2, 0);
} else {
snd_hda_codec_write(codec, 0x0a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00a70600
}
//cs42l83_headset_amp_setup_TDM_proper_full(codec);
cs42l83_headset_amp_setup_TDM_proper(codec, full);
retval = snd_hda_codec_read_check(codec, 0x2c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x02cf0700
snd_hda_codec_write(codec, 0x2c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x000000c0); // 0x02c707c0
// snd_hda: 44 ['AC_PINCTL_OUT_EN', 'AC_PINCTL_HP_EN']
}
static void cs_8409_headset_amp_disable_TDM_proper(struct hda_codec *codec, int full)
{
int retval;
int ret_coef1 = 0;
int new_coef1 = 0;
int ret_coef71 = 0;
int new_coef71 = 0;
// AppleHDATDMBusManagerCS8409::disableTDMPath
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0029, 0x0000, 0x00000800, 0 ); // coef read 2411
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0029, 0x8800, 0x00000000, 0 ); // coef write 2415
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x002a, 0x0000, 0x00000820, 0 ); // coef read 2419
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x002a, 0x8820, 0x00000000, 0 ); // coef write 2423
if (full)
{
// AppleHDATDMBusManagerCS8409::disableTDMPath
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x0001, 0xffff, 0x0000a801, 0, 2185 ); // coef write mask 2185
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x0000, 0xa800, 0x0000a801, 0x0001, 0 ); // coef write mask 2185
// AppleHDATDMBusManagerCS8409::disableTDMPath
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000240, 0 ); // AppleHDATDMBusManagerCS8409::disableTDMPath coef read 2191
new_coef1 = (ret_coef1 & 0xffbf); // clear our 0x40 bit
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_amp_disable_TDM_proper coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0200, 0x00000000, 2195 ); // AppleHDATDMBusManagerCS8409::disableTDMPath coef write 2195
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::disableTDMPath coef write 2195
}
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 2427 ); // coef read 2427
tdm_in_use(codec, 301);
if (full)
{
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x00000000, 0 ); // coef write 2452
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00000000);
}
else
{
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 2624
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000800f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 2628
new_coef71 = (ret_coef71 & 0xffff); // why doesnt this really disable this here??
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_amp_disable_TDM_proper coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x800f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 2632
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 2635
}
}
static void cs_8409_headset_amp_format_setup_disable(struct hda_codec *codec, int full)
{
int retval;
mycodec_info(codec, "cs_8409_headset_amp_format_setup_disable full %d\n", full);
cs_8409_headset_amp_disable_TDM_proper(codec, full);
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
snd_hda_codec_write(codec, 0x0a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x00a70600
// snd_hda: conv stream channel map 10 [('CHAN', 0), ('STREAMID', 0)]
snd_hda_codec_write(codec, 0x0a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x00a20000
// snd_hda: stream format 10 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
retval = snd_hda_codec_read_check(codec, 0x2c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000040, 0); // 0x02cf0700
snd_hda_codec_write(codec, 0x2c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x02c70700
// snd_hda: 44 []
}
static void cs42l83_headset_mike_format_setup_enable(struct hda_codec *codec, int nullformat, int full)
{
int retval = 0;
int ret_coef71 = 0;
int new_coef71 = 0;
//snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x01a24031
// snd_hda: stream format 26 [('CHAN', 2), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x01a70610
// snd_hda: conv stream channel map 26 [('CHAN', 0), ('STREAMID', 1)]
if (nullformat)
{
// note that 0x4031 is Apples fixed format - but this is for plugin stage when we have
// not defined any format yet so just use it - we overwrite below when actually play
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x01a24031
if (full)
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x01a70610
}
else
{
if (full)
cs_8409_really_update_stream_format(codec, 0x1a, 1, 2, 0);
else
cs_8409_really_update_stream_format(codec, 0x1a, 1, 0, 0);
}
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0012, 0xaccc, 0xffff, 0x0000cccc, 0, 0 ); // coef write mask 12272
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0011, 0x0001, 0xffff, 0x00000000, 0, 0 ); // coef write mask 12278
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0049, 0x0000, 0x00008000, 0 ); // coef read 12285
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0049, 0x0800, 0x00000000, 0 ); // coef write 12289
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x004a, 0x0000, 0x00008000, 0 ); // coef read 12293
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x004a, 0x0820, 0x00000000, 0 ); // coef write 12297
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 12301 ); // coef read 12301
tdm_in_use(codec, 201);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 12370
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000800f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 12374
new_coef71 = (ret_coef71 & 0xffff);
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_mike_format_setup_enable coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x800f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 12378
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 12381
if (full)
{
retval = snd_hda_codec_read_check(codec, 0x3c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x03cf0700
snd_hda_codec_write(codec, 0x3c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x03c70720
// snd_hda: 60 ['AC_PINCTL_IN_EN']
}
}
static void cs42l83_headset_mike_format_setup_disable(struct hda_codec *codec)
{
int retval = 0;
int ret_coef71 = 0;
int new_coef71 = 0;
// snd_hda: # AppleHDATDMBusManagerCS8409::disableTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0049, 0x0000, 0x00000800, 0 ); // coef read 13141
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0049, 0x8800, 0x00000000, 0 ); // coef write 13145
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x004a, 0x0000, 0x00000820, 0 ); // coef read 13149
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x004a, 0x8820, 0x00000000, 0 ); // coef write 13153
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 13157 ); // coef read 13157
tdm_in_use(codec, 202);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13226
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000800f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 13230
new_coef71 = (ret_coef71 & 0xffff);
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_mike_format_setup_disable coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x800f, 0x00000000, 13234 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13234
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, new_coef71, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13234
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 13237
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x01a70600
// snd_hda: conv stream channel map 26 [('CHAN', 0), ('STREAMID', 0)]
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x01a20000
// snd_hda: stream format 26 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
retval = snd_hda_codec_read_check(codec, 0x3c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000020, 0); // 0x03cf0700
snd_hda_codec_write(codec, 0x3c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x03c70700
// snd_hda: 60 []
}
// NOTE - the following routines NOT fixed up yet - currently not used!!
static void cs42l83_headset_mike_format_setup_enable1(struct hda_codec *codec)
{
//int retval = 0;
//snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x01a24031
// snd_hda: stream format 26 [('CHAN', 2), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
cs_8409_really_update_stream_format(codec, 0x1a, 1, 0, 0);
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0012, 0xaccc, 0xffff, 0x0000accc, 0, 0 ); // coef write mask 13249
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0011, 0x0001, 0xffff, 0x00000001, 0, 0 ); // coef write mask 13255
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0049, 0x0000, 0x00008800, 0 ); // coef read 13262
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0049, 0x0800, 0x00000000, 0 ); // coef write 13266
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x004a, 0x0000, 0x00008820, 0 ); // coef read 13270
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x004a, 0x0820, 0x00000000, 0 ); // coef write 13274
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 13278 ); // coef read 13278
tdm_in_use(codec, 203);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13347
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000800f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 13351
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x800f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13355
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 13358
}
static void cs42l83_headset_mike_format_setup_enable1a(struct hda_codec *codec)
{
//int retval = 0;
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x01a24031
// snd_hda: stream format 26 [('CHAN', 2), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0012, 0xaccc, 0xffff, 0x0000accc, 0, 0 ); // coef write mask 13249
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0011, 0x0001, 0xffff, 0x00000001, 0, 0 ); // coef write mask 13255
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0049, 0x0000, 0x00008800, 0 ); // coef read 13262
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0049, 0x0800, 0x00000000, 0 ); // coef write 13266
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x004a, 0x0000, 0x00008820, 0 ); // coef read 13270
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x004a, 0x0820, 0x00000000, 0 ); // coef write 13274
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 13278 ); // coef read 13278
tdm_in_use(codec, 203);
}
static void cs42l83_headset_mike_format_setup_enable1b(struct hda_codec *codec)
{
int retval = 0;
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004031); // 0x01a24031
// snd_hda: stream format 26 [('CHAN', 2), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000010); // 0x01a70610
// snd_hda: conv stream channel map 26 [('CHAN', 0), ('STREAMID', 1)]
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0012, 0xaccc, 0xffff, 0x0000accc, 0, 0 ); // coef write mask 13368
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0011, 0x0001, 0xffff, 0x00000001, 0, 0 ); // coef write mask 13374
// snd_hda: # AppleHDATDMBusManagerCS8409::setupTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0049, 0x0000, 0x00000800, 0 ); // coef read 13381
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0049, 0x0800, 0x00000000, 0 ); // coef write 13385
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x004a, 0x0000, 0x00000820, 0 ); // coef read 13389
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x004a, 0x0820, 0x00000000, 0 ); // coef write 13393
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00008800, 13397 ); // coef read 13397
tdm_in_use(codec, 204);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13466
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000800f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 13470
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0x800f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 13474
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 13477
retval = snd_hda_codec_read_check(codec, 0x3c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x03cf0700
snd_hda_codec_write(codec, 0x3c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x03c70720
// snd_hda: 60 ['AC_PINCTL_IN_EN']
}
// NOTE - end of unfixed routines
static void cs42l83_headset_amp_disable_and_mike_disable_TDM_proper(struct hda_codec *codec)
{
//int retval = 0;
int ret_coef1 = 0;
int new_coef1 = 0;
int ret_coef71 = 0;
int new_coef71 = 0;
// snd_hda: # AppleHDATDMBusManagerCS8409::disableTDMPath:
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0049, 0x0000, 0x00000800, 0 ); // coef read 10459
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0049, 0x8800, 0x00000000, 0 ); // coef write 10463
snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x004a, 0x0000, 0x00000820, 0 ); // coef read 10467
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x004a, 0x8820, 0x00000000, 0 ); // coef write 10471
// this section is actually disabling the headset amp TDM setup
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x5400, 0xffff, 0x0000fc00, 0, 10475 ); // coef write mask 10475
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0082, 0x0000, 0xa800, 0x0000fc00, 0x5400, 0 ); // coef write mask 10475
ret_coef1 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0001, 0x0000, 0x00000260, 0 ); // AppleHDATDMBusManagerCS8409::disableTDMPath coef read 10481
new_coef1 = (ret_coef1 & 0xffbf);
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_amp_disable_and_mike_disable_TDM_proper coef 0x01 update 0x%04x 0x%04x \n", ret_coef1, new_coef1);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, 0x0220, 0x00000000, 10485 ); // AppleHDATDMBusManagerCS8409::disableTDMPath coef write 10485
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0001, new_coef1, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::disableTDMPath coef write 10485
// end of section disabling the headset amp TDM setup
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR: AppleHDATDMBusManagerCS8409::tdmInUse:
//snd_hda_coef_item(codec, 0, CS8409_VENDOR_NID, 0x0019, 0x0000, 0x00000800, 10489 ); // coef read 10489
tdm_in_use(codec, 401);
// snd_hda: # AppleHDATDMBusManagerCS8409::configureTDMUR:
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x006c, 0x001f, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 10494
ret_coef71 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0071, 0x0000, 0x0000c00f, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef read 10498
new_coef71 = (ret_coef71 & 0xffff); // I dont get this - it doesnt seem to change this at all - but this is for output 0x800f (headphones) or 0x400f (amps)
myprintk_dbg("snd_hda_intel: masked cs42l83_headset_amp_disable_and_mike_disable_TDM_proper coef 0x71 update 0x%04x 0x%04x \n", ret_coef71, new_coef71);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, 0xc00f, 0x00000000, 10502 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 10502
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0071, new_coef71, 0x00000000, 0 ); // AppleHDATDMBusManagerCS8409::configureTDMUR coef write 10502
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, 0x7f0, 0x00b6 ); // AppleHDATDMBusManagerCS8409::configureTDMUR write verb 10505
}
static void cs42l83_headset_amp_disable_and_mike_format_setup_disable(struct hda_codec *codec)
{
int retval = 0;
cs42l83_headset_amp_disable_and_mike_disable_TDM_proper(codec);
// note this means the cached stream data in the hda_cvt_setup struct will now be inconsistent
// we need to ensure any further stream format re-update MUST be a forced update
// still not clear if should be calling eg __snd_hda_codec_cleanup_stream
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x01a70600
// snd_hda: conv stream channel map 26 [('CHAN', 0), ('STREAMID', 0)]
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_STREAM_FORMAT, 0x00000000); // 0x01a20000
// snd_hda: stream format 26 [('CHAN', 1), ('RATE', 48000), ('BITS', 8), ('RATE_MUL', 1), ('RATE_DIV', 1)]
retval = snd_hda_codec_read_check(codec, 0x3c, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000020, 0); // 0x03cf0700
snd_hda_codec_write(codec, 0x3c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000000); // 0x03c70700
// snd_hda: 60 []
}
static void cs_8409_linein_format_setup_enable(struct hda_codec *codec)
{
int retval;
int ret_coef9 = 0;
int new_coef9 = 0;
struct cs8409_apple_spec *spec = codec->spec;
// theres some weird issue here
// index 0x0009 has bit 0x0080 set only after an unplug event with headset with mike
// but then never seems to be turned off!!!
// 0x45 -> 0x23 is line input
// now updated to not write the Apple format but use my format setting routines
// (remember we have limited the allowed formats to acceptable ones)
// note that apparently we can set the format with the nid powered down but for setting the
// stream id the nid has to be powered up
// we may wish to ignore the power down here - because we reactivate the nid only a few steps
// later
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_STREAM_FORMAT, 0x00004033); // 0x02324033
// snd_hda: stream format 35 [('CHAN', 4), ('RATE', 44100), ('BITS', 24), ('RATE_MUL', 1), ('RATE_DIV', 1)]
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10555); // 0x023f0500
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02370500
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 10558); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D0);
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000012); // 0x02370612
// snd_hda: conv stream channel map 35 [('CHAN', 2), ('STREAMID', 1)]
// using the stored stream parameters update nid 0x23 stream parameters
// we have limited the allowed formats so should only have working formats here
//cs_8409_really_update_stream_format(codec, 0x23, 1, 1, 0);
cs_8409_really_update_stream_format(codec, spec->linein_amp_nid, 1, 1, 0);
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02370503
//retval = snd_hda_codec_read_check(codec, 0x23, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10561); // 0x023f0500
hda_set_node_power_state(codec, spec->linein_amp_nid, AC_PWRST_D3);
// snd_hda: # AppleHDAWidgetCS8409::setConnectionSelect:
ret_coef9 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0009, 0x0000, 0x000000b3, 0 ); // AppleHDAWidgetCS8409::setConnectionSelect coef read 10563
//new_coef9 = ret_coef9 | 0x80; // I dont get this bit set - see above
new_coef9 = ret_coef9 | spec->reg9_linein_dmic_mo; // I dont get this bit set - see above
myprintk_dbg("snd_hda_intel: masked cs_8409_linein_format_setup_enable coef 0x09 update 0x%04x 0x%04x \n", ret_coef9, new_coef9);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0009, 0x00b3, 0x00000000, 10567 ); // AppleHDAWidgetCS8409::setConnectionSelect coef write 10567
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0009, new_coef9, 0x00000000, 0 ); // AppleHDAWidgetCS8409::setConnectionSelect coef write 10567
//snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL, 0x00000000); // 0x02370100
snd_hda_codec_write(codec, spec->linein_amp_nid, 0, AC_VERB_SET_CONNECT_SEL, 0x00000000); // 0x02370100
}
static void cs_8409_linein_stream_on_nid(struct hda_codec *codec)
{
int retval;
int reg_coef82 = 0;
int new_coef82 = 0;
struct cs8409_apple_spec *spec = codec->spec;
reg_coef82 = snd_hda_coef_item_check(codec, 0, CS8409_VENDOR_NID, 0x0082, 0x0000, 0x00005401, 0 ); // coef read 10584
//new_coef82 = (reg_coef82 | 0x2);
new_coef82 = (reg_coef82 | spec->reg82_linein_dmic_scl);
myprintk_dbg("snd_hda_intel: masked cs_8409_linein_stream_on_nid coef 0x0082 update 0x%04x 0x%04x \n", reg_coef82, new_coef82);
//snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, 0x5403, 0x00000000, 10588 ); // coef write 10588
snd_hda_coef_item(codec, 1, CS8409_VENDOR_NID, 0x0082, new_coef82, 0x00000000, 10588 ); // coef write 10588
//retval = snd_hda_codec_read_check(codec, 0x45, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x045f0700
retval = snd_hda_codec_read_check(codec, spec->linein_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00000000, 0x00000000, 0); // 0x045f0700
snd_hda_codec_write(codec, spec->linein_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x04570720
//snd_hda_codec_write(codec, 0x45, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00000020); // 0x04570720
// snd_hda: 69 ['AC_PINCTL_IN_EN']
}
static void cs_8409_intmike_stream_conn_off_disable(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// more weird issue here
// index 0x0009 has bit 0x0100 set only after an unplug event with headset with mike
// it is reset
// 0x44 -> 0x22 is internal (I think) mike input (macbook pro)
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x022f0600
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x022f0600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10596); // 0x022f0500
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02270500
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 10599); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02270503
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10602); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
// this is NOT from setConnectionSelect - unknown where from
// very not clear what this does - it appears as part of the multiple disable/enables
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x01b3, 0xffff, 0x000000b3, 0, 10604 ); // coef write mask 10604
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0100, 0x0000, 0x000000b3, 0x01b3, 0 ); // coef write mask 10604
}
static void cs_8409_intmike_stream_conn_off_enable(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
snd_hda_codec_write(codec, CS8409_VENDOR_NID, 0, AC_VERB_SET_PROC_STATE, 0x00000001); // 0x04770301
retval = snd_hda_codec_read_check(codec, spec->intmike_adc_nid, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x022f0600
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_CONV, 0x00000000, 0x00000000, 0); // 0x022f0600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10676); // 0x022f0500
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000000); // 0x02270500
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000030, 10679); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D0);
snd_hda_codec_write(codec, spec->intmike_adc_nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_CHANNEL_STREAMID, 0x00000000); // 0x02270600
// snd_hda: conv stream channel map 34 [('CHAN', 0), ('STREAMID', 0)]
//snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_POWER_STATE, 0x00000003); // 0x02270503
//retval = snd_hda_codec_read_check(codec, 0x22, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000033, 10682); // 0x022f0500
hda_set_node_power_state(codec, spec->intmike_adc_nid, AC_PWRST_D3);
// this is NOT from setConnectionSelect - unknown where from
// very not clear what this does - it appears as part of the multiple disable/enables
// snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x00b3, 0xffff, 0x000001b3, 0, 10684 ); // coef write mask 10684
snd_hda_coef_item_masked(codec, 2, CS8409_VENDOR_NID, 0x0009, 0x0000, 0x0100, 0x000001b3, 0x00b3, 0 ); // coef write mask 10684
}
static void cs_8409_intmike_linein_resetup(struct hda_codec *codec)
{
struct cs8409_apple_spec *spec = codec->spec;
// for some very strange reason we setup a 4 channel format after unplug of headset with mike
//cs_8409_intmike_format_setup_format33(codec);
cs_8409_intmike_format_setup_enable(codec, 0x4033, 1);
cs_8409_intmike_volume_setup(codec, 0x27);
cs_8409_intmike_stream_on_nid(codec);
cs_8409_linein_format_setup_enable(codec);
cs_8409_linein_volume_setup(codec, 0x27);
cs_8409_linein_stream_on_nid(codec);
cs_8409_intmike_stream_conn_off_disable(codec);
cs_8409_linein_stream_conn_off(codec);
cs_8409_intmike_stream_off_nid(codec);
cs_8409_linein_stream_off_nid(codec);
//cs_8409_intmike_format_setup_format_nouse(codec);
//cs_8409_really_update_stream_format(codec, 0x22, 1, 0, 0);
cs_8409_really_update_stream_format(codec, spec->intmike_adc_nid, 1, 0, 0);
cs_8409_linein_volume_setup(codec, 0x27);
cs_8409_linein_format_setup_disable(codec);
cs_8409_intmike_stream_conn_off_enable(codec);
cs_8409_linein_stream_conn_off(codec);
cs_8409_intmike_stream_off_nid(codec);
cs_8409_linein_stream_off_nid(codec);
cs_8409_intmike_volume_mute(codec);
cs_8409_linein_volume_mute(codec);
cs_8409_intmike_volume_unmute(codec);
cs_8409_linein_volume_unmute(codec);
cs_8409_inputs_power_nids_off(codec);
}
// this is where we need to decode the actions to be taken
// note that the button interrupts are undocumented for the cs42l42 (reserved)
// not yet clear which one is up and which one is down!!
// so after button detect 0x1b7b is 0x14 and 0x1b7c is 0x0a
// for 0x1b7b 0x14 are reserved bits for cs42l42 - but the 0x04 only seen on detection
// actual button presses are 0x01, 0x02 and button release 0x10
// for 0x1b7c 0x02 is a short release for buttons, 0x08 is reserved
// the mask bits for 0x1b7a seem to be 0xe7 for buttons defining 0x08 as the button detect interrupt
// (0x1b79 is mask, 0x1b7b status; 0x1b7a is mask, 0x1b7c is presumed status, 0x131b is mask, 0x1308 status
// 0x1320 is mask, 0x130f status)
#define TIP_SENSE_PLUG 0x400000
#define TIP_SENSE_UNPLUG 0x200000
#define BUTTON_DOWN_PRESS 0x10000
#define BUTTON_UP_PRESS 0x20000
#define BUTTON_RELEASE 0x100000
// pressing the play/pause button on earbuds yields 0x100 on down and 0x200 on up
#define BUTTON_TOGGLE_DOWN_PRESS 0x100
#define BUTTON_TOGGLE_UP_PRESS 0x200
#define BUTTON_DETECT_MAIN 0x1800 // we only see 0x800 but the mask allows for these 2 bits
#define BUTTON_DETECT_MASK 0x60
#define BUTTON_DETECT1 0x40
#define BUTTON_DETECT2 0x20
#define MIKE_CONNECT 0x02
#define BUTTONS (BUTTON_UP_PRESS | BUTTON_DOWN_PRESS | BUTTON_TOGGLE_UP_PRESS | BUTTON_TOGGLE_DOWN_PRESS)
#define HSDET_AUTO_DONE 0x02
#define PDN_DONE 0x01
static void cs_8409_headset_plugin_event(struct hda_codec *codec);
static void cs_8409_headset_unplug_event(struct hda_codec *codec);
static void cs_8409_headset_type_detect_event(struct hda_codec *codec);
static int cs_8409_set_power_state(struct hda_codec *codec, int power_state);
static void cs_8409_enable_headset_streaming(struct hda_codec *codec);
static void cs_8409_headset_button_detect_event(struct hda_codec *codec);
static void cs_8409_headset_button_event(struct hda_codec *codec, int buttons);
static void cs_8409_plugin_event_continued(struct hda_codec *codec);
static void cs_8409_interrupt_action(struct hda_codec *codec, int int_response)
{
int retval;
int headset_state;
int update_jacks = 0;
struct cs8409_apple_spec *spec = codec->spec;
// so if Im analyzing the Dell code correctly
// I think we should only do the snd_hda_jack_report_sync after all jack detection
// plus all nid mute/unmute and widget output/input enable
// because the Dell code first does tip sense, then (if wanted) jack type detection
// then runs snd_hda_jack_unsol_event which does any callbacks
// and finally the snd_hda_jack_report_sync
if ((int_response & TIP_SENSE_PLUG) == TIP_SENSE_PLUG)
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - plug in\n");
cs_8409_headset_plugin_event(codec);
}
else if ((int_response & TIP_SENSE_UNPLUG) == TIP_SENSE_UNPLUG)
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - unplug\n");
cs_8409_cs42l83_mark_jack(codec);
cs_8409_headset_unplug_event(codec);
// so although this more consistent with linux way (all automute etc callbacks done before report sync)
// it seems we need to update the linux user side before doing the amp reset when playing
// with cs_8409_cs42l83_jack_report_sync here there is a few 10s milliseconds period where get anomalous volume
// because we start playing through the amps while linux user side still says its headphone output
// - this may be because updating the linux user side takes a little while
//dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - unplug jack_report_sync\n");
//cs_8409_cs42l83_jack_report_sync(codec);
}
else if ((int_response & HSDET_AUTO_DONE) == HSDET_AUTO_DONE)
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - headset detected\n");
cs_8409_headset_type_detect_event(codec);
// and this is where life gets really complicated
// if we have a mike we do a button detect - but that leads to an unsolicited response
// so we only continue here I think if we dont have a mike
if (!(spec->have_mike)) {
cs_8409_cs42l83_mark_jack(codec);
cs_8409_plugin_event_continued(codec);
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - headset detect no mike jack_report_sync\n");
cs_8409_cs42l83_jack_report_sync(codec);
}
}
// not clear what test is here - but this should check what we see - one button interrupt seems to be activated
// when doing the button detect
// not sure what the exact button interrupt is - we get 0x140800
// so the button detect interrupt is 0x0800 - the 0x140000 are actual button interrupts (undocumented for cs42l42)
else if (int_response & BUTTON_DETECT_MAIN)
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - buttons detected\n");
cs_8409_headset_button_detect_event(codec);
cs_8409_cs42l83_mark_jack(codec);
cs_8409_plugin_event_continued(codec);
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - button detect jack_report_sync\n");
cs_8409_cs42l83_jack_report_sync(codec);
}
else if (((int_response & BUTTON_UP_PRESS) == BUTTON_UP_PRESS) ||
((int_response & BUTTON_DOWN_PRESS) == BUTTON_DOWN_PRESS) ||
((int_response & BUTTON_TOGGLE_UP_PRESS) == BUTTON_TOGGLE_UP_PRESS) ||
((int_response & BUTTON_TOGGLE_DOWN_PRESS) == BUTTON_TOGGLE_DOWN_PRESS))
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - button event on \n");
cs_8409_headset_button_event(codec, int_response);
update_jacks = 1;
}
else if (((int_response & BUTTON_RELEASE) == BUTTON_RELEASE))
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - button event off \n");
//cs_8409_cs42l83_mark_jack(codec);
cs_8409_headset_button_event(codec, int_response);
update_jacks = 1;
}
else if ((int_response & PDN_DONE) == PDN_DONE)
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - power down\n");
}
else
{
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - UNKNOWN INTERRUPT 0x%08x\n", int_response);
}
return;
}
static void cs42l83_headset_play_setup_on(struct hda_codec *codec);
static void cs_8409_headset_streaming_preplay(struct hda_codec *codec);
static void cs_8409_intmike_linein_disable(struct hda_codec *codec);
static void cs_8409_headset_mike_streaming_preplay(struct hda_codec *codec, int nullformat);
static void cs_8409_headset_mike_buttons_enable(struct hda_codec *codec);
static void cs_8409_plugin_event_continued(struct hda_codec *codec)
{
struct cs8409_apple_spec *spec = codec->spec;
int headset_plugged_in = 0;
int retval = 0;
mycodec_info(codec, "cs_8409_plugin_event_continued start\n");
// 0 is power state - 0 is powered on +ve powered/powering down
// headset_plugged_in indicates if headset still plugged in or not
headset_plugged_in = cs_8409_set_power_state(codec, 0);
mycodec_info(codec, "cs_8409_plugin_event_continued headset_plugged_in %d\n", headset_plugged_in);
if (headset_plugged_in)
{
// now handle plugin while playing
if (spec->playing)
{
cs_8409_amps_disable_streaming(codec);
cs_8409_enable_headset_streaming(codec);
// the following is just cs_8409_enable_headset_streaming
//cs43l83_headset_amp_format_setup(codec);
//mycodec_info(codec, "cs42l83_headset_play_setup_on\n");
//cs42l83_headset_play_setup_on(codec);
// power on audio output
//cs42l83_set_power_state_on(codec, 0);
//cs42l83_headset_enable_on(codec);
// so OSX now does another one of its enable off/enable on - ignoring
//cs_8409_headset_enable_off(codec);
//cs42l83_power_off_codec_output_off(codec);
//headphone_play_stop_buffers_off(codec);
//headphone_play_stop_power_off(codec);
//headphone_play_stop_headphone_format_setup_disable(codec);
//cs_8409_enable_headset_streaming(codec);
// we need to reset formats here - so we follow the same path as a simple amp
// or headphone play ie after the pre-prepare we force a reset of the
// of the stream format
// using explicit nid here!!
//cs_8409_reset_stream_format(codec, 0xa, 1, 1);
}
else
{
// try removing this - we still do a partial setup when actually play on OSX
// and if we stop play then do another play we do a full setup
// - why not just enable when we play??
// in any case we initially made this a full setup and it worked
//cs_8409_headset_streaming_preplay(codec);
// so now think on OSX we pre-setup the headphone and mike here
// when we dont know if we will be playing or capturing
// in particular realised that cs42l83_configure_serial_port is only called
// for the headphone setup - but it sets both primary ASP (Audio Serial Port)
// transmit and receive frequencies - which would seem to be important for
// capturing!!
//spec->headset_presetup_done = 1;
}
// NOTA BENE - no concept/implementation of plugging in while capturing!!
mycodec_info(codec, "cs_8409_plugin_event_continued headset_phase %d\n", spec->headset_phase);
// this event now gets called if boot with headset plugged in
// but from this point the boot phase setup is different
// - now a headset_phase of 1 indicates booted with headset plugged in
// - headset phase of 2 or more means post boot headset plugin
if (spec->headset_phase >= 2)
{
// ensure the intmike/linein nids are powered off
cs_8409_inputs_power_nids_off(codec);
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_plugin_event_continued headphone sense 0x%x\n", retval);
if (!(retval & 0x80))
{
dev_info(hda_codec_dev(codec), "cs_8409_plugin_event_continued JACK DISCONNECT UNIMPLEMENTED!!\n");
}
if (spec->have_mike)
{
if (spec->capturing)
{
dev_info(hda_codec_dev(codec), "cs_8409_plugin_event_continued PLUGIN WHILE CAPTURING UNIMPLEMENTED!!\n");
}
// this is just calling this routine
//cs_8409_headset_mike_setup_nouse
cs_8409_intmike_linein_disable(codec);
// is this a good position to switch the inputs??
switch_input_src(codec);
// confirmed that if do a second recording we get a full setup as for playing above
// - so why not just enable when we capture??
// (only plausible reason so far is to reduce setup time because of the long time
// to send the i2c commands??)
// NOTE - this is complicated because on OSX it appears the headphone setup is always
// done - even if just capturing
// going with OSX way and doing the headphone setup as well
// so this is a problem - at this point we dont have a stream
// so our format is null
// what to do??
// now moving all this setup into the actual capture setup
// - as did with the play setup
//cs_8409_headset_mike_streaming_preplay(codec, 1);
//spec->headset_presetup_done = 1;
cs_8409_headset_mike_buttons_enable(codec);
}
}
}
else
{} // headset unplugged - should be handled by the unplug interrupt
mycodec_info(codec, "cs_8409_plugin_event_continued end\n");
}
static void cs_8409_plugin_handle_detect(struct hda_codec *codec);
static void cs_8409_plugin_complete_detect(struct hda_codec *codec);
static void cs_8409_headset_plugin_event(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
mycodec_info(codec, "cs_8409_headset_plugin_event pre plugin handle_detect\n");
cs_8409_plugin_handle_detect(codec);
mycodec_info(codec, "cs_8409_headset_plugin_event post plugin handle_detect\n");
//retval = snd_hda_codec_read_check(codec, codec->core.afg, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000000, 1066); // 0x001f0500
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
// this seems to be here but no idea where coming from
retval = read_gpio_status_check(codec);
// following code likely from AppleHDAMikeyInternalCS8409::handleJackDetectUR
// moved from cs_8409_plugin_handle_detect
// then call setTimer to initiate function after a time period
// this is NOT a debug sleep - it occurs on all plugin events on OSX for some reason
msleep(1800);
//retval = snd_hda_codec_read_check(codec, codec->core.afg, 0, AC_VERB_GET_POWER_STATE, 0x00000000, 0x00000000, 1069); // 0x001f0500
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
mycodec_info(codec, "cs_8409_headset_plugin_event pre plugin complete_detect\n");
cs_8409_plugin_complete_detect(codec);
mycodec_info(codec, "cs_8409_headset_plugin_event post plugin complete_detect\n");
spec->headset_phase = 3;
}
static void cs_8409_plugin_handle_detect(struct hda_codec *codec)
{
//int retval;
struct cs8409_apple_spec *spec = codec->spec;
// now think this is AppleHDAMikeyInternalCS8409::handleJackDetectUR
// which calls:
// AppleHDAMikeyInternalCS8409::disableButtonDetection
// AppleHDAMikeyInternalCS8409::enableHPClamps
// AppleHDAMikeyInternalCS8409::enableHPClamps calls:
// AppleHDATDM_Codec::setHPOutClamp
mycodec_info(codec, "cs_8409_plugin_handle_detect start\n");
// this is a pre-value - indicates we have had a jack detect
// but set to 1 when have checked with cs42l83_headphone_sense for headset
// at the moment not used
spec->jack_present = 2;
cs42l83_headset_button_detect_interrupts_off(codec);
cs42l83_headset_set_hpout_clamp_disable(codec);
// IOSleep(1) here
msleep(1);
mycodec_info(codec, "cs_8409_plugin_handle_detect end\n");
}
static void cs_8409_plugin_complete_detect(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
// so AppleHDAMikeyInternalCS8409::generalTimerCallback calls AppleHDAMikeyInternalCS8409::completeJackDetectUR
// AppleHDAMikeyInternalCS8409::generalTimerCallback is set as a timer callback in the AppleHDAMikeyInternal::init
// using the IOTimerEventSource::timerEventSource function
// this is AppleHDAMikeyInternalCS8409::completeJackDetectUR
// its first call is to AppleHDATDM_Codec::getHeadphonePinSense
// which if returns 0 in the bool arg jumps to AppleHDAMikeyInternalCS8409::handleJackDisconnectUR
// - which does the disconnect
mycodec_info(codec, "cs_8409_plugin_complete_detect start\n");
// so thats weird - the first call is a power call which doesnt seem to exist in the log
//hda_set_node_power_state(codec, codec->core.afg, AC_PWRST_D0);
retval = cs42l83_headphone_sense(codec);
mycodec_info(codec, "cs_8409_plugin_complete_detect headphone sense 0x%x\n", retval);
if ((retval & 0x80))
{
mycodec_info(codec, "cs_8409_plugin_complete_detect headphone sensed\n");
spec->jack_present = 1;
spec->headset_enable = 1;
cs42l83_complete_jack_detect(codec);
cs42l83_power_hs_bias_on(codec);
// this seems to be setting an interrupt on 0x131b for headset detect
// - but there doesnt seem to be a delay anywhere here
// so it must be immediately triggered
cs42l83_enable_hs_auto_int_on(codec);
cs42l83_unplug_interrupt_setup(codec);
cs42l83_set_hpout_pulldown_off(codec);
cs42l83_headset_detect_on(codec);
//cs42l83_headset_detect_onoff(codec, 1);
}
else
{
mycodec_info(codec, "cs_8409_plugin_complete_detect headphone NOT sensed\n");
spec->jack_present = 0;
spec->headset_enable = 0;
// AppleHDAMikeyInternalCS8409::handleJackDisconnectUR
dev_info(hda_codec_dev(codec), "cs_8409_plugin_complete_detect no headphone UNIMPLEMENTED!!\n");
}
mycodec_info(codec, "cs_8409_plugin_complete_detect end\n");
}
static void cs_8409_headset_type_detect_event(struct hda_codec *codec)
{
int retval;
int retstate;
int flag = 1;
int headset_type = 0;
struct cs8409_apple_spec *spec = codec->spec;
// this is AppleHDAMikeyInternalCS8409::handleTypeDetectUR
// dont yet see the path to call this - Im guessing from some messaging call
mycodec_info(codec, "cs_8409_headset_type_detect_event start\n");
// I think we get to here if have either an unplug event or headset detect event
// - in both cases we need to turn off the headset detect interrupt
// and unset for headset detect
//plugin_enable_hs_auto_int_off(codec);
cs42l83_enable_hs_auto_int_off(codec);
//headset_type = plugin_headset_type(codec);
headset_type = cs42l83_headset_type(codec);
// we then have options based on the headset type
headset_type = headset_type & 0x3;
// types are 0x00 (1), 0x01 (2), 0x02 (3) and 0x3 (4)
// type 1 Pin 1 Left, Pin 2 Right, Pin 3 Gnd, Pin 4 Mic
// type 2 Pin 1 Left, Pin 2 Right, Pin 3 Mic, Pin 4 Gnd
// type 3 Pin 1 Left, Pin 2 Right, Pin 3 Gnd, Pin 4 Gnd
// type 4 Optical!!
mycodec_info(codec, "cs_8409_headset_type_detect_event headset type %d\n", headset_type);
if (headset_type == 0x00 && flag == 0)
{
// 0x74df1
// if ?? goto 0x74ee2
// if ?? goto 0x751e8
// 0x74e42
//plugin_headset_detect_off(codec);
// IOSleep(250);
// possible AppleHDAMikeyInternalCS8409::handleJackDetectUR
// goto 0x7546d
// IOLog()
// goto 0x75198
// return
// else
// 0x751e8
//retval = plugin_headphone_sense1(codec);
// if dont sense headphone guess we do AppleHDAMikeyInternalCS8409::handleJackDisconnectUR
//if (!(retval & 0x80))
//{
// // AppleHDAMikeyInternalCS8409::handleJackDisconnectUR
// goto 0x74ee2
//}
// error!!
}
if (headset_type == 0x00)
{
// 0x74df1
// goto 0x74ee2
spec->headset_type = 1;
spec->have_mike = 1;
dev_info(hda_codec_dev(codec), "cs_8409_headset_type_detect_event headset has mike!!\n");
}
else if (headset_type == 0x01)
{
// 0x74e98
// insert Mikey event 0xfe
// goto 0x74ee2
spec->headset_type = 2;
spec->have_mike = 1;
dev_info(hda_codec_dev(codec), "cs_8409_headset_type_detect_event headset has mike!!\n");
}
else if (headset_type == 0x02)
{
// 0x74eb9
// goto 0x74ee2
spec->headset_type = 3;
dev_info(hda_codec_dev(codec), "cs_8409_headset_type_detect_event headset does not have mike!!\n");
}
else if (headset_type == 0x03)
{
// this is SPDIF!!
// 0x74ec3
// insert Mikey event 0xfc
spec->headset_type = 4;
dev_info(hda_codec_dev(codec), "cs_8409_headset_type_detect_event headset does not have mike!!\n");
}
// 0x74ee2
cs42l83_headset_detect_off(codec);
//cs42l83_headset_detect_onoff(codec, 0);
cs42l83_set_hpout_pulldown_on(codec);
// IOSleep(1);
msleep(1);
// 0x74ff1
cs42l83_set_hpout_clamp_enable(codec);
// IOSleep(1);
msleep(1);
if (spec->have_mike)
{
cs42l83_enable_hsbias_auto_clamp_on(codec);
//cs42l83_enable_hsbias_auto_clamp_off(codec);
cs42l83_enable_hsbias_auto_clamp_off0(codec);
// I dont see a difference in these 2 functions
//cs42l83_power_hs_bias_off1(codec);
cs42l83_power_hs_bias_off(codec);
// difference from no mike headphones
cs42l83_setup_button_detect(codec);
cs42l83_power_hs_bias_button_on(codec);
cs42l83_enable_hsbias_auto_clamp_off1(codec);
}
else
{
// goto 0x75a02
// 0x750a2
cs42l83_headset_mike_detect_off(codec);
cs42l83_power_hs_bias_off(codec);
}
// 0x75149
// there is a call to dispatchStatelessTagToEngines which is likely what initiates the stream setup etc
// 0x7546d
// 0x75198
// there is an unknown call here - possible setPowerState
// cannot figure out if this is doing anything - none of the functions seem to fit the log
// so now think this function isnt really doing anything
// and the setPowerState is from some other function call path ie the result
// of dispatchStatelessTagToEngines
// exit routine after this
mycodec_info(codec, "cs_8409_headset_type_detect_event end\n");
}
static int cs_8409_set_power_state(struct hda_codec *codec, int power_state)
{
int retval = 0;
int retstate = 0;
int flag = 0;
mycodec_info(codec, "cs_8409_set_power_state start\n");
// this is likely AppleHDAMikeyInternalCS8409::setPowerState as there is
// a pin sense and handleJackDisconnectUR in AppleHDAMikeyInternalCS8409::setPowerState
// in fact all AppleHDAMikeyInternalCS8409::setPowerState does is check the headphone sense
// and then either do a handleJackDisconnectUR or handleJackDetectUR
if (flag)
{
// check for headphone whatever power state of HDA is
retval = cs42l83_headphone_sense(codec);
// if sense headphone guess we do AppleHDAMikeyInternalCS8409::handleJackDetectUR
if ((retval & 0x80))
{
// AppleHDAMikeyInternalCS8409::handleJackDetectUR
dev_info(hda_codec_dev(codec), "cs_8409_set_power_state JACK DETECT UNIMPLEMENTED!!\n");
}
retstate = 0;
}
else
{
// only check for headphone if HDA powered up
if (power_state == 0)
{
retval = cs42l83_headphone_sense(codec);
// if dont sense headphone guess we do AppleHDAMikeyInternalCS8409::handleJackDisconnectUR
if (!(retval & 0x80))
{
// AppleHDAMikeyInternalCS8409::handleJackDisconnectUR
dev_info(hda_codec_dev(codec), "cs_8409_set_power_state JACK DISCONNECT UNIMPLEMENTED!!\n");
retstate = 0;
}
else
retstate = 1;
}
}
mycodec_info(codec, "cs_8409_set_power_state end\n");
return retstate;
}
static void cs_8409_headset_button_detect_event(struct hda_codec *codec)
{
int ret_button;
int ret_mike;
struct cs8409_apple_spec *spec = codec->spec;
mycodec_info(codec, "cs_8409_headset_button_detect_event start\n");
// this returns significant state - headphone sense (shift 16), and 2 reads from register 0x1b78 (second one shifted 8)
ret_button = cs42l83_handle_button_detect(codec);
mycodec_info(codec, "cs_8409_headset_button_detect_event button data 0x%08x\n", ret_button);
// so now seen on imacs we have a button detect of 0x20 rather than 0x40 previously seen
// - this maybe an Apple headset/non-Apple headset issue rather than imac issue (the headset was non-Apple)
//if ((ret_button & BUTTON_DETECT) == BUTTON_DETECT)
if (ret_button & BUTTON_DETECT_MASK)
{
mycodec_info(codec, "cs_8409_headset_button_detect_event HAVE BUTTON\n");
spec->have_buttons = 1;
}
// this is a read from same register 0x1b78 - which seems to contain both senses
// - button sense 0x40/0x20 (assumed) and mike sense 0x02 - known but undocumented
// do we do anything with this??
// we have aleady set have_mike prior to this
// could log an error here
ret_mike = cs42l83_mike_connected(codec);
mycodec_info(codec, "cs_8409_headset_button_detect_event mike data 0x%08x\n", ret_mike);
if ((ret_mike & MIKE_CONNECT) != MIKE_CONNECT)
dev_err(hda_codec_dev(codec), "ERROR - has mike but mike not connected - not analyzed!!\n");
mycodec_info(codec, "cs_8409_headset_button_detect_event end\n");
}
static void cs_8409_headset_button_event(struct hda_codec *codec, int buttons)
{
mycodec_info(codec, "cs_8409_headset_button_event buttons 0x%08x\n", buttons);
}
static void cs_8409_intmike_linein_disable(struct hda_codec *codec)
{
cs_8409_intmike_stream_conn_off(codec);
cs_8409_linein_stream_conn_off(codec);
cs_8409_intmike_stream_off_nid(codec);
cs_8409_linein_stream_off_nid(codec);
cs_8409_intmike_volume_setup(codec, 0x27);
cs_8409_intmike_format_setup_disable(codec);
cs_8409_linein_volume_setup(codec, 0x27);
cs_8409_linein_format_setup_disable(codec);
}
static void cs_8409_headset_mike_streaming_preplay(struct hda_codec *codec, int nullformat)
{
// confirmed that if do a second recording we get a full setup as for playing
// - so why not just enable when we capture??
// (only plausible reason so far is to reduce setup time because of the long time
// to send the i2c commands??)
// NOTE - this is complicated because on OSX it appears the headphone setup is always
// done - even if just capturing
// going with OSX way and doing the headphone setup as well
//cs42l83_headset_mike_format_setup_enable(codec, nullformat, 1);
//cs42l83_input_set_output_sample_rate(codec);
//cs42l83_mike_setup_audio_input(codec);
//cs42l83_mike_enable(codec);
// yet again the usual disable/second enable
//cs42l83_mike_disable(codec);
//cs42l83_headset_mike_format_setup_disable(codec);
// cs42l83_headset_mike_format_setup_enable1(codec);
// cs42l83_headset_mike_format_setup_enable1a(codec);
// cs42l83_headset_mike_format_setup_enable1b(codec);
// cs42l83_input_set_output_sample_rate1(codec);
// cs42l83_input_setup_audio_input(codec);
// cs42l83_mike_enable(codec);
//cs42l83_headset_mike_pin_enable(codec);
}
static void cs_8409_headset_mike_buttons_enable(struct hda_codec *codec)
{
// part of AppleHDAMikeyInternalCS8409::handleButtonDetectUR
cs42l83_configure_headset_button_interrupts(codec);
cs42l83_enable_hsbias_auto_clamp_off2(codec);
// following coded explicitly in handleButtonDetectUR
cs42l83_hsbias_sense_on(codec);
}
static void cs_8409_headset_plugin_preplay_unused1(struct hda_codec *codec)
{
// these occur for headset with mike but seem to be triggered by
// by something - maybe volume control??
// dont know where coming from - ignoring for now
//plugin3_set_power_state_on(codec);
//plugin3_headphone_play_start_headset_enable_on(codec);
//plugin3_headphone_sense3(codec);
//plugin3_headphone_sense4(codec);
//plugin3_headphone_format_setup_enable2(codec);
}
static void cs_8409_headset_plugin_preplay_unused2(struct hda_codec *codec)
{
// these occur for headset with mike but seem to be triggered by
// by something - this is definitely after an interrupt - but
// no interrupt triggered
// dont know where coming from - ignoring for now
//plugin3_headset_enable_off(codec);
//plugin3_power_off_codec_output_off(codec);
//plugin3_buffers_off1(codec);
//plugin3_headphone_format_setup_disable1(codec);
//plugin3_headset_enable_off1(codec);
//plugin3_power_off_codec_output_off1(codec);
}
static void cs_8409_unplug_handle_disconnect(struct hda_codec *codec);
static void cs_8409_headset_unplug_event(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
mycodec_info(codec, "cs_8409_headset_unplug_event start\n");
// Im guessing we are ensuring headphone is unplugged here
// what to do if not!!
retval = cs42l83_headphone_sense(codec);
if ((retval & 0x80))
{
dev_info(hda_codec_dev(codec), "cs_8409_headset_unplug_event headphone still sensed - NOT HANDLED - UNIMPLEMENTED!!!\n");
}
else
{
mycodec_info(codec, "cs_8409_headset_unplug_event headphone not sensed - OK\n");
cs_8409_unplug_handle_disconnect(codec);
}
mycodec_info(codec, "cs_8409_headset_unplug_event end\n");
}
static void cs_8409_unplug_handle_disconnect(struct hda_codec *codec)
{
int retval;
struct cs8409_apple_spec *spec = codec->spec;
mycodec_info(codec, "cs_8409_unplug_handle_disconnect start\n");
cs42l83_plugin_interrupt_setup(codec);
cs42l83_enable_hs_auto_int_off(codec);
cs42l83_headset_detect2_off(codec);
if (spec->have_mike)
{
cs42l83_power_hs_bias_off(codec);
cs42l83_enable_hsbias_auto_clamp_off3(codec);
cs42l83_disable_button_interrupts(codec);
}
// Im guessing we are ensuring headphone is unplugged here
// what to do if not!!
retval = cs42l83_headphone_sense(codec);
if ((retval & 0x80))
{
dev_err(hda_codec_dev(codec), "cs_8409_unplug_handle_disconnect headphone still sensed - NOT HANDLED - UNIMPLEMENTED!!!\n");
}
else
{
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headphone not sensed - OK\n");
// even here this still has audio glitch
// - but with 100 ms wait later seems to fix it
// silly me - we must update this here so jack_detect_update in jack_report_sync will determine the headset has been unplugged
spec->jack_present = 0;
// try setting ALL jacks dirty - likely not needed
//snd_hda_jack_set_dirty_all(codec);
dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - unplug jack_report_sync\n");
cs_8409_cs42l83_jack_report_sync(codec);
if (spec->playing)
{
mycodec_info(codec, "cs_8409_unplug_handle_disconnect playing 1 start\n");
cs42l83_headset_enable_off(codec);
cs42l83_power_off_codec_output(codec);
//unplug23_buffers_off(codec);
cs42l83_buffers_onoff(codec, 0);
if ((spec->have_mike))
cs_8409_headset_amp_format_setup_disable(codec, 0);
else
{
cs42l83_power_onoff(codec, 0);
cs_8409_headset_amp_format_setup_disable(codec, 1);
}
cs42l83_headset_enable_off(codec);
//unplug23_power_off_codec_output1(codec);
cs42l83_power_off_codec_output(codec);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect playing 1 end\n");
}
// so we have determined the volume/glitch issues are after this
//mycodec_info(codec, "cs_8409_unplug_handle_disconnect sleep 1\n");
//msleep(10000);
//mycodec_info(codec, "cs_8409_unplug_handle_disconnect sleep 1 end\n");
// with previous jack_report_sync and this wait dont have a glitch
msleep(100);
// silly me - we must update this here so jack_detect_update in jack_report_sync will determine the headset has been unplugged
//spec->jack_present = 0;
//dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - unplug jack_report_sync\n");
//cs_8409_cs42l83_jack_report_sync(codec);
// add a wait for user side update - still get a small glitch
//msleep(100);
// this is done if playing or not??
// - changing - only setup amps if still playing
if (spec->playing)
{
mycodec_info(codec, "cs_8409_unplug_handle_disconnect playing 2 start\n");
//unplug23_play_setup_TDM_6462(struct hda_codec *codec)
//play_setup_TDM_amps12_debug(codec, 1);
play_setup_TDM_amps12(codec, 1);
//unplug23_setup_amps_6462(struct hda_codec *codec)
play_setup_amps12(codec);
//unplug23_play_setup_TDM_7472(struct hda_codec *codec)
play_setup_TDM_amps34(codec);
//unplug23_play_setup_amps_7472(struct hda_codec *codec)
play_setup_amps34(codec);
//unplug23_sync_converters_on(struct hda_codec *codec)
play_sync_converters_on(codec);
// so here linux user side reports still headphone output (because originally had not yet done
// jack_report_sync) which leads to audio glitch with output now through speakers
// so we need to update linux user side after headphone output disable above
// (the volume mismatch previously heard was due to incorrect handling of nid 0x03 update for stereo (ie 2 channel) source)
// can only think its delay from jack_report_sync till linux user side updated
// (we dont really have a massive lot of commands from here till jack_report_sync
// (here would be more consistent with linux way which does all power/automute/automic etc callbacks before jack_report_sync)
//mycodec_info(codec, "cs_8409_unplug_handle_disconnect sleep 2\n");
//msleep(10000);
//mycodec_info(codec, "cs_8409_unplug_handle_disconnect sleep 2 end\n");
// silly me - we must update this here so jack_detect_update in jack_report_sync will determine the headset has been unplugged
//spec->jack_present = 0;
//dev_info(hda_codec_dev(codec), "cs_8409_interrupt_action - unplug jack_report_sync\n");
//cs_8409_cs42l83_jack_report_sync(codec);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect playing 2 end\n");
}
// more duplicated disable/enables
//unplug_sync_converters_off(codec);
//unplug_disable_amps_6462(codec);
//unplug_disable_TDM_6462(codec);
//unplug_disable_amps_7472(codec);
//unplug_disable_TDM_7472(codec);
//unplug_setup_TDM2_6462(codec);
//unplug_setup_amps1_6462(codec);
//unplug_setup_TDM2_7472(codec);
//unplug_setup_amps1_7472(codec);
//unplug_sync_converters2_on(codec);
if (!(spec->have_mike))
{
cs_8409_inputs_power_nids_off(codec);
}
// and another headphone sense
retval = cs42l83_headphone_sense(codec);
if ((retval & 0x80))
{
dev_err(hda_codec_dev(codec), "cs_8409_unplug_handle_disconnect headphone sensed again - NOT HANDLED - UNIMPLEMENTED!!!\n");
}
else
{
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset not sensed - OK\n");
if (spec->have_mike)
{
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset have mike start\n");
//unplug23_mike_disable(codec);
cs42l83_mike_disable(codec);
//unplug23_power_on_off(codec);
cs42l83_power_onoff(codec, 0);
//unplug23_headset_amp_disable_and_mike_format_setup_disable(codec);
cs42l83_headset_amp_disable_and_mike_format_setup_disable(codec);
// is this a good position to switch the inputs??
switch_input_src(codec);
//unplug23_intmike_linein_resetup(codec);
cs_8409_intmike_linein_resetup(codec);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset have mike end\n");
}
if (spec->playing)
{
if (!(spec->have_mike))
{
cs_8409_inputs_power_nids_off(codec);
}
}
if (spec->have_mike)
cs_8409_inputs_power_nids_off(codec);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset disable start\n");
cs42l83_unplug_headset_detect_off(codec);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset disable 1\n");
cs42l83_headset_switch_control(codec);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset disable end\n");
}
}
mycodec_info(codec, "cs_8409_unplug_handle_disconnect headset about to reset vars\n");
// and reset all headset variables
spec->jack_present = 0;
spec->headset_type = 0;
spec->have_mike = 0;
spec->have_buttons = 0;
spec->headset_play_format_setup_needed = 1;
spec->headset_capture_format_setup_needed = 1;
spec->headset_presetup_done = 0;
mycodec_info(codec, "cs_8409_unplug_handle_disconnect jack_present %d\n", spec->jack_present);
mycodec_info(codec, "cs_8409_unplug_handle_disconnect end\n");
}
static void cs42l83_headset_play_setup_on(struct hda_codec *codec)
{
// this is the function AppleHDATDM_CS42L83::enable for turning on headset for play
// the following section is often done pre-play
cs42l83_configure_int_mclk(codec);
//cs42l83_headset_power_on_on_nouse(codec);
cs42l83_power_onoff(codec, 1);
cs42l83_configure_serial_port(codec);
// the following section always done before play
cs42l83_output_set_input_sample_rate(codec);
cs42l83_setup_audio_output(codec);
// headset_setup_SPDIF_output(codec); - presumably if is SPDIF setup
//cs42l83_headset_rcv_enable_on(codec);
cs42l83_buffers_onoff(codec, 1);
}
static void cs42l83_headset_disable_nouse(struct hda_codec *codec, int full)
{
myprintk("snd_hda_intel: cs42l83_headset_disable start\n");
cs42l83_headset_enable_off(codec);
myprintk("snd_hda_intel: cs42l83_power_off_codec_output start\n");
cs42l83_power_off_codec_output(codec);
myprintk("snd_hda_intel: cs42l83_power_off_codec_output end\n");
if (full)
{
#if 0
// so this is old style - why didnt I update it??
myprintk("snd_hda_intel: cs42l83_headset_rcv_enable_off start\n");
cs42l83_headset_rcv_enable_off(codec);
myprintk("snd_hda_intel: cs42l83_headset_rcv_enable_off end\n");
myprintk("snd_hda_intel: cs42l83_headset_power_off start\n");
cs42l83_headset_power_off(codec);
myprintk("snd_hda_intel: cs42l83_headset_power_off end\n");
#endif
myprintk("snd_hda_intel: cs42l83_buffers_onoff start\n");
//cs42l83_headset_rcv_enable_off(codec);
cs42l83_buffers_onoff(codec, 0);
myprintk("snd_hda_intel: cs42l83_buffers_onoff end\n");
myprintk("snd_hda_intel: cs42l83_power_onoff start\n");
//cs42l83_headset_power_off(codec);
cs42l83_power_onoff(codec, 0);
myprintk("snd_hda_intel: cs42l83_power_onoff end\n");
}
myprintk("snd_hda_intel: cs42l83_headset_disable end\n");
}
static void cs42l83_headset_disable(struct hda_codec *codec)
{
myprintk("snd_hda_intel: cs42l83_headset_disable start\n");
myprintk("snd_hda_intel: cs42l83_buffers_onoff start\n");
//cs42l83_headset_rcv_enable_off(codec);
cs42l83_buffers_onoff(codec, 0);
myprintk("snd_hda_intel: cs42l83_buffers_onoff end\n");
myprintk("snd_hda_intel: cs42l83_power_onoff start\n");
//cs42l83_headset_power_off(codec);
cs42l83_power_onoff(codec, 0);
myprintk("snd_hda_intel: cs42l83_power_onoff end\n");
myprintk("snd_hda_intel: cs42l83_headset_disable end\n");
}
static void cs_8409_headset_streaming_preplay(struct hda_codec *codec)
{
//int retval;
// this code performed on plugin even if not playing
// the usual enable/disable multiple times
//plugin3_headphone_format_setup_enable(codec);
cs43l83_headset_amp_format_setup(codec, 1, 1);
//plugin3_configure_int_mclk(codec);
cs42l83_configure_int_mclk(codec);
//plugin3_power_on_on(codec);
cs42l83_power_onoff(codec, 1);
//plugin3_configure_serial_port(codec);
cs42l83_configure_serial_port(codec);
//plugin3_set_sample_rate(codec);
cs42l83_output_set_input_sample_rate(codec);
//plugin3_setup_audio_output(codec);
cs42l83_setup_audio_output(codec);
//plugin3_buffers_on(codec);
cs42l83_buffers_onoff(codec, 1);
// ignoring the disable
//plugin3_buffers_off(codec);
//cs42l83_buffers_onoff(codec, 0);
//plugin3_power_on_off(codec);
//cs42l83_headset_power_off(codec);
//plugin3_headphone_format_setup_disable(codec);
//cs_8409_headset_amp_format_setup_disable(codec, 1);
//plugin3_headphone_format_setup_enable1(codec);
//plugin3_headphone_format_setup_enable1a(codec);
//plugin3_configure_int_mclk1(codec);
//plugin3_power_on_on2(codec);
//plugin3_configure_serial_port1(codec);
//plugin3_set_sample_rate1(codec);
//plugin3_setup_audio_output1(codec);
//plugin3_buffers_on1(codec);
}
static void cs_8409_enable_headset_streaming(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "cs_8409_enable_headset_streaming start\n");
// debug status check - 0x27 here
read_gpio_status_check(codec);
// dont really have any idea how to get to here
// Im guessing from messaging
//play_format_setup_headphone(codec);
cs43l83_headset_amp_format_setup(codec, 1, 1);
cs42l83_headset_play_setup_on(codec);
// power on audio output
cs42l83_set_power_state_on(codec, 0);
cs42l83_headset_enable_on(codec);
mycodec_info(codec, "cs_8409_enable_headset_streaming end\n");
}
static void cs_8409_disable_headset_streaming(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "snd_hda_intel: cs_8409_disable_headset_streaming start\n");
// why do we do the headphone disable/poweroff codec output twice??
// but we do - repeatedly seen in logs
// this was cs42l83_headset_disable(codec, 1);
cs42l83_headset_enable_off(codec);
myprintk("snd_hda_intel: cs_8409_disable_headset_streaming cs42l83_power_off_codec_output start\n");
cs42l83_power_off_codec_output(codec);
myprintk("snd_hda_intel: cs_8409_disable_headset_streaming cs42l83_power_off_codec_output end\n");
cs42l83_headset_disable(codec);
//playstop_headset_amp_format_setup_disable_headphone(codec);
cs_8409_headset_amp_format_setup_disable(codec, 1);
// this was cs42l83_headset_disable(codec, 0);
cs42l83_headset_enable_off(codec);
myprintk("snd_hda_intel: cs_8409_disable_headset_streaming 1 cs42l83_power_off_codec_output start\n");
cs42l83_power_off_codec_output(codec);
myprintk("snd_hda_intel: cs_8409_disable_headset_streaming 1 cs42l83_power_off_codec_output end\n");
mycodec_info(codec, "snd_hda_intel: cs_8409_disable_headset_streaming end\n");
}
static void cs_8409_headplay_real(struct hda_codec *codec)
{
//int retval;
struct cs8409_apple_spec *spec = codec->spec;
mycodec_info(codec, "cs_8409_headplay_real start\n");
if (spec->headset_enable == 0)
{
mycodec_info(codec, "cs_8409_headplay_real enable 0\n");
//cs_8409_headplay_real1(codec);
}
else if (spec->headset_enable == 1)
{
mycodec_info(codec, "cs_8409_headplay_real enable 1\n");
//cs_8409_headplay_real1(codec);
cs_8409_enable_headset_streaming(codec);
//spec->headset_enable = 2;
}
else if (spec->headset_enable == 2)
{
mycodec_info(codec, "cs_8409_headplay_real enable 2\n");
//cs_8409_headplay_real2(codec);
}
mycodec_info(codec, "cs_8409_headplay_real end\n");
}
static void cs_8409_headplaystop_real(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "cs_8409_headplaystop_real start\n");
cs_8409_disable_headset_streaming(codec);
mycodec_info(codec, "cs_8409_headplaystop_real end\n");
}
static void cs_8409_enable_headset_mike_streaming(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "cs_8409_enable_headset_mike_streaming start\n");
// debug status check - 0x27 here
read_gpio_status_check(codec);
// dont really have any idea how to get to here
// Im guessing from messaging
// NOTE - there are big ordering issues here
// - here we setup the headphone output before the mike
// - this maybe because Quicktime defaults to enabling play when recording
// unfortunately looks as tho linux tends to open the capture stream before the playback stream
// - so going to ignore this here
// this sets up the headphones
// note this only does a partial headset amp setup compared to a base headset play
// power on audio output
//cs42l83_set_power_state_on(codec, 0);
//cs42l83_headset_enable_on(codec);
//retval = cs42l83_headphone_sense(codec);
//mycodec_info(codec, "cs_8409_enable_headset_mike_streaming headphone sense 0x%x\n", retval);
//if (!(retval & 0x80))
//{
// dev_info(hda_codec_dev(codec), "cs_8409_enable_headset_mike_streaming headphone NOT PLUGGED IN UNIMPLEMENTED!!\n");
//}
//retval = cs42l83_headphone_sense(codec);
//mycodec_info(codec, "cs_8409_enable_headset_mike_streaming headphone sense 0x%x\n", retval);
//if (!(retval & 0x80))
//{
// dev_info(hda_codec_dev(codec), "cs_8409_enable_headset_mike_streaming headphone NOT PLUGGED IN UNIMPLEMENTED!!\n");
//}
////cs43l83_headset_amp_format_setup_partial
//cs43l83_headset_amp_format_setup(codec, 0);
cs42l83_headset_mike_format_setup_enable(codec, 0, 1);
cs42l83_input_set_output_sample_rate(codec);
cs42l83_mike_setup_audio_input(codec);
cs42l83_mike_enable(codec);
// power on the codec/audio input
cs42l83_set_power_state_on(codec, 1);
// unmute audio input
cs42l83_headset_mike_adc_unmutevol(codec, 1);
// for partial setup only
//cs42l83_headset_mike_pin_enable(codec);
//cs42l83_headset_mike_format_setup_enable(codec, 0, 1);
// this is all done in the capture hook after this call
//read_gpio_status
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_disambiguate_ur_from_int
//read_gpio_status
//read_gpio_status
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_disambiguate_ur_from_int
//read_gpio_status
mycodec_info(codec, "cs_8409_enable_headset_mike_streaming end\n");
}
static void cs_8409_disable_headset_mike_streaming(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "snd_hda_intel: cs_8409_disable_headset_mike_streaming start\n");
// NOTE - there are big ordering issues here
// although here the mike is turned off before the headphone output
// mute ADC
cs42l83_headset_mike_adc_unmutevol(codec, 0);
cs42l83_power_off_codec_input(codec);
cs42l83_mike_disable(codec);
cs42l83_headset_mike_format_setup_disable(codec);
// and duplicate the above!!
cs42l83_headset_mike_adc_unmutevol(codec, 0);
cs42l83_power_off_codec_input(codec);
// the following is disabling the headphone component
// - assuming this is done by the playback hooks
//cs42l83_headset_enable_off
//cs42l83_power_off_codec_output
//cs42l83_buffers_onoff
//cs42l83_headset_power_off
//cs_8409_headset_amp_disable_TDM_proper (full)
//cs_8409_headset_amp_format_setup_disable
//cs42l83_headset_enable_off
//cs42l83_power_off_codec_output
//cs_8409_external_device_unsolicited_response
//cs_8409_read_status_and_clear_interrupt
//read_gpio_status
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_disambiguate_ur_from_int
//read_gpio_status
// and re-enabling the headphone component?????
// igoring all the following for the moment
// note there was a 7 second delay here - this is recextstop2/2c
//cs43l83_headset_amp_format_setup (full)
//cs42l83_configure_int_mclk
//cs42l83_power_onoff
//cs42l83_configure_serial_port
//cs42l83_output_set_input_sample_rate
//cs42l83_setup_audio_output
//cs42l83_buffers_onoff
//cs42l83_set_power_state_on
//cs42l83_headset_enable_on
//cs_8409_external_device_unsolicited_response
//cs_8409_read_status_and_clear_interrupt
//read_gpio_status
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_disambiguate_ur_from_int
//read_gpio_status
//cs_8409_external_device_unsolicited_response (continued)
//cs_8409_read_status_and_clear_interrupt
//read_gpio_status
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_disambiguate_ur_from_int
//read_gpio_status
// then re-disabling!!
// note there was a 5 second delay here - this is recextstop3
//cs42l83_headset_enable_off
//cs42l83_power_off_codec_output
//cs42l83_headset_rcv_enable_off
//cs42l83_headset_power_off
//cs_8409_headset_amp_disable_TDM_proper - full
//cs42l83_headset_enable_off
//cs42l83_power_off_codec_output
//cs_8409_external_device_unsolicited_response
//cs_8409_read_status_and_clear_interrupt
//read_gpio_status
//read_gpio_status
//cs42l83_read_status_and_clear_interrupt
//read_gpio_status
//cs42l83_disambiguate_ur_from_int
//read_gpio_status
mycodec_info(codec, "snd_hda_intel: cs_8409_disable_headset_mike_streaming end\n");
}
static void cs_8409_headcapture_real(struct hda_codec *codec)
{
//int retval;
struct cs8409_apple_spec *spec = codec->spec;
mycodec_info(codec, "cs_8409_headcapture_real start\n");
if (spec->headset_enable == 0)
{
mycodec_info(codec, "cs_8409_headcapture_real enable 0\n");
//cs_8409_headcapture_real1(codec);
}
else if (spec->headset_enable == 1)
{
mycodec_info(codec, "cs_8409_headcapture_real enable 1\n");
//cs_8409_headcapture_real1(codec);
hda_check_power_state(codec, 0x1a, 11);
hda_check_power_state(codec, 0x3c, 11);
cs_8409_enable_headset_mike_streaming(codec);
hda_check_power_state(codec, 0x1a, 12);
hda_check_power_state(codec, 0x3c, 12);
//spec->headset_enable = 2;
}
else if (spec->headset_enable == 2)
{
mycodec_info(codec, "cs_8409_headcapture_real enable 2\n");
//cs_8409_headcapture_real2(codec);
}
mycodec_info(codec, "cs_8409_headcapture_real end\n");
}
static void cs_8409_headcapturestop_real(struct hda_codec *codec)
{
//int retval;
mycodec_info(codec, "cs_8409_headcapturestop_real start\n");
cs_8409_disable_headset_mike_streaming(codec);
mycodec_info(codec, "cs_8409_headcapturestop_real end\n");
}