|
@@ -32,6 +32,7 @@
|
|
|
#include "hda_codec.h"
|
|
|
#include "hda_local.h"
|
|
|
#include "hda_auto_parser.h"
|
|
|
+#include "hda_jack.h"
|
|
|
|
|
|
#include "ca0132_regs.h"
|
|
|
|
|
@@ -672,22 +673,11 @@ enum ca0132_sample_rate {
|
|
|
SR_RATE_UNKNOWN = 0x1F
|
|
|
};
|
|
|
|
|
|
-/*
|
|
|
- * Scp Helper function
|
|
|
- */
|
|
|
-enum get_set {
|
|
|
- IS_SET = 0,
|
|
|
- IS_GET = 1,
|
|
|
-};
|
|
|
-
|
|
|
-/*
|
|
|
- * Duplicated from ca0110 codec
|
|
|
- */
|
|
|
-
|
|
|
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
|
|
|
{
|
|
|
if (pin) {
|
|
|
- snd_hda_set_pin_ctl(codec, pin, PIN_HP);
|
|
|
+ snd_hda_codec_write(codec, pin, 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
|
|
|
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
|
|
|
snd_hda_codec_write(codec, pin, 0,
|
|
|
AC_VERB_SET_AMP_GAIN_MUTE,
|
|
@@ -701,16 +691,23 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
|
|
|
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
|
|
|
{
|
|
|
if (pin) {
|
|
|
- snd_hda_set_pin_ctl(codec, pin, PIN_IN |
|
|
|
- snd_hda_get_default_vref(codec, pin));
|
|
|
+ snd_hda_codec_write(codec, pin, 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
|
|
|
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
|
|
|
snd_hda_codec_write(codec, pin, 0,
|
|
|
AC_VERB_SET_AMP_GAIN_MUTE,
|
|
|
AMP_IN_UNMUTE(0));
|
|
|
}
|
|
|
- if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP))
|
|
|
+ if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP)) {
|
|
|
snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
|
|
AMP_IN_UNMUTE(0));
|
|
|
+
|
|
|
+ /* init to 0 dB and unmute. */
|
|
|
+ snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0,
|
|
|
+ HDA_AMP_VOLMASK, 0x5a);
|
|
|
+ snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0,
|
|
|
+ HDA_AMP_MUTE, 0);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
|
|
@@ -774,11 +771,18 @@ enum dsp_download_state {
|
|
|
*/
|
|
|
|
|
|
struct ca0132_spec {
|
|
|
+ const struct hda_verb *base_init_verbs;
|
|
|
+ const struct hda_verb *base_exit_verbs;
|
|
|
+ const struct hda_verb *init_verbs[5];
|
|
|
+ unsigned int num_init_verbs; /* exclude base init verbs */
|
|
|
struct auto_pin_cfg autocfg;
|
|
|
+
|
|
|
+ /* Nodes configurations */
|
|
|
struct hda_multi_out multiout;
|
|
|
hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
|
|
|
hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
|
|
|
hda_nid_t hp_dac;
|
|
|
+ unsigned int num_outputs;
|
|
|
hda_nid_t input_pins[AUTO_PIN_LAST];
|
|
|
hda_nid_t adcs[AUTO_PIN_LAST];
|
|
|
hda_nid_t dig_out;
|
|
@@ -788,7 +792,7 @@ struct ca0132_spec {
|
|
|
long curr_hp_volume[2];
|
|
|
long curr_speaker_switch;
|
|
|
const char *input_labels[AUTO_PIN_LAST];
|
|
|
- struct hda_pcm pcm_rec[2]; /* PCM information */
|
|
|
+ struct hda_pcm pcm_rec[5]; /* PCM information */
|
|
|
|
|
|
/* chip access */
|
|
|
struct mutex chipio_mutex; /* chip access mutex */
|
|
@@ -803,6 +807,18 @@ struct ca0132_spec {
|
|
|
unsigned int scp_resp_header;
|
|
|
unsigned int scp_resp_data[4];
|
|
|
unsigned int scp_resp_count;
|
|
|
+
|
|
|
+ /* mixer and effects related */
|
|
|
+ unsigned char dmic_ctl;
|
|
|
+ int cur_out_type;
|
|
|
+ int cur_mic_type;
|
|
|
+ long vnode_lvol[VNODES_COUNT];
|
|
|
+ long vnode_rvol[VNODES_COUNT];
|
|
|
+ long vnode_lswitch[VNODES_COUNT];
|
|
|
+ long vnode_rswitch[VNODES_COUNT];
|
|
|
+ long effects_switch[EFFECTS_COUNT];
|
|
|
+ long voicefx_val;
|
|
|
+ long cur_mic_boost;
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -886,6 +902,7 @@ static int chipio_write_address(struct hda_codec *codec,
|
|
|
*/
|
|
|
static int chipio_write_data(struct hda_codec *codec, unsigned int data)
|
|
|
{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
int res;
|
|
|
|
|
|
/* send low 16 bits of the data */
|
|
@@ -897,6 +914,10 @@ static int chipio_write_data(struct hda_codec *codec, unsigned int data)
|
|
|
data >> 16);
|
|
|
}
|
|
|
|
|
|
+ /*If no error encountered, automatically increment the address
|
|
|
+ as per chip behaviour*/
|
|
|
+ spec->curr_chip_addx = (res != -EIO) ?
|
|
|
+ (spec->curr_chip_addx + 4) : ~0UL;
|
|
|
return res;
|
|
|
}
|
|
|
|
|
@@ -926,6 +947,7 @@ static int chipio_write_data_multiple(struct hda_codec *codec,
|
|
|
*/
|
|
|
static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
|
|
|
{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
int res;
|
|
|
|
|
|
/* post read */
|
|
@@ -943,6 +965,10 @@ static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
|
|
|
0);
|
|
|
}
|
|
|
|
|
|
+ /*If no error encountered, automatically increment the address
|
|
|
+ as per chip behaviour*/
|
|
|
+ spec->curr_chip_addx = (res != -EIO) ?
|
|
|
+ (spec->curr_chip_addx + 4) : ~0UL;
|
|
|
return res;
|
|
|
}
|
|
|
|
|
@@ -1418,6 +1444,21 @@ static int dspio_scp(struct hda_codec *codec,
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Set DSP parameters
|
|
|
+ */
|
|
|
+static int dspio_set_param(struct hda_codec *codec, int mod_id,
|
|
|
+ int req, void *data, unsigned int len)
|
|
|
+{
|
|
|
+ return dspio_scp(codec, mod_id, req, SCP_SET, data, len, NULL, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static int dspio_set_uint_param(struct hda_codec *codec, int mod_id,
|
|
|
+ int req, unsigned int data)
|
|
|
+{
|
|
|
+ return dspio_set_param(codec, mod_id, req, &data, sizeof(unsigned int));
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Allocate a DSP DMA channel via an SCP message
|
|
|
*/
|
|
@@ -2597,6 +2638,9 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Controls stuffs.
|
|
|
+ */
|
|
|
|
|
|
/*
|
|
|
* Mixer controls helpers.
|
|
@@ -2698,6 +2742,300 @@ static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Select the active output.
|
|
|
+ * If autodetect is enabled, output will be selected based on jack detection.
|
|
|
+ * If jack inserted, headphone will be selected, else built-in speakers
|
|
|
+ * If autodetect is disabled, output will be selected based on selection.
|
|
|
+ */
|
|
|
+static int ca0132_select_out(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ unsigned int pin_ctl;
|
|
|
+ int jack_present;
|
|
|
+ int auto_jack;
|
|
|
+ unsigned int tmp;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ snd_printdd(KERN_INFO "ca0132_select_out\n");
|
|
|
+
|
|
|
+ snd_hda_power_up(codec);
|
|
|
+
|
|
|
+ auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
|
|
|
+
|
|
|
+ if (auto_jack)
|
|
|
+ jack_present = snd_hda_jack_detect(codec, spec->out_pins[1]);
|
|
|
+ else
|
|
|
+ jack_present =
|
|
|
+ spec->vnode_lswitch[VNID_HP_SEL - VNODE_START_NID];
|
|
|
+
|
|
|
+ if (jack_present)
|
|
|
+ spec->cur_out_type = HEADPHONE_OUT;
|
|
|
+ else
|
|
|
+ spec->cur_out_type = SPEAKER_OUT;
|
|
|
+
|
|
|
+ if (spec->cur_out_type == SPEAKER_OUT) {
|
|
|
+ snd_printdd(KERN_INFO "ca0132_select_out speaker\n");
|
|
|
+ /*speaker out config*/
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
|
|
|
+ if (err < 0)
|
|
|
+ goto exit;
|
|
|
+ /*enable speaker EQ*/
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
|
|
|
+ if (err < 0)
|
|
|
+ goto exit;
|
|
|
+
|
|
|
+ /* Setup EAPD */
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[1], 0,
|
|
|
+ VENDOR_CHIPIO_EAPD_SEL_SET, 0x02);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_SET_EAPD_BTLENABLE, 0x00);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_EAPD_SEL_SET, 0x00);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_SET_EAPD_BTLENABLE, 0x02);
|
|
|
+
|
|
|
+ /* disable headphone node */
|
|
|
+ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
|
|
|
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[1], 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
+ pin_ctl & 0xBF);
|
|
|
+ /* enable speaker node */
|
|
|
+ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
+ pin_ctl | 0x40);
|
|
|
+ } else {
|
|
|
+ snd_printdd(KERN_INFO "ca0132_select_out hp\n");
|
|
|
+ /*headphone out config*/
|
|
|
+ tmp = FLOAT_ZERO;
|
|
|
+ err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
|
|
|
+ if (err < 0)
|
|
|
+ goto exit;
|
|
|
+ /*disable speaker EQ*/
|
|
|
+ tmp = FLOAT_ZERO;
|
|
|
+ err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
|
|
|
+ if (err < 0)
|
|
|
+ goto exit;
|
|
|
+
|
|
|
+ /* Setup EAPD */
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_EAPD_SEL_SET, 0x00);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_SET_EAPD_BTLENABLE, 0x00);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[1], 0,
|
|
|
+ VENDOR_CHIPIO_EAPD_SEL_SET, 0x02);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_SET_EAPD_BTLENABLE, 0x02);
|
|
|
+
|
|
|
+ /* disable speaker*/
|
|
|
+ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[0], 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
+ pin_ctl & 0xBF);
|
|
|
+ /* enable headphone*/
|
|
|
+ pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
|
|
|
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
+ snd_hda_codec_write(codec, spec->out_pins[1], 0,
|
|
|
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
+ pin_ctl | 0x40);
|
|
|
+ }
|
|
|
+
|
|
|
+exit:
|
|
|
+ snd_hda_power_down(codec);
|
|
|
+
|
|
|
+ return err < 0 ? err : 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void ca0132_set_dmic(struct hda_codec *codec, int enable);
|
|
|
+static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
|
|
|
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Select the active VIP source
|
|
|
+ */
|
|
|
+static int ca0132_set_vipsource(struct hda_codec *codec, int val)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ unsigned int tmp;
|
|
|
+
|
|
|
+ if (!dspload_is_loaded(codec))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* if CrystalVoice if off, vipsource should be 0 */
|
|
|
+ if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ||
|
|
|
+ (val == 0)) {
|
|
|
+ chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
|
|
|
+ chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
|
|
|
+ chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
|
|
|
+ if (spec->cur_mic_type == DIGITAL_MIC)
|
|
|
+ tmp = FLOAT_TWO;
|
|
|
+ else
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
|
|
+ tmp = FLOAT_ZERO;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x05, tmp);
|
|
|
+ } else {
|
|
|
+ chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
|
|
|
+ chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
|
|
|
+ if (spec->cur_mic_type == DIGITAL_MIC)
|
|
|
+ tmp = FLOAT_TWO;
|
|
|
+ else
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x05, tmp);
|
|
|
+ msleep(20);
|
|
|
+ chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Select the active microphone.
|
|
|
+ * If autodetect is enabled, mic will be selected based on jack detection.
|
|
|
+ * If jack inserted, ext.mic will be selected, else built-in mic
|
|
|
+ * If autodetect is disabled, mic will be selected based on selection.
|
|
|
+ */
|
|
|
+static int ca0132_select_mic(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ int jack_present;
|
|
|
+ int auto_jack;
|
|
|
+
|
|
|
+ snd_printdd(KERN_INFO "ca0132_select_mic\n");
|
|
|
+
|
|
|
+ snd_hda_power_up(codec);
|
|
|
+
|
|
|
+ auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
|
|
|
+
|
|
|
+ if (auto_jack)
|
|
|
+ jack_present = snd_hda_jack_detect(codec, spec->input_pins[0]);
|
|
|
+ else
|
|
|
+ jack_present =
|
|
|
+ spec->vnode_lswitch[VNID_AMIC1_SEL - VNODE_START_NID];
|
|
|
+
|
|
|
+ if (jack_present)
|
|
|
+ spec->cur_mic_type = LINE_MIC_IN;
|
|
|
+ else
|
|
|
+ spec->cur_mic_type = DIGITAL_MIC;
|
|
|
+
|
|
|
+ if (spec->cur_mic_type == DIGITAL_MIC) {
|
|
|
+ /* enable digital Mic */
|
|
|
+ chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_32_000);
|
|
|
+ ca0132_set_dmic(codec, 1);
|
|
|
+ ca0132_mic_boost_set(codec, 0);
|
|
|
+ /* set voice focus */
|
|
|
+ ca0132_effects_set(codec, VOICE_FOCUS,
|
|
|
+ spec->effects_switch
|
|
|
+ [VOICE_FOCUS - EFFECT_START_NID]);
|
|
|
+ } else {
|
|
|
+ /* disable digital Mic */
|
|
|
+ chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_96_000);
|
|
|
+ ca0132_set_dmic(codec, 0);
|
|
|
+ ca0132_mic_boost_set(codec, spec->cur_mic_boost);
|
|
|
+ /* disable voice focus */
|
|
|
+ ca0132_effects_set(codec, VOICE_FOCUS, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ snd_hda_power_down(codec);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Set the effects parameters
|
|
|
+ */
|
|
|
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ unsigned int on;
|
|
|
+ int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
|
|
|
+ int err = 0;
|
|
|
+ int idx = nid - EFFECT_START_NID;
|
|
|
+
|
|
|
+ if ((idx < 0) || (idx >= num_fx))
|
|
|
+ return 0; /* no changed */
|
|
|
+
|
|
|
+ /* for out effect, qualify with PE */
|
|
|
+ if ((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) {
|
|
|
+ /* if PE if off, turn off out effects. */
|
|
|
+ if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
|
|
|
+ val = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* for in effect, qualify with CrystalVoice */
|
|
|
+ if ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID)) {
|
|
|
+ /* if CrystalVoice if off, turn off in effects. */
|
|
|
+ if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
|
|
|
+ val = 0;
|
|
|
+
|
|
|
+ /* Voice Focus applies to 2-ch Mic, Digital Mic */
|
|
|
+ if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC))
|
|
|
+ val = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ snd_printdd(KERN_INFO, "ca0132_effect_set: nid=0x%x, val=%ld\n",
|
|
|
+ nid, val);
|
|
|
+
|
|
|
+ on = (val == 0) ? FLOAT_ZERO : FLOAT_ONE;
|
|
|
+ err = dspio_set_uint_param(codec, ca0132_effects[idx].mid,
|
|
|
+ ca0132_effects[idx].reqs[0], on);
|
|
|
+
|
|
|
+ if (err < 0)
|
|
|
+ return 0; /* no changed */
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* Check if Mic1 is streaming, if so, stop streaming */
|
|
|
+static int stop_mic1(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ unsigned int oldval = snd_hda_codec_read(codec, spec->adcs[0], 0,
|
|
|
+ AC_VERB_GET_CONV, 0);
|
|
|
+ if (oldval != 0)
|
|
|
+ snd_hda_codec_write(codec, spec->adcs[0], 0,
|
|
|
+ AC_VERB_SET_CHANNEL_STREAMID,
|
|
|
+ 0);
|
|
|
+ return oldval;
|
|
|
+}
|
|
|
+
|
|
|
+/* Resume Mic1 streaming if it was stopped. */
|
|
|
+static void resume_mic1(struct hda_codec *codec, unsigned int oldval)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ /* Restore the previous stream and channel */
|
|
|
+ if (oldval != 0)
|
|
|
+ snd_hda_codec_write(codec, spec->adcs[0], 0,
|
|
|
+ AC_VERB_SET_CHANNEL_STREAMID,
|
|
|
+ oldval);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Set Mic Boost
|
|
|
+ */
|
|
|
+static int ca0132_mic_boost_set(struct hda_codec *codec, long val)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (val) /* on */
|
|
|
+ ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
|
|
|
+ HDA_INPUT, 0, HDA_AMP_VOLMASK, 3);
|
|
|
+ else /* off */
|
|
|
+ ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
|
|
|
+ HDA_INPUT, 0, HDA_AMP_VOLMASK, 0);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
*/
|
|
|
static struct hda_pcm_stream ca0132_pcm_analog_playback = {
|
|
@@ -2892,7 +3230,7 @@ static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol,
|
|
|
|
|
|
/* any change? */
|
|
|
if ((spec->curr_hp_volume[0] == left_vol) &&
|
|
|
- (spec->curr_hp_volume[1] == right_vol))
|
|
|
+ (spec->curr_hp_volume[1] == right_vol))
|
|
|
return 0;
|
|
|
|
|
|
snd_hda_power_up(codec);
|
|
@@ -2925,7 +3263,7 @@ static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid)
|
|
|
{
|
|
|
struct snd_kcontrol_new knew =
|
|
|
HDA_CODEC_MUTE_MONO("Headphone Playback Switch",
|
|
|
- nid, 1, 0, HDA_OUTPUT);
|
|
|
+ nid, 1, 0, HDA_OUTPUT);
|
|
|
knew.get = ca0132_hp_switch_get;
|
|
|
knew.put = ca0132_hp_switch_put;
|
|
|
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
|
|
@@ -2935,7 +3273,7 @@ static int add_hp_volume(struct hda_codec *codec, hda_nid_t nid)
|
|
|
{
|
|
|
struct snd_kcontrol_new knew =
|
|
|
HDA_CODEC_VOLUME_MONO("Headphone Playback Volume",
|
|
|
- nid, 3, 0, HDA_OUTPUT);
|
|
|
+ nid, 3, 0, HDA_OUTPUT);
|
|
|
knew.get = ca0132_hp_volume_get;
|
|
|
knew.put = ca0132_hp_volume_put;
|
|
|
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
|
|
@@ -2945,7 +3283,7 @@ static int add_speaker_switch(struct hda_codec *codec, hda_nid_t nid)
|
|
|
{
|
|
|
struct snd_kcontrol_new knew =
|
|
|
HDA_CODEC_MUTE_MONO("Speaker Playback Switch",
|
|
|
- nid, 1, 0, HDA_OUTPUT);
|
|
|
+ nid, 1, 0, HDA_OUTPUT);
|
|
|
knew.get = ca0132_speaker_switch_get;
|
|
|
knew.put = ca0132_speaker_switch_put;
|
|
|
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
|
|
@@ -3021,6 +3359,215 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir)
|
|
|
+{
|
|
|
+ unsigned int caps;
|
|
|
+
|
|
|
+ caps = snd_hda_param_read(codec, nid, dir == HDA_OUTPUT ?
|
|
|
+ AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
|
|
|
+ snd_hda_override_amp_caps(codec, nid, dir, caps);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Switch between Digital built-in mic and analog mic.
|
|
|
+ */
|
|
|
+static void ca0132_set_dmic(struct hda_codec *codec, int enable)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ unsigned int tmp;
|
|
|
+ u8 val;
|
|
|
+ unsigned int oldval;
|
|
|
+
|
|
|
+ snd_printdd(KERN_INFO "ca0132_set_dmic: enable=%d\n", enable);
|
|
|
+
|
|
|
+ oldval = stop_mic1(codec);
|
|
|
+ ca0132_set_vipsource(codec, 0);
|
|
|
+ if (enable) {
|
|
|
+ /* set DMic input as 2-ch */
|
|
|
+ tmp = FLOAT_TWO;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
|
|
+
|
|
|
+ val = spec->dmic_ctl;
|
|
|
+ val |= 0x80;
|
|
|
+ snd_hda_codec_write(codec, spec->input_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_DMIC_CTL_SET, val);
|
|
|
+
|
|
|
+ if (!(spec->dmic_ctl & 0x20))
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 1);
|
|
|
+ } else {
|
|
|
+ /* set AMic input as mono */
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
|
|
+
|
|
|
+ val = spec->dmic_ctl;
|
|
|
+ /* clear bit7 and bit5 to disable dmic */
|
|
|
+ val &= 0x5f;
|
|
|
+ snd_hda_codec_write(codec, spec->input_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_DMIC_CTL_SET, val);
|
|
|
+
|
|
|
+ if (!(spec->dmic_ctl & 0x20))
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 0);
|
|
|
+ }
|
|
|
+ ca0132_set_vipsource(codec, 1);
|
|
|
+ resume_mic1(codec, oldval);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialization for Digital Mic.
|
|
|
+ */
|
|
|
+static void ca0132_init_dmic(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ u8 val;
|
|
|
+
|
|
|
+ /* Setup Digital Mic here, but don't enable.
|
|
|
+ * Enable based on jack detect.
|
|
|
+ */
|
|
|
+
|
|
|
+ /* MCLK uses MPIO1, set to enable.
|
|
|
+ * Bit 2-0: MPIO select
|
|
|
+ * Bit 3: set to disable
|
|
|
+ * Bit 7-4: reserved
|
|
|
+ */
|
|
|
+ val = 0x01;
|
|
|
+ snd_hda_codec_write(codec, spec->input_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_DMIC_MCLK_SET, val);
|
|
|
+
|
|
|
+ /* Data1 uses MPIO3. Data2 not use
|
|
|
+ * Bit 2-0: Data1 MPIO select
|
|
|
+ * Bit 3: set disable Data1
|
|
|
+ * Bit 6-4: Data2 MPIO select
|
|
|
+ * Bit 7: set disable Data2
|
|
|
+ */
|
|
|
+ val = 0x83;
|
|
|
+ snd_hda_codec_write(codec, spec->input_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_DMIC_PIN_SET, val);
|
|
|
+
|
|
|
+ /* Use Ch-0 and Ch-1. Rate is 48K, mode 1. Disable DMic first.
|
|
|
+ * Bit 3-0: Channel mask
|
|
|
+ * Bit 4: set for 48KHz, clear for 32KHz
|
|
|
+ * Bit 5: mode
|
|
|
+ * Bit 6: set to select Data2, clear for Data1
|
|
|
+ * Bit 7: set to enable DMic, clear for AMic
|
|
|
+ */
|
|
|
+ val = 0x23;
|
|
|
+ /* keep a copy of dmic ctl val for enable/disable dmic purpuse */
|
|
|
+ spec->dmic_ctl = val;
|
|
|
+ snd_hda_codec_write(codec, spec->input_pins[0], 0,
|
|
|
+ VENDOR_CHIPIO_DMIC_CTL_SET, val);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialization for Analog Mic 2
|
|
|
+ */
|
|
|
+static void ca0132_init_analog_mic2(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+
|
|
|
+ mutex_lock(&spec->chipio_mutex);
|
|
|
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
|
|
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x20);
|
|
|
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
|
|
+ VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19);
|
|
|
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
|
|
+ VENDOR_CHIPIO_8051_DATA_WRITE, 0x00);
|
|
|
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
|
|
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x2D);
|
|
|
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
|
|
+ VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19);
|
|
|
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
|
|
+ VENDOR_CHIPIO_8051_DATA_WRITE, 0x00);
|
|
|
+ mutex_unlock(&spec->chipio_mutex);
|
|
|
+}
|
|
|
+
|
|
|
+static void ca0132_refresh_widget_caps(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+ int i;
|
|
|
+ hda_nid_t nid;
|
|
|
+
|
|
|
+ snd_printdd(KERN_INFO "ca0132_refresh_widget_caps.\n");
|
|
|
+ nid = codec->start_nid;
|
|
|
+ for (i = 0; i < codec->num_nodes; i++, nid++)
|
|
|
+ codec->wcaps[i] = snd_hda_param_read(codec, nid,
|
|
|
+ AC_PAR_AUDIO_WIDGET_CAP);
|
|
|
+
|
|
|
+ for (i = 0; i < spec->multiout.num_dacs; i++)
|
|
|
+ refresh_amp_caps(codec, spec->dacs[i], HDA_OUTPUT);
|
|
|
+
|
|
|
+ for (i = 0; i < spec->num_outputs; i++)
|
|
|
+ refresh_amp_caps(codec, spec->out_pins[i], HDA_OUTPUT);
|
|
|
+
|
|
|
+ for (i = 0; i < spec->num_inputs; i++) {
|
|
|
+ refresh_amp_caps(codec, spec->adcs[i], HDA_INPUT);
|
|
|
+ refresh_amp_caps(codec, spec->input_pins[i], HDA_INPUT);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Setup default parameters for DSP
|
|
|
+ */
|
|
|
+static void ca0132_setup_defaults(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ unsigned int tmp;
|
|
|
+ int num_fx;
|
|
|
+ int idx, i;
|
|
|
+
|
|
|
+ if (!dspload_is_loaded(codec))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* out, in effects + voicefx */
|
|
|
+ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
|
|
|
+ for (idx = 0; idx < num_fx; idx++) {
|
|
|
+ for (i = 0; i <= ca0132_effects[idx].params; i++) {
|
|
|
+ dspio_set_uint_param(codec, ca0132_effects[idx].mid,
|
|
|
+ ca0132_effects[idx].reqs[i],
|
|
|
+ ca0132_effects[idx].def_vals[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*remove DSP headroom*/
|
|
|
+ tmp = FLOAT_ZERO;
|
|
|
+ dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
|
|
|
+
|
|
|
+ /*set speaker EQ bypass attenuation*/
|
|
|
+ dspio_set_uint_param(codec, 0x8f, 0x01, tmp);
|
|
|
+
|
|
|
+ /* set AMic1 and AMic2 as mono mic */
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x01, tmp);
|
|
|
+
|
|
|
+ /* set AMic1 as CrystalVoice input */
|
|
|
+ tmp = FLOAT_ONE;
|
|
|
+ dspio_set_uint_param(codec, 0x80, 0x05, tmp);
|
|
|
+
|
|
|
+ /* set WUH source */
|
|
|
+ tmp = FLOAT_TWO;
|
|
|
+ dspio_set_uint_param(codec, 0x31, 0x00, tmp);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialization of flags in chip
|
|
|
+ */
|
|
|
+static void ca0132_init_flags(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_PORT_A_COMMON_MODE, 0);
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_PORT_D_COMMON_MODE, 0);
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_PORT_A_10KOHM_LOAD, 0);
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0);
|
|
|
+ chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_HIGH_PASS, 1);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialization of parameters in chip
|
|
|
+ */
|
|
|
+static void ca0132_init_params(struct hda_codec *codec)
|
|
|
+{
|
|
|
+ chipio_set_control_param(codec, CONTROL_PARAM_PORTA_160OHM_GAIN, 6);
|
|
|
+ chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6);
|
|
|
+}
|
|
|
|
|
|
static void ca0132_set_ct_ext(struct hda_codec *codec, int enable)
|
|
|
{
|
|
@@ -3038,7 +3585,6 @@ static void ca0132_config(struct hda_codec *codec)
|
|
|
struct ca0132_spec *spec = codec->spec;
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
|
|
- codec->pcm_format_first = 1;
|
|
|
codec->no_sticky_stream = 1;
|
|
|
|
|
|
/* line-outs */
|
|
@@ -3088,16 +3634,115 @@ static void ca0132_config(struct hda_codec *codec)
|
|
|
cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Verbs tables.
|
|
|
+ */
|
|
|
+
|
|
|
+/* Sends before DSP download. */
|
|
|
+static struct hda_verb ca0132_base_init_verbs[] = {
|
|
|
+ /*enable ct extension*/
|
|
|
+ {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1},
|
|
|
+ /*enable DSP node unsol, needed for DSP download*/
|
|
|
+ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_DSP},
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+/* Send at exit. */
|
|
|
+static struct hda_verb ca0132_base_exit_verbs[] = {
|
|
|
+ /*set afg to D3*/
|
|
|
+ {0x01, AC_VERB_SET_POWER_STATE, 0x03},
|
|
|
+ /*disable ct extension*/
|
|
|
+ {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0},
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+/* Other verbs tables. Sends after DSP download. */
|
|
|
+static struct hda_verb ca0132_init_verbs0[] = {
|
|
|
+ /* chip init verbs */
|
|
|
+ {0x15, 0x70D, 0xF0},
|
|
|
+ {0x15, 0x70E, 0xFE},
|
|
|
+ {0x15, 0x707, 0x75},
|
|
|
+ {0x15, 0x707, 0xD3},
|
|
|
+ {0x15, 0x707, 0x09},
|
|
|
+ {0x15, 0x707, 0x53},
|
|
|
+ {0x15, 0x707, 0xD4},
|
|
|
+ {0x15, 0x707, 0xEF},
|
|
|
+ {0x15, 0x707, 0x75},
|
|
|
+ {0x15, 0x707, 0xD3},
|
|
|
+ {0x15, 0x707, 0x09},
|
|
|
+ {0x15, 0x707, 0x02},
|
|
|
+ {0x15, 0x707, 0x37},
|
|
|
+ {0x15, 0x707, 0x78},
|
|
|
+ {0x15, 0x53C, 0xCE},
|
|
|
+ {0x15, 0x575, 0xC9},
|
|
|
+ {0x15, 0x53D, 0xCE},
|
|
|
+ {0x15, 0x5B7, 0xC9},
|
|
|
+ {0x15, 0x70D, 0xE8},
|
|
|
+ {0x15, 0x70E, 0xFE},
|
|
|
+ {0x15, 0x707, 0x02},
|
|
|
+ {0x15, 0x707, 0x68},
|
|
|
+ {0x15, 0x707, 0x62},
|
|
|
+ {0x15, 0x53A, 0xCE},
|
|
|
+ {0x15, 0x546, 0xC9},
|
|
|
+ {0x15, 0x53B, 0xCE},
|
|
|
+ {0x15, 0x5E8, 0xC9},
|
|
|
+ {0x15, 0x717, 0x0D},
|
|
|
+ {0x15, 0x718, 0x20},
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+static struct hda_verb ca0132_init_verbs1[] = {
|
|
|
+ {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_HP},
|
|
|
+ {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_AMIC1},
|
|
|
+ /* config EAPD */
|
|
|
+ {0x0b, 0x78D, 0x00},
|
|
|
+ /*{0x0b, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/
|
|
|
+ /*{0x10, 0x78D, 0x02},*/
|
|
|
+ /*{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
static void ca0132_init_chip(struct hda_codec *codec)
|
|
|
{
|
|
|
struct ca0132_spec *spec = codec->spec;
|
|
|
+ int num_fx;
|
|
|
+ int i;
|
|
|
+ unsigned int on;
|
|
|
|
|
|
mutex_init(&spec->chipio_mutex);
|
|
|
+
|
|
|
+ spec->cur_out_type = SPEAKER_OUT;
|
|
|
+ spec->cur_mic_type = DIGITAL_MIC;
|
|
|
+ spec->cur_mic_boost = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < VNODES_COUNT; i++) {
|
|
|
+ spec->vnode_lvol[i] = 0x5a;
|
|
|
+ spec->vnode_rvol[i] = 0x5a;
|
|
|
+ spec->vnode_lswitch[i] = 0;
|
|
|
+ spec->vnode_rswitch[i] = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Default states for effects are in ca0132_effects[].
|
|
|
+ */
|
|
|
+ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
|
|
|
+ for (i = 0; i < num_fx; i++) {
|
|
|
+ on = (unsigned int)ca0132_effects[i].reqs[0];
|
|
|
+ spec->effects_switch[i] = on ? 1 : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ spec->voicefx_val = 0;
|
|
|
+ spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
|
|
|
+ spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
static void ca0132_exit_chip(struct hda_codec *codec)
|
|
|
{
|
|
|
/* put any chip cleanup stuffs here. */
|
|
|
+
|
|
|
+ if (dspload_is_loaded(codec))
|
|
|
+ dsp_reset(codec);
|
|
|
}
|
|
|
|
|
|
static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k)
|
|
@@ -3155,15 +3800,25 @@ static int ca0132_init(struct hda_codec *codec)
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
int i;
|
|
|
|
|
|
+ spec->dsp_state = DSP_DOWNLOAD_INIT;
|
|
|
+ spec->curr_chip_addx = (unsigned int)INVALID_CHIP_ADDRESS;
|
|
|
+
|
|
|
+ snd_hda_power_up(codec);
|
|
|
+
|
|
|
+ ca0132_init_params(codec);
|
|
|
+ ca0132_init_flags(codec);
|
|
|
+ snd_hda_sequence_write(codec, spec->base_init_verbs);
|
|
|
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
|
|
ca0132_download_dsp(codec);
|
|
|
#endif
|
|
|
+ ca0132_refresh_widget_caps(codec);
|
|
|
+ ca0132_setup_defaults(codec);
|
|
|
+ ca0132_init_analog_mic2(codec);
|
|
|
+ ca0132_init_dmic(codec);
|
|
|
+
|
|
|
+ for (i = 0; i < spec->num_outputs; i++)
|
|
|
+ init_output(codec, spec->out_pins[i], spec->dacs[0]);
|
|
|
|
|
|
- for (i = 0; i < spec->multiout.num_dacs; i++) {
|
|
|
- init_output(codec, spec->out_pins[i],
|
|
|
- spec->multiout.dac_nids[i]);
|
|
|
- }
|
|
|
- init_output(codec, cfg->hp_pins[0], spec->hp_dac);
|
|
|
init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
|
|
|
|
|
|
for (i = 0; i < spec->num_inputs; i++)
|
|
@@ -3171,16 +3826,25 @@ static int ca0132_init(struct hda_codec *codec)
|
|
|
|
|
|
init_input(codec, cfg->dig_in_pin, spec->dig_in);
|
|
|
|
|
|
- ca0132_set_ct_ext(codec, 1);
|
|
|
+ for (i = 0; i < spec->num_init_verbs; i++)
|
|
|
+ snd_hda_sequence_write(codec, spec->init_verbs[i]);
|
|
|
+
|
|
|
+ ca0132_select_out(codec);
|
|
|
+ ca0132_select_mic(codec);
|
|
|
+
|
|
|
+ snd_hda_power_down(codec);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static void ca0132_free(struct hda_codec *codec)
|
|
|
{
|
|
|
- ca0132_set_ct_ext(codec, 0);
|
|
|
+ struct ca0132_spec *spec = codec->spec;
|
|
|
+
|
|
|
+ snd_hda_power_up(codec);
|
|
|
+ snd_hda_sequence_write(codec, spec->base_exit_verbs);
|
|
|
ca0132_exit_chip(codec);
|
|
|
+ snd_hda_power_down(codec);
|
|
|
kfree(codec->spec);
|
|
|
}
|
|
|
|
|
@@ -3191,8 +3855,6 @@ static struct hda_codec_ops ca0132_patch_ops = {
|
|
|
.free = ca0132_free,
|
|
|
};
|
|
|
|
|
|
-
|
|
|
-
|
|
|
static int patch_ca0132(struct hda_codec *codec)
|
|
|
{
|
|
|
struct ca0132_spec *spec;
|
|
@@ -3204,6 +3866,12 @@ static int patch_ca0132(struct hda_codec *codec)
|
|
|
return -ENOMEM;
|
|
|
codec->spec = spec;
|
|
|
|
|
|
+ spec->base_init_verbs = ca0132_base_init_verbs;
|
|
|
+ spec->base_exit_verbs = ca0132_base_exit_verbs;
|
|
|
+ spec->init_verbs[0] = ca0132_init_verbs0;
|
|
|
+ spec->init_verbs[1] = ca0132_init_verbs1;
|
|
|
+ spec->num_init_verbs = 2;
|
|
|
+
|
|
|
ca0132_init_chip(codec);
|
|
|
|
|
|
ca0132_config(codec);
|