ALSA: hda/ca0132: Init chip, DSP effects and mixer settings
authorIan Minett <ian_minett@creativelabs.com>
Fri, 21 Dec 2012 02:53:34 +0000 (18:53 -0800)
committerTakashi Iwai <tiwai@suse.de>
Tue, 15 Jan 2013 15:57:56 +0000 (16:57 +0100)
This patch adds the framework to set effect parameters: ca0132_effects_set()
and ca0132_setup_defaults() are general functions for parameter setting and
initializing to default values. dspio_set_param() and dspio_set_uint_param()
are lower-level fns to simplify setting individual DSP parameters via an
SCP buffer transfer to the firmware.
The CA0132 chip parameter init code is added in ca0132_init_params().
In chipio_[write,read]_data(), the current chip address is auto-incremented
if no error has occurred.
ca0132_select_out() selects the current output. If autodetect is enabled,
use headphones (if jack detected) or speakers (if no jack).
ca0132_select_mic() selects the current mic in. If autodetect is enabled,
use exterior mic (if jack detected) or built-in mic (if no jack).
Init digital mic and switch between dmic and amic with ca0132_init_dmic(),
ca0132_set_dmic(). amic2 is initialized in ca0132_init_analog_mic2().
Finally, add verb tables for configuring DSP firmware.

Signed-off-by: Ian Minett <ian_minett@creativelabs.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_ca0132.c

index 38ac07b8a4ec25f0840d578358cbb2ba5239a142..e4e1684ace6fbea1f817b067a8bf00a4aec99449 100644 (file)
@@ -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);
This page took 0.036255 seconds and 5 git commands to generate.