2005-04-13 12:45:30 +00:00
|
|
|
/*
|
|
|
|
* Universal Interface for Intel High Definition Audio Codec
|
|
|
|
*
|
|
|
|
* HD audio interface patch for SigmaTel STAC92xx
|
|
|
|
*
|
|
|
|
* Copyright (c) 2005 Embedded Alley Solutions, Inc.
|
2005-11-29 14:00:51 +00:00
|
|
|
* Matt Porter <mporter@embeddedalley.com>
|
2005-04-13 12:45:30 +00:00
|
|
|
*
|
|
|
|
* Based on patch_cmedia.c and patch_realtek.c
|
|
|
|
* Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
|
|
|
|
*
|
|
|
|
* This driver is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This driver is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <sound/core.h>
|
2005-06-27 12:59:41 +00:00
|
|
|
#include <sound/asoundef.h>
|
2008-10-15 18:45:38 +00:00
|
|
|
#include <sound/jack.h>
|
2005-04-13 12:45:30 +00:00
|
|
|
#include "hda_codec.h"
|
|
|
|
#include "hda_local.h"
|
2008-07-18 16:20:52 +00:00
|
|
|
#include "hda_beep.h"
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
enum {
|
|
|
|
STAC_VREF_EVENT = 1,
|
|
|
|
STAC_INSERT_EVENT,
|
|
|
|
STAC_PWR_EVENT,
|
|
|
|
STAC_HP_EVENT,
|
|
|
|
};
|
2005-07-04 15:51:39 +00:00
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_AUTO,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_REF,
|
2008-02-03 19:31:47 +00:00
|
|
|
STAC_9200_OQO,
|
2007-08-23 17:04:28 +00:00
|
|
|
STAC_9200_DELL_D21,
|
|
|
|
STAC_9200_DELL_D22,
|
|
|
|
STAC_9200_DELL_D23,
|
|
|
|
STAC_9200_DELL_M21,
|
|
|
|
STAC_9200_DELL_M22,
|
|
|
|
STAC_9200_DELL_M23,
|
|
|
|
STAC_9200_DELL_M24,
|
|
|
|
STAC_9200_DELL_M25,
|
|
|
|
STAC_9200_DELL_M26,
|
|
|
|
STAC_9200_DELL_M27,
|
2008-08-11 08:18:39 +00:00
|
|
|
STAC_9200_M4,
|
|
|
|
STAC_9200_M4_2,
|
2008-03-18 08:53:23 +00:00
|
|
|
STAC_9200_PANASONIC,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_9200_MODELS
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_9205_AUTO,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_9205_REF,
|
2007-08-23 17:04:28 +00:00
|
|
|
STAC_9205_DELL_M42,
|
2007-08-13 13:50:29 +00:00
|
|
|
STAC_9205_DELL_M43,
|
|
|
|
STAC_9205_DELL_M44,
|
2009-01-22 16:40:18 +00:00
|
|
|
STAC_9205_EAPD,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_9205_MODELS
|
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_92HD73XX_AUTO,
|
2008-12-17 13:51:01 +00:00
|
|
|
STAC_92HD73XX_NO_JD, /* no jack-detection */
|
2007-12-13 16:47:21 +00:00
|
|
|
STAC_92HD73XX_REF,
|
2008-11-25 14:18:29 +00:00
|
|
|
STAC_DELL_M6_AMIC,
|
|
|
|
STAC_DELL_M6_DMIC,
|
|
|
|
STAC_DELL_M6_BOTH,
|
2008-11-03 13:12:43 +00:00
|
|
|
STAC_DELL_EQ,
|
2007-12-13 16:47:21 +00:00
|
|
|
STAC_92HD73XX_MODELS
|
|
|
|
};
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_92HD83XXX_AUTO,
|
2008-07-27 08:30:30 +00:00
|
|
|
STAC_92HD83XXX_REF,
|
2009-01-23 01:53:29 +00:00
|
|
|
STAC_92HD83XXX_PWR_REF,
|
2009-02-12 21:50:01 +00:00
|
|
|
STAC_DELL_S14,
|
2008-07-27 08:30:30 +00:00
|
|
|
STAC_92HD83XXX_MODELS
|
|
|
|
};
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_92HD71BXX_AUTO,
|
2007-11-06 10:53:55 +00:00
|
|
|
STAC_92HD71BXX_REF,
|
2008-02-21 06:51:14 +00:00
|
|
|
STAC_DELL_M4_1,
|
|
|
|
STAC_DELL_M4_2,
|
2008-11-21 02:21:43 +00:00
|
|
|
STAC_DELL_M4_3,
|
2008-09-12 16:02:30 +00:00
|
|
|
STAC_HP_M4,
|
2009-01-14 07:27:35 +00:00
|
|
|
STAC_HP_DV5,
|
2009-03-08 22:19:05 +00:00
|
|
|
STAC_HP_HDX,
|
2009-05-03 08:00:44 +00:00
|
|
|
STAC_HP_DV4_1222NR,
|
2007-11-06 10:53:55 +00:00
|
|
|
STAC_92HD71BXX_MODELS
|
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_925x_AUTO,
|
2007-01-08 10:04:17 +00:00
|
|
|
STAC_925x_REF,
|
2008-08-11 08:18:39 +00:00
|
|
|
STAC_M1,
|
|
|
|
STAC_M1_2,
|
|
|
|
STAC_M2,
|
2007-01-08 10:04:17 +00:00
|
|
|
STAC_M2_2,
|
2008-08-11 08:18:39 +00:00
|
|
|
STAC_M3,
|
|
|
|
STAC_M5,
|
|
|
|
STAC_M6,
|
2007-01-08 10:04:17 +00:00
|
|
|
STAC_925x_MODELS
|
|
|
|
};
|
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_922X_AUTO,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_D945_REF,
|
|
|
|
STAC_D945GTP3,
|
|
|
|
STAC_D945GTP5,
|
2007-05-29 14:03:00 +00:00
|
|
|
STAC_INTEL_MAC_V1,
|
|
|
|
STAC_INTEL_MAC_V2,
|
|
|
|
STAC_INTEL_MAC_V3,
|
|
|
|
STAC_INTEL_MAC_V4,
|
|
|
|
STAC_INTEL_MAC_V5,
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
|
|
|
|
* is given, one of the above models will be
|
|
|
|
* chosen according to the subsystem id. */
|
2007-08-23 17:04:28 +00:00
|
|
|
/* for backward compatibility */
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_MACMINI,
|
2007-02-16 12:27:18 +00:00
|
|
|
STAC_MACBOOK,
|
2007-03-15 11:38:15 +00:00
|
|
|
STAC_MACBOOK_PRO_V1,
|
|
|
|
STAC_MACBOOK_PRO_V2,
|
2007-04-27 12:22:36 +00:00
|
|
|
STAC_IMAC_INTEL,
|
2007-05-21 10:41:29 +00:00
|
|
|
STAC_IMAC_INTEL_20,
|
2008-08-04 13:39:59 +00:00
|
|
|
STAC_ECS_202,
|
2007-08-23 17:04:28 +00:00
|
|
|
STAC_922X_DELL_D81,
|
|
|
|
STAC_922X_DELL_D82,
|
|
|
|
STAC_922X_DELL_M81,
|
|
|
|
STAC_922X_DELL_M82,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_922X_MODELS
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
2009-02-26 15:50:43 +00:00
|
|
|
STAC_927X_AUTO,
|
2008-12-17 12:48:29 +00:00
|
|
|
STAC_D965_REF_NO_JD, /* no jack-detection */
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_D965_REF,
|
|
|
|
STAC_D965_3ST,
|
|
|
|
STAC_D965_5ST,
|
2007-08-07 09:48:12 +00:00
|
|
|
STAC_DELL_3ST,
|
2007-12-17 10:58:13 +00:00
|
|
|
STAC_DELL_BIOS,
|
2006-11-24 16:07:44 +00:00
|
|
|
STAC_927X_MODELS
|
|
|
|
};
|
2005-11-29 14:00:51 +00:00
|
|
|
|
2009-03-12 17:17:58 +00:00
|
|
|
enum {
|
|
|
|
STAC_9872_AUTO,
|
|
|
|
STAC_9872_VAIO,
|
|
|
|
STAC_9872_MODELS
|
|
|
|
};
|
|
|
|
|
2008-10-25 05:06:04 +00:00
|
|
|
struct sigmatel_event {
|
|
|
|
hda_nid_t nid;
|
2008-11-25 10:58:19 +00:00
|
|
|
unsigned char type;
|
|
|
|
unsigned char tag;
|
2008-10-25 05:06:04 +00:00
|
|
|
int data;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sigmatel_jack {
|
|
|
|
hda_nid_t nid;
|
|
|
|
int type;
|
|
|
|
struct snd_jack *jack;
|
|
|
|
};
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
struct sigmatel_spec {
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_kcontrol_new *mixers[4];
|
2005-06-27 12:59:41 +00:00
|
|
|
unsigned int num_mixers;
|
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
int board_config;
|
2008-11-16 16:42:34 +00:00
|
|
|
unsigned int eapd_switch: 1;
|
2005-06-27 12:59:41 +00:00
|
|
|
unsigned int surr_switch: 1;
|
2006-01-23 14:27:49 +00:00
|
|
|
unsigned int alt_switch: 1;
|
2006-03-21 10:24:42 +00:00
|
|
|
unsigned int hp_detect: 1;
|
2008-09-27 22:13:47 +00:00
|
|
|
unsigned int spdif_mute: 1;
|
2009-01-20 14:28:38 +00:00
|
|
|
unsigned int check_volume_offset:1;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-01-29 14:28:44 +00:00
|
|
|
/* gpio lines */
|
2008-04-14 11:32:54 +00:00
|
|
|
unsigned int eapd_mask;
|
2008-01-29 14:28:44 +00:00
|
|
|
unsigned int gpio_mask;
|
|
|
|
unsigned int gpio_dir;
|
|
|
|
unsigned int gpio_data;
|
|
|
|
unsigned int gpio_mute;
|
|
|
|
|
2008-08-15 05:45:52 +00:00
|
|
|
/* stream */
|
|
|
|
unsigned int stream_delay;
|
|
|
|
|
2008-01-29 14:28:44 +00:00
|
|
|
/* analog loopback */
|
2009-03-02 13:26:25 +00:00
|
|
|
struct snd_kcontrol_new *aloopback_ctl;
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned char aloopback_mask;
|
|
|
|
unsigned char aloopback_shift;
|
2007-07-31 13:56:24 +00:00
|
|
|
|
2008-01-10 15:55:06 +00:00
|
|
|
/* power management */
|
|
|
|
unsigned int num_pwrs;
|
2008-07-27 08:30:30 +00:00
|
|
|
unsigned int *pwr_mapping;
|
2008-01-10 15:55:06 +00:00
|
|
|
hda_nid_t *pwr_nids;
|
2008-02-06 13:49:44 +00:00
|
|
|
hda_nid_t *dac_list;
|
2008-01-10 15:55:06 +00:00
|
|
|
|
2008-10-25 05:06:04 +00:00
|
|
|
/* jack detection */
|
|
|
|
struct snd_array jacks;
|
|
|
|
|
|
|
|
/* events */
|
|
|
|
struct snd_array events;
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
/* playback */
|
2008-01-22 11:32:30 +00:00
|
|
|
struct hda_input_mux *mono_mux;
|
2008-09-11 13:49:39 +00:00
|
|
|
struct hda_input_mux *amp_mux;
|
2008-01-22 11:32:30 +00:00
|
|
|
unsigned int cur_mmux;
|
2005-04-13 12:45:30 +00:00
|
|
|
struct hda_multi_out multiout;
|
2006-01-23 14:27:49 +00:00
|
|
|
hda_nid_t dac_nids[5];
|
2008-12-19 08:26:08 +00:00
|
|
|
hda_nid_t hp_dacs[5];
|
|
|
|
hda_nid_t speaker_dacs[5];
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2009-01-20 14:28:38 +00:00
|
|
|
int volume_offset;
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
/* capture */
|
|
|
|
hda_nid_t *adc_nids;
|
|
|
|
unsigned int num_adcs;
|
2005-06-14 08:19:34 +00:00
|
|
|
hda_nid_t *mux_nids;
|
|
|
|
unsigned int num_muxes;
|
2006-10-26 15:12:59 +00:00
|
|
|
hda_nid_t *dmic_nids;
|
|
|
|
unsigned int num_dmics;
|
2007-12-13 16:47:21 +00:00
|
|
|
hda_nid_t *dmux_nids;
|
2007-12-18 17:05:52 +00:00
|
|
|
unsigned int num_dmuxes;
|
2008-09-07 10:03:41 +00:00
|
|
|
hda_nid_t *smux_nids;
|
|
|
|
unsigned int num_smuxes;
|
2008-09-16 14:39:37 +00:00
|
|
|
const char **spdif_labels;
|
2008-09-07 10:03:41 +00:00
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
hda_nid_t dig_in_nid;
|
2008-01-22 11:32:30 +00:00
|
|
|
hda_nid_t mono_nid;
|
2008-07-18 16:20:52 +00:00
|
|
|
hda_nid_t anabeep_nid;
|
|
|
|
hda_nid_t digbeep_nid;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
|
|
|
/* pin widgets */
|
|
|
|
hda_nid_t *pin_nids;
|
|
|
|
unsigned int num_pins;
|
|
|
|
|
|
|
|
/* codec specific stuff */
|
|
|
|
struct hda_verb *init;
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_kcontrol_new *mixer;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
|
|
|
/* capture source */
|
2006-10-26 15:12:59 +00:00
|
|
|
struct hda_input_mux *dinput_mux;
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned int cur_dmux[2];
|
2005-06-27 12:59:41 +00:00
|
|
|
struct hda_input_mux *input_mux;
|
2006-01-23 14:27:49 +00:00
|
|
|
unsigned int cur_mux[3];
|
2008-09-07 10:03:41 +00:00
|
|
|
struct hda_input_mux *sinput_mux;
|
|
|
|
unsigned int cur_smux[2];
|
2008-09-13 20:45:39 +00:00
|
|
|
unsigned int cur_amux;
|
|
|
|
hda_nid_t *amp_nids;
|
|
|
|
unsigned int num_amps;
|
2008-08-15 05:45:52 +00:00
|
|
|
unsigned int powerdown_adcs;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
/* i/o switches */
|
|
|
|
unsigned int io_switch[2];
|
2007-09-03 13:29:04 +00:00
|
|
|
unsigned int clfe_swap;
|
2008-12-19 08:26:08 +00:00
|
|
|
hda_nid_t line_switch; /* shared line-in for input and output */
|
|
|
|
hda_nid_t mic_switch; /* shared mic-in for input and output */
|
|
|
|
hda_nid_t hp_switch; /* NID of HP as line-out */
|
2007-09-03 13:29:37 +00:00
|
|
|
unsigned int aloopback;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
struct hda_pcm pcm_rec[2]; /* PCM information */
|
|
|
|
|
|
|
|
/* dynamic controls and input_mux */
|
|
|
|
struct auto_pin_cfg autocfg;
|
2008-07-30 13:01:44 +00:00
|
|
|
struct snd_array kctls;
|
2006-10-26 15:12:59 +00:00
|
|
|
struct hda_input_mux private_dimux;
|
2005-06-27 12:59:41 +00:00
|
|
|
struct hda_input_mux private_imux;
|
2008-09-07 10:03:41 +00:00
|
|
|
struct hda_input_mux private_smux;
|
2008-09-11 13:49:39 +00:00
|
|
|
struct hda_input_mux private_amp_mux;
|
2008-01-22 11:32:30 +00:00
|
|
|
struct hda_input_mux private_mono_mux;
|
2005-04-13 12:45:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9200_adc_nids[1] = {
|
|
|
|
0x03,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9200_mux_nids[1] = {
|
|
|
|
0x0c,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9200_dac_nids[1] = {
|
|
|
|
0x02,
|
|
|
|
};
|
|
|
|
|
2008-01-10 15:55:06 +00:00
|
|
|
static hda_nid_t stac92hd73xx_pwr_nids[8] = {
|
|
|
|
0x0a, 0x0b, 0x0c, 0xd, 0x0e,
|
|
|
|
0x0f, 0x10, 0x11
|
|
|
|
};
|
|
|
|
|
2008-09-08 15:20:05 +00:00
|
|
|
static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
|
|
|
|
0x26, 0,
|
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
static hda_nid_t stac92hd73xx_adc_nids[2] = {
|
|
|
|
0x1a, 0x1b
|
|
|
|
};
|
|
|
|
|
2008-09-13 20:45:39 +00:00
|
|
|
#define DELL_M6_AMP 2
|
|
|
|
static hda_nid_t stac92hd73xx_amp_nids[3] = {
|
|
|
|
0x0b, 0x0c, 0x0e
|
2008-09-11 13:49:39 +00:00
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
#define STAC92HD73XX_NUM_DMICS 2
|
|
|
|
static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
|
|
|
|
0x13, 0x14, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
#define STAC92HD73_DAC_COUNT 5
|
|
|
|
|
|
|
|
static hda_nid_t stac92hd73xx_mux_nids[4] = {
|
|
|
|
0x28, 0x29, 0x2a, 0x2b,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac92hd73xx_dmux_nids[2] = {
|
|
|
|
0x20, 0x21,
|
|
|
|
};
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static hda_nid_t stac92hd73xx_smux_nids[2] = {
|
|
|
|
0x22, 0x23,
|
|
|
|
};
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
#define STAC92HD83XXX_NUM_DMICS 2
|
|
|
|
static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
|
|
|
|
0x11, 0x12, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
#define STAC92HD83_DAC_COUNT 3
|
|
|
|
|
|
|
|
static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
|
|
|
|
0x17, 0x18,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac92hd83xxx_adc_nids[2] = {
|
|
|
|
0x15, 0x16,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
|
|
|
|
0xa, 0xb, 0xd, 0xe,
|
|
|
|
};
|
|
|
|
|
2008-09-08 15:20:05 +00:00
|
|
|
static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
|
|
|
|
0x1e, 0,
|
|
|
|
};
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
static unsigned int stac92hd83xxx_pwr_mapping[4] = {
|
2009-01-23 01:38:42 +00:00
|
|
|
0x03, 0x0c, 0x20, 0x40,
|
2008-07-27 08:30:30 +00:00
|
|
|
};
|
|
|
|
|
2009-01-14 08:40:25 +00:00
|
|
|
static hda_nid_t stac92hd83xxx_amp_nids[1] = {
|
2009-01-13 18:30:07 +00:00
|
|
|
0xc,
|
|
|
|
};
|
|
|
|
|
2008-01-10 15:55:06 +00:00
|
|
|
static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
|
|
|
|
0x0a, 0x0d, 0x0f
|
|
|
|
};
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
static hda_nid_t stac92hd71bxx_adc_nids[2] = {
|
|
|
|
0x12, 0x13,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac92hd71bxx_mux_nids[2] = {
|
|
|
|
0x1a, 0x1b
|
|
|
|
};
|
|
|
|
|
2008-10-10 13:07:23 +00:00
|
|
|
static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
|
|
|
|
0x1c, 0x1d,
|
2007-12-13 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static hda_nid_t stac92hd71bxx_smux_nids[2] = {
|
|
|
|
0x24, 0x25,
|
|
|
|
};
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
#define STAC92HD71BXX_NUM_DMICS 2
|
|
|
|
static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
|
|
|
|
0x18, 0x19, 0
|
|
|
|
};
|
|
|
|
|
2008-09-08 15:20:05 +00:00
|
|
|
static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
|
|
|
|
0x22, 0
|
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static hda_nid_t stac925x_adc_nids[1] = {
|
|
|
|
0x03,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac925x_mux_nids[1] = {
|
|
|
|
0x0f,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac925x_dac_nids[1] = {
|
|
|
|
0x02,
|
|
|
|
};
|
|
|
|
|
2007-10-16 12:27:04 +00:00
|
|
|
#define STAC925X_NUM_DMICS 1
|
|
|
|
static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
|
|
|
|
0x15, 0
|
2007-05-17 07:36:34 +00:00
|
|
|
};
|
|
|
|
|
2007-12-18 17:05:52 +00:00
|
|
|
static hda_nid_t stac925x_dmux_nids[1] = {
|
|
|
|
0x14,
|
|
|
|
};
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static hda_nid_t stac922x_adc_nids[2] = {
|
|
|
|
0x06, 0x07,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac922x_mux_nids[2] = {
|
|
|
|
0x12, 0x13,
|
|
|
|
};
|
|
|
|
|
2009-02-04 22:49:41 +00:00
|
|
|
static hda_nid_t stac927x_slave_dig_outs[2] = {
|
|
|
|
0x1f, 0,
|
|
|
|
};
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
static hda_nid_t stac927x_adc_nids[3] = {
|
|
|
|
0x07, 0x08, 0x09
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac927x_mux_nids[3] = {
|
|
|
|
0x15, 0x16, 0x17
|
|
|
|
};
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static hda_nid_t stac927x_smux_nids[1] = {
|
|
|
|
0x21,
|
|
|
|
};
|
|
|
|
|
2008-02-06 13:49:44 +00:00
|
|
|
static hda_nid_t stac927x_dac_nids[6] = {
|
|
|
|
0x02, 0x03, 0x04, 0x05, 0x06, 0
|
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
static hda_nid_t stac927x_dmux_nids[1] = {
|
|
|
|
0x1b,
|
|
|
|
};
|
|
|
|
|
2007-10-18 15:38:17 +00:00
|
|
|
#define STAC927X_NUM_DMICS 2
|
|
|
|
static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
|
|
|
|
0x13, 0x14, 0
|
|
|
|
};
|
|
|
|
|
2008-09-16 14:39:37 +00:00
|
|
|
static const char *stac927x_spdif_labels[5] = {
|
|
|
|
"Digital Playback", "ADAT", "Analog Mux 1",
|
|
|
|
"Analog Mux 2", "Analog Mux 3"
|
|
|
|
};
|
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
static hda_nid_t stac9205_adc_nids[2] = {
|
|
|
|
0x12, 0x13
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9205_mux_nids[2] = {
|
|
|
|
0x19, 0x1a
|
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
static hda_nid_t stac9205_dmux_nids[1] = {
|
2007-12-18 17:05:52 +00:00
|
|
|
0x1d,
|
2007-12-13 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static hda_nid_t stac9205_smux_nids[1] = {
|
|
|
|
0x21,
|
|
|
|
};
|
|
|
|
|
2007-10-16 12:27:04 +00:00
|
|
|
#define STAC9205_NUM_DMICS 2
|
|
|
|
static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
|
|
|
|
0x17, 0x18, 0
|
2006-10-26 15:12:59 +00:00
|
|
|
};
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
static hda_nid_t stac9200_pin_nids[8] = {
|
2006-09-01 19:03:12 +00:00
|
|
|
0x08, 0x09, 0x0d, 0x0e,
|
|
|
|
0x0f, 0x10, 0x11, 0x12,
|
2005-04-13 12:45:30 +00:00
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static hda_nid_t stac925x_pin_nids[8] = {
|
|
|
|
0x07, 0x08, 0x0a, 0x0b,
|
|
|
|
0x0c, 0x0d, 0x10, 0x11,
|
|
|
|
};
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static hda_nid_t stac922x_pin_nids[10] = {
|
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
|
|
0x0f, 0x10, 0x11, 0x15, 0x1b,
|
|
|
|
};
|
|
|
|
|
2008-02-21 06:51:14 +00:00
|
|
|
static hda_nid_t stac92hd73xx_pin_nids[13] = {
|
2007-12-13 16:47:21 +00:00
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
|
|
0x0f, 0x10, 0x11, 0x12, 0x13,
|
2008-09-07 10:03:41 +00:00
|
|
|
0x14, 0x22, 0x23
|
2007-12-13 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
2009-02-12 21:50:01 +00:00
|
|
|
static hda_nid_t stac92hd83xxx_pin_nids[10] = {
|
2008-07-27 08:30:30 +00:00
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
2009-02-12 21:50:01 +00:00
|
|
|
0x0f, 0x10, 0x11, 0x1f, 0x20,
|
2008-07-27 08:30:30 +00:00
|
|
|
};
|
2009-02-04 16:23:19 +00:00
|
|
|
|
|
|
|
#define STAC92HD71BXX_NUM_PINS 13
|
|
|
|
static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
|
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x00,
|
|
|
|
0x00, 0x14, 0x18, 0x19, 0x1e,
|
|
|
|
0x1f, 0x20, 0x27
|
|
|
|
};
|
|
|
|
static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
|
2007-11-06 10:53:55 +00:00
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
|
|
0x0f, 0x14, 0x18, 0x19, 0x1e,
|
2009-02-04 16:23:19 +00:00
|
|
|
0x1f, 0x20, 0x27
|
2007-11-06 10:53:55 +00:00
|
|
|
};
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
static hda_nid_t stac927x_pin_nids[14] = {
|
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
|
|
0x0f, 0x10, 0x11, 0x12, 0x13,
|
|
|
|
0x14, 0x21, 0x22, 0x23,
|
|
|
|
};
|
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
static hda_nid_t stac9205_pin_nids[12] = {
|
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
|
|
0x0f, 0x14, 0x16, 0x17, 0x18,
|
|
|
|
0x21, 0x22,
|
|
|
|
};
|
|
|
|
|
2008-09-11 13:49:39 +00:00
|
|
|
#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
|
|
|
|
|
|
|
|
static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
hda_nid_t nid = spec->amp_nids[spec->cur_amux];
|
|
|
|
|
|
|
|
kcontrol->private_value ^= get_amp_nid(kcontrol);
|
|
|
|
kcontrol->private_value |= nid;
|
|
|
|
|
|
|
|
return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
hda_nid_t nid = spec->amp_nids[spec->cur_amux];
|
|
|
|
|
|
|
|
kcontrol->private_value ^= get_amp_nid(kcontrol);
|
|
|
|
kcontrol->private_value |= nid;
|
|
|
|
|
|
|
|
return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
|
|
|
|
}
|
|
|
|
|
2006-10-26 15:12:59 +00:00
|
|
|
static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
2006-10-26 15:12:59 +00:00
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
|
2006-10-26 15:12:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
2006-10-26 15:12:59 +00:00
|
|
|
|
|
|
|
return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
|
2006-10-26 15:12:59 +00:00
|
|
|
}
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-09-27 22:13:47 +00:00
|
|
|
struct hda_input_mux *smux = &spec->private_smux;
|
2008-09-07 10:03:41 +00:00
|
|
|
unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
2008-09-27 22:13:47 +00:00
|
|
|
int err, val;
|
|
|
|
hda_nid_t nid;
|
2008-09-07 10:03:41 +00:00
|
|
|
|
2008-09-27 22:13:47 +00:00
|
|
|
err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
|
2008-09-07 10:03:41 +00:00
|
|
|
spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
|
2008-09-27 22:13:47 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (spec->spdif_mute) {
|
|
|
|
if (smux_idx == 0)
|
|
|
|
nid = spec->multiout.dig_out_nid;
|
|
|
|
else
|
|
|
|
nid = codec->slave_dig_outs[smux_idx - 1];
|
|
|
|
if (spec->cur_smux[smux_idx] == smux->num_items - 1)
|
2008-12-01 10:42:09 +00:00
|
|
|
val = HDA_AMP_MUTE;
|
2008-09-27 22:13:47 +00:00
|
|
|
else
|
2008-12-01 10:42:09 +00:00
|
|
|
val = 0;
|
2008-09-27 22:13:47 +00:00
|
|
|
/* un/mute SPDIF out */
|
2008-12-01 10:42:09 +00:00
|
|
|
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
|
|
|
HDA_AMP_MUTE, val);
|
2008-09-27 22:13:47 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2008-09-07 10:03:41 +00:00
|
|
|
}
|
|
|
|
|
2009-05-15 13:33:30 +00:00
|
|
|
static unsigned int stac92xx_vref_set(struct hda_codec *codec,
|
|
|
|
hda_nid_t nid, unsigned int new_vref)
|
|
|
|
{
|
|
|
|
unsigned int error;
|
|
|
|
unsigned int pincfg;
|
|
|
|
pincfg = snd_hda_codec_read(codec, nid, 0,
|
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
|
|
|
|
|
pincfg &= 0xff;
|
|
|
|
pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
|
|
|
|
pincfg |= new_vref;
|
|
|
|
|
|
|
|
if (new_vref == AC_PINCTL_VREF_HIZ)
|
|
|
|
pincfg |= AC_PINCTL_OUT_EN;
|
|
|
|
else
|
|
|
|
pincfg |= AC_PINCTL_IN_EN;
|
|
|
|
|
|
|
|
error = snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
|
|
|
|
if (error < 0)
|
|
|
|
return error;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
unsigned int vref;
|
|
|
|
vref = snd_hda_codec_read(codec, nid, 0,
|
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
|
vref &= AC_PINCTL_VREFEN;
|
|
|
|
return vref;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
unsigned int new_vref;
|
|
|
|
unsigned int error;
|
|
|
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] == 0)
|
|
|
|
new_vref = AC_PINCTL_VREF_80;
|
|
|
|
else if (ucontrol->value.enumerated.item[0] == 1)
|
|
|
|
new_vref = AC_PINCTL_VREF_GRD;
|
|
|
|
else
|
|
|
|
new_vref = AC_PINCTL_VREF_HIZ;
|
|
|
|
|
|
|
|
if (new_vref != stac92xx_vref_get(codec, kcontrol->private_value)) {
|
|
|
|
error = stac92xx_vref_set(codec,
|
|
|
|
kcontrol->private_value, new_vref);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
unsigned int vref = stac92xx_vref_get(codec, kcontrol->private_value);
|
|
|
|
if (vref == AC_PINCTL_VREF_80)
|
|
|
|
ucontrol->value.enumerated.item[0] = 0;
|
|
|
|
else if (vref == AC_PINCTL_VREF_GRD)
|
|
|
|
ucontrol->value.enumerated.item[0] = 1;
|
|
|
|
else if (vref == AC_PINCTL_VREF_HIZ)
|
|
|
|
ucontrol->value.enumerated.item[0] = 2;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
static char *texts[] = {
|
|
|
|
"Mic In", "Line In", "Line Out"
|
|
|
|
};
|
|
|
|
|
|
|
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
|
|
|
uinfo->value.enumerated.items = 3;
|
|
|
|
uinfo->count = 1;
|
|
|
|
if (uinfo->value.enumerated.item >= 3)
|
|
|
|
uinfo->value.enumerated.item = 2;
|
|
|
|
strcpy(uinfo->value.enumerated.name,
|
|
|
|
texts[uinfo->value.enumerated.item]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-17 13:57:47 +00:00
|
|
|
static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2005-06-27 12:59:41 +00:00
|
|
|
return snd_hda_input_mux_info(spec->input_mux, uinfo);
|
2005-04-13 12:45:30 +00:00
|
|
|
}
|
|
|
|
|
2005-11-17 13:57:47 +00:00
|
|
|
static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-17 13:57:47 +00:00
|
|
|
static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
|
2005-04-13 12:45:30 +00:00
|
|
|
spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
|
|
|
|
}
|
|
|
|
|
2008-01-22 11:32:30 +00:00
|
|
|
static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_input_mux_info(spec->mono_mux, uinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_mmux;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
|
|
|
|
spec->mono_nid, &spec->cur_mmux);
|
|
|
|
}
|
|
|
|
|
2008-09-11 13:49:39 +00:00
|
|
|
static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *uinfo)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_input_mux_info(spec->amp_mux, uinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
ucontrol->value.enumerated.item[0] = spec->cur_amux;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct snd_kcontrol *ctl =
|
|
|
|
snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
|
|
|
|
if (!ctl)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
|
|
|
|
SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
|
|
|
|
|
|
|
|
return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
|
|
|
|
0, &spec->cur_amux);
|
|
|
|
}
|
|
|
|
|
2007-09-03 13:29:37 +00:00
|
|
|
#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
|
|
|
|
|
|
|
|
static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
2007-09-03 13:29:37 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
ucontrol->value.integer.value[0] = !!(spec->aloopback &
|
|
|
|
(spec->aloopback_mask << idx));
|
2007-09-03 13:29:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
2007-09-03 13:29:37 +00:00
|
|
|
unsigned int dac_mode;
|
2007-12-13 16:47:21 +00:00
|
|
|
unsigned int val, idx_val;
|
2007-09-03 13:29:37 +00:00
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
idx_val = spec->aloopback_mask << idx;
|
|
|
|
if (ucontrol->value.integer.value[0])
|
|
|
|
val = spec->aloopback | idx_val;
|
|
|
|
else
|
|
|
|
val = spec->aloopback & ~idx_val;
|
2007-11-15 14:54:38 +00:00
|
|
|
if (spec->aloopback == val)
|
2007-09-03 13:29:37 +00:00
|
|
|
return 0;
|
|
|
|
|
2007-11-15 14:54:38 +00:00
|
|
|
spec->aloopback = val;
|
2007-09-03 13:29:37 +00:00
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
/* Only return the bits defined by the shift value of the
|
|
|
|
* first two bytes of the mask
|
|
|
|
*/
|
2007-09-03 13:29:37 +00:00
|
|
|
dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
|
2007-12-13 16:47:21 +00:00
|
|
|
kcontrol->private_value & 0xFFFF, 0x0);
|
|
|
|
dac_mode >>= spec->aloopback_shift;
|
2007-09-03 13:29:37 +00:00
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
if (spec->aloopback & idx_val) {
|
2007-09-03 13:29:37 +00:00
|
|
|
snd_hda_power_up(codec);
|
2007-12-13 16:47:21 +00:00
|
|
|
dac_mode |= idx_val;
|
2007-09-03 13:29:37 +00:00
|
|
|
} else {
|
|
|
|
snd_hda_power_down(codec);
|
2007-12-13 16:47:21 +00:00
|
|
|
dac_mode &= ~idx_val;
|
2007-09-03 13:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
snd_hda_codec_write_cache(codec, codec->afg, 0,
|
|
|
|
kcontrol->private_value >> 16, dac_mode);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
static struct hda_verb stac9200_core_init[] = {
|
2005-04-13 12:45:30 +00:00
|
|
|
/* set dac0mux for dac converter */
|
2005-06-27 12:59:41 +00:00
|
|
|
{ 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
|
2005-04-13 12:45:30 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2007-10-10 08:04:26 +00:00
|
|
|
static struct hda_verb stac9200_eapd_init[] = {
|
|
|
|
/* set dac0mux for dac converter */
|
|
|
|
{0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
|
|
|
|
{0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
static struct hda_verb stac92hd73xx_6ch_core_init[] = {
|
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
|
|
|
/* setup adcs to point to mixer */
|
|
|
|
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
/* setup import muxs */
|
|
|
|
{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2008-03-14 07:46:51 +00:00
|
|
|
static struct hda_verb dell_eq_core_init[] = {
|
|
|
|
/* set master volume to max value without distortion
|
|
|
|
* and direct control */
|
|
|
|
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
|
|
|
|
/* setup adcs to point to mixer */
|
|
|
|
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
/* setup import muxs */
|
|
|
|
{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2008-02-29 11:08:20 +00:00
|
|
|
static struct hda_verb dell_m6_core_init[] = {
|
2008-11-03 13:12:43 +00:00
|
|
|
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2008-02-29 11:08:20 +00:00
|
|
|
/* setup adcs to point to mixer */
|
|
|
|
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
/* setup import muxs */
|
|
|
|
{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
static struct hda_verb stac92hd73xx_8ch_core_init[] = {
|
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
|
|
|
/* setup adcs to point to mixer */
|
|
|
|
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
/* setup import muxs */
|
|
|
|
{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct hda_verb stac92hd73xx_10ch_core_init[] = {
|
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
|
|
|
/* dac3 is connected to import3 mux */
|
|
|
|
{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
|
|
|
|
/* setup adcs to point to mixer */
|
|
|
|
{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
|
|
|
|
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
|
/* setup import muxs */
|
|
|
|
{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
static struct hda_verb stac92hd83xxx_core_init[] = {
|
2009-02-12 21:50:01 +00:00
|
|
|
{ 0xa, AC_VERB_SET_CONNECT_SEL, 0x1},
|
|
|
|
{ 0xb, AC_VERB_SET_CONNECT_SEL, 0x1},
|
|
|
|
{ 0xd, AC_VERB_SET_CONNECT_SEL, 0x0},
|
2008-07-27 08:30:30 +00:00
|
|
|
|
|
|
|
/* power state controls amps */
|
|
|
|
{ 0x01, AC_VERB_SET_EAPD, 1 << 2},
|
2008-12-23 18:53:00 +00:00
|
|
|
{}
|
2008-07-27 08:30:30 +00:00
|
|
|
};
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
static struct hda_verb stac92hd71bxx_core_init[] = {
|
2007-12-14 11:08:04 +00:00
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2008-12-23 18:53:00 +00:00
|
|
|
{}
|
2007-12-14 11:08:04 +00:00
|
|
|
};
|
|
|
|
|
2009-01-26 14:33:52 +00:00
|
|
|
#define HD_DISABLE_PORTF 1
|
2007-12-14 11:08:04 +00:00
|
|
|
static struct hda_verb stac92hd71bxx_analog_core_init[] = {
|
2008-06-13 16:04:33 +00:00
|
|
|
/* start of config #1 */
|
|
|
|
|
|
|
|
/* connect port 0f to audio mixer */
|
|
|
|
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
|
|
|
|
/* start of config #2 */
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2009-01-26 14:33:52 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
|
|
|
|
/* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
|
|
|
|
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
2007-11-06 10:53:55 +00:00
|
|
|
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
|
|
|
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static struct hda_verb stac925x_core_init[] = {
|
|
|
|
/* set dac0mux for dac converter */
|
|
|
|
{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
|
2009-01-15 16:31:00 +00:00
|
|
|
/* mute the master volume */
|
|
|
|
{ 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
|
2007-01-08 10:04:17 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
static struct hda_verb stac922x_core_init[] = {
|
2005-04-13 12:45:30 +00:00
|
|
|
/* set master volume and direct control */
|
2005-06-27 12:59:41 +00:00
|
|
|
{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2005-04-13 12:45:30 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2006-09-01 19:03:12 +00:00
|
|
|
static struct hda_verb d965_core_init[] = {
|
2006-06-28 13:52:16 +00:00
|
|
|
/* set master volume and direct control */
|
2006-09-01 19:03:12 +00:00
|
|
|
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2006-06-28 13:52:16 +00:00
|
|
|
/* unmute node 0x1b */
|
|
|
|
{ 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
|
|
|
|
/* select node 0x03 as DAC */
|
|
|
|
{ 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
static struct hda_verb stac927x_core_init[] = {
|
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2008-07-18 16:20:52 +00:00
|
|
|
/* enable analog pc beep path */
|
|
|
|
{ 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
|
2006-01-23 14:27:49 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
static struct hda_verb stac9205_core_init[] = {
|
|
|
|
/* set master volume and direct control */
|
|
|
|
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
|
2008-07-27 08:30:30 +00:00
|
|
|
/* enable analog pc beep path */
|
|
|
|
{ 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
|
2006-07-31 10:49:34 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2008-01-22 11:32:30 +00:00
|
|
|
#define STAC_MONO_MUX \
|
|
|
|
{ \
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = "Mono Mux", \
|
|
|
|
.count = 1, \
|
|
|
|
.info = stac92xx_mono_mux_enum_info, \
|
|
|
|
.get = stac92xx_mono_mux_enum_get, \
|
|
|
|
.put = stac92xx_mono_mux_enum_put, \
|
|
|
|
}
|
|
|
|
|
2008-09-11 13:49:39 +00:00
|
|
|
#define STAC_AMP_MUX \
|
|
|
|
{ \
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = "Amp Selector Capture Switch", \
|
|
|
|
.count = 1, \
|
|
|
|
.info = stac92xx_amp_mux_enum_info, \
|
|
|
|
.get = stac92xx_amp_mux_enum_get, \
|
|
|
|
.put = stac92xx_amp_mux_enum_put, \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
|
|
|
|
{ \
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = xname, \
|
|
|
|
.index = 0, \
|
|
|
|
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
|
|
|
|
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
|
|
|
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
|
|
|
|
.info = stac92xx_amp_volume_info, \
|
|
|
|
.get = stac92xx_amp_volume_get, \
|
|
|
|
.put = stac92xx_amp_volume_put, \
|
|
|
|
.tlv = { .c = snd_hda_mixer_amp_tlv }, \
|
|
|
|
.private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
|
|
|
|
}
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
|
2007-09-03 13:29:37 +00:00
|
|
|
{ \
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = "Analog Loopback", \
|
2007-12-13 16:47:21 +00:00
|
|
|
.count = cnt, \
|
2007-09-03 13:29:37 +00:00
|
|
|
.info = stac92xx_aloopback_info, \
|
|
|
|
.get = stac92xx_aloopback_get, \
|
|
|
|
.put = stac92xx_aloopback_put, \
|
|
|
|
.private_value = verb_read | (verb_write << 16), \
|
|
|
|
}
|
|
|
|
|
2009-05-15 13:33:30 +00:00
|
|
|
#define DC_BIAS(xname, idx, nid) \
|
|
|
|
{ \
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = xname, \
|
|
|
|
.index = idx, \
|
|
|
|
.info = stac92xx_dc_bias_info, \
|
|
|
|
.get = stac92xx_dc_bias_get, \
|
|
|
|
.put = stac92xx_dc_bias_put, \
|
|
|
|
.private_value = nid, \
|
|
|
|
}
|
|
|
|
|
2005-11-17 13:57:47 +00:00
|
|
|
static struct snd_kcontrol_new stac9200_mixer[] = {
|
2005-04-13 12:45:30 +00:00
|
|
|
HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
|
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2008-09-13 20:45:39 +00:00
|
|
|
#define DELL_M6_MIXER 6
|
2007-12-13 16:47:21 +00:00
|
|
|
static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
|
2008-09-13 20:45:39 +00:00
|
|
|
/* start of config #1 */
|
2007-12-13 16:47:21 +00:00
|
|
|
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
|
|
|
|
|
2008-09-13 20:45:39 +00:00
|
|
|
HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
|
|
|
|
|
|
|
|
/* start of config #2 */
|
|
|
|
HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
|
|
|
|
|
2008-09-13 20:45:39 +00:00
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
|
|
|
|
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
|
2007-12-13 16:47:21 +00:00
|
|
|
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
|
2009-03-02 13:26:25 +00:00
|
|
|
{}
|
|
|
|
};
|
2007-12-13 16:47:21 +00:00
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
|
|
|
|
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
|
2007-12-13 16:47:21 +00:00
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
|
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
|
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
|
|
|
|
static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
|
|
|
|
|
2008-12-20 22:47:24 +00:00
|
|
|
HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
|
2008-07-27 08:30:30 +00:00
|
|
|
|
2008-12-20 22:47:24 +00:00
|
|
|
HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT),
|
2008-07-27 08:30:30 +00:00
|
|
|
|
2008-12-20 22:47:24 +00:00
|
|
|
HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT),
|
2008-07-27 08:30:30 +00:00
|
|
|
|
2008-12-20 22:47:24 +00:00
|
|
|
HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT),
|
2008-07-27 08:30:30 +00:00
|
|
|
|
|
|
|
/*
|
2008-12-20 22:47:24 +00:00
|
|
|
HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT),
|
2008-07-27 08:30:30 +00:00
|
|
|
*/
|
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2007-12-14 11:08:04 +00:00
|
|
|
static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
|
2007-11-07 12:03:12 +00:00
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
|
2008-07-18 16:20:52 +00:00
|
|
|
/* analog pc-beep replaced with digital beep support */
|
|
|
|
/*
|
2008-07-10 15:49:11 +00:00
|
|
|
HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
|
2008-07-18 16:20:52 +00:00
|
|
|
*/
|
2008-07-10 15:49:11 +00:00
|
|
|
|
2008-10-11 17:52:43 +00:00
|
|
|
HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
|
2008-10-10 13:07:23 +00:00
|
|
|
|
2008-10-11 17:52:43 +00:00
|
|
|
HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
|
|
|
|
HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
|
2008-10-10 13:07:23 +00:00
|
|
|
|
|
|
|
HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
|
|
|
|
HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
|
|
|
|
HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
|
2007-11-06 10:53:55 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
|
|
|
|
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
|
|
|
|
};
|
2007-12-14 11:08:04 +00:00
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
|
2007-12-14 11:08:04 +00:00
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
|
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static struct snd_kcontrol_new stac925x_mixer[] = {
|
2009-01-15 16:31:00 +00:00
|
|
|
HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
|
|
|
|
HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
|
2007-01-08 10:04:17 +00:00
|
|
|
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
|
2008-05-25 16:20:06 +00:00
|
|
|
HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
|
2007-01-08 10:04:17 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2007-09-03 13:31:02 +00:00
|
|
|
static struct snd_kcontrol_new stac9205_mixer[] = {
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
|
2005-04-13 12:45:30 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
static struct snd_kcontrol_new stac9205_loopback[] = {
|
|
|
|
STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2006-06-28 13:52:16 +00:00
|
|
|
/* This needs to be generated dynamically based on sequence */
|
2007-09-03 13:31:02 +00:00
|
|
|
static struct snd_kcontrol_new stac922x_mixer[] = {
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
|
2006-06-28 13:52:16 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2007-09-03 13:31:02 +00:00
|
|
|
|
2006-11-23 18:27:12 +00:00
|
|
|
static struct snd_kcontrol_new stac927x_mixer[] = {
|
2007-09-03 13:31:02 +00:00
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
|
|
|
|
|
|
|
|
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
|
2006-07-31 10:49:34 +00:00
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
static struct snd_kcontrol_new stac927x_loopback[] = {
|
|
|
|
STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2007-12-18 17:05:52 +00:00
|
|
|
static struct snd_kcontrol_new stac_dmux_mixer = {
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
.name = "Digital Input Source",
|
|
|
|
/* count set later */
|
|
|
|
.info = stac92xx_dmux_enum_info,
|
|
|
|
.get = stac92xx_dmux_enum_get,
|
|
|
|
.put = stac92xx_dmux_enum_put,
|
|
|
|
};
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static struct snd_kcontrol_new stac_smux_mixer = {
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
2008-09-08 15:36:59 +00:00
|
|
|
.name = "IEC958 Playback Source",
|
2008-09-07 10:03:41 +00:00
|
|
|
/* count set later */
|
|
|
|
.info = stac92xx_smux_enum_info,
|
|
|
|
.get = stac92xx_smux_enum_get,
|
|
|
|
.put = stac92xx_smux_enum_put,
|
|
|
|
};
|
|
|
|
|
2008-01-10 15:53:55 +00:00
|
|
|
static const char *slave_vols[] = {
|
|
|
|
"Front Playback Volume",
|
|
|
|
"Surround Playback Volume",
|
|
|
|
"Center Playback Volume",
|
|
|
|
"LFE Playback Volume",
|
|
|
|
"Side Playback Volume",
|
|
|
|
"Headphone Playback Volume",
|
|
|
|
"Speaker Playback Volume",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *slave_sws[] = {
|
|
|
|
"Front Playback Switch",
|
|
|
|
"Surround Playback Switch",
|
|
|
|
"Center Playback Switch",
|
|
|
|
"LFE Playback Switch",
|
|
|
|
"Side Playback Switch",
|
|
|
|
"Headphone Playback Switch",
|
|
|
|
"Speaker Playback Switch",
|
2008-01-29 11:47:02 +00:00
|
|
|
"IEC958 Playback Switch",
|
2008-01-10 15:53:55 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2008-07-30 13:01:44 +00:00
|
|
|
static void stac92xx_free_kctls(struct hda_codec *codec);
|
2008-11-18 08:32:42 +00:00
|
|
|
static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
|
2008-07-30 13:01:44 +00:00
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static int stac92xx_build_controls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-11-18 08:32:42 +00:00
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
hda_nid_t nid;
|
2005-04-13 12:45:30 +00:00
|
|
|
int err;
|
2005-06-27 12:59:41 +00:00
|
|
|
int i;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
|
|
|
err = snd_hda_add_new_ctls(codec, spec->mixer);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
for (i = 0; i < spec->num_mixers; i++) {
|
|
|
|
err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2007-12-18 17:05:52 +00:00
|
|
|
if (spec->num_dmuxes > 0) {
|
|
|
|
stac_dmux_mixer.count = spec->num_dmuxes;
|
2008-07-30 13:01:45 +00:00
|
|
|
err = snd_hda_ctl_add(codec,
|
2007-12-18 17:05:52 +00:00
|
|
|
snd_ctl_new1(&stac_dmux_mixer, codec));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-09-07 10:03:41 +00:00
|
|
|
if (spec->num_smuxes > 0) {
|
2008-09-27 22:13:47 +00:00
|
|
|
int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
|
|
|
|
struct hda_input_mux *smux = &spec->private_smux;
|
|
|
|
/* check for mute support on SPDIF out */
|
|
|
|
if (wcaps & AC_WCAP_OUT_AMP) {
|
|
|
|
smux->items[smux->num_items].label = "Off";
|
|
|
|
smux->items[smux->num_items].index = 0;
|
|
|
|
smux->num_items++;
|
|
|
|
spec->spdif_mute = 1;
|
|
|
|
}
|
2008-09-07 10:03:41 +00:00
|
|
|
stac_smux_mixer.count = spec->num_smuxes;
|
2008-12-19 09:14:13 +00:00
|
|
|
err = snd_hda_ctl_add(codec,
|
2008-09-07 10:03:41 +00:00
|
|
|
snd_ctl_new1(&stac_smux_mixer, codec));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
if (spec->multiout.dig_out_nid) {
|
|
|
|
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-02-12 17:37:26 +00:00
|
|
|
err = snd_hda_create_spdif_share_sw(codec,
|
|
|
|
&spec->multiout);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
spec->multiout.share_spdif = 1;
|
2005-06-14 08:19:34 +00:00
|
|
|
}
|
2008-10-22 03:28:04 +00:00
|
|
|
if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
|
2005-06-14 08:19:34 +00:00
|
|
|
err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-01-10 15:53:55 +00:00
|
|
|
|
|
|
|
/* if we have no master control, let's create it */
|
|
|
|
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
2008-02-18 12:05:50 +00:00
|
|
|
unsigned int vmaster_tlv[4];
|
2008-01-10 15:53:55 +00:00
|
|
|
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
|
2008-02-18 12:05:50 +00:00
|
|
|
HDA_OUTPUT, vmaster_tlv);
|
2009-01-20 14:28:38 +00:00
|
|
|
/* correct volume offset */
|
|
|
|
vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
|
2008-01-10 15:53:55 +00:00
|
|
|
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
2008-02-18 12:05:50 +00:00
|
|
|
vmaster_tlv, slave_vols);
|
2008-01-10 15:53:55 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
|
|
|
|
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
|
|
|
|
NULL, slave_sws);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
if (spec->aloopback_ctl &&
|
|
|
|
snd_hda_get_bool_hint(codec, "loopback") == 1) {
|
|
|
|
err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-07-30 13:01:44 +00:00
|
|
|
stac92xx_free_kctls(codec); /* no longer needed */
|
2008-11-18 08:32:42 +00:00
|
|
|
|
|
|
|
/* create jack input elements */
|
|
|
|
if (spec->hp_detect) {
|
|
|
|
for (i = 0; i < cfg->hp_outs; i++) {
|
|
|
|
int type = SND_JACK_HEADPHONE;
|
|
|
|
nid = cfg->hp_pins[i];
|
|
|
|
/* jack detection */
|
|
|
|
if (cfg->hp_outs == i)
|
|
|
|
type |= SND_JACK_LINEOUT;
|
|
|
|
err = stac92xx_add_jack(codec, nid, type);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < cfg->line_outs; i++) {
|
|
|
|
err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
|
|
|
|
SND_JACK_LINEOUT);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
|
|
|
nid = cfg->input_pins[i];
|
|
|
|
if (nid) {
|
|
|
|
err = stac92xx_add_jack(codec, nid,
|
|
|
|
SND_JACK_MICROPHONE);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
return 0;
|
2005-04-13 12:45:30 +00:00
|
|
|
}
|
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
static unsigned int ref9200_pin_configs[8] = {
|
2005-06-14 08:19:34 +00:00
|
|
|
0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
|
2005-04-13 12:45:30 +00:00
|
|
|
0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
|
|
|
|
};
|
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static unsigned int gateway9200_m4_pin_configs[8] = {
|
|
|
|
0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
|
|
|
|
0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
|
|
|
|
};
|
|
|
|
static unsigned int gateway9200_m4_2_pin_configs[8] = {
|
|
|
|
0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
|
|
|
|
0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
2007-08-23 17:04:28 +00:00
|
|
|
STAC 9200 pin configs for
|
|
|
|
102801A8
|
|
|
|
102801DE
|
|
|
|
102801E8
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_d21_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
|
|
|
|
0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200 pin configs for
|
|
|
|
102801C0
|
|
|
|
102801C1
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_d22_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
|
|
|
|
0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200 pin configs for
|
|
|
|
102801C4 (Dell Dimension E310)
|
|
|
|
102801C5
|
|
|
|
102801C7
|
|
|
|
102801D9
|
|
|
|
102801DA
|
|
|
|
102801E3
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_d23_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
|
|
|
|
0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32 pin configs for
|
|
|
|
102801B5 (Dell Inspiron 630m)
|
|
|
|
102801D8 (Dell Inspiron 640m)
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m21_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
|
|
|
|
0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32 pin configs for
|
|
|
|
102801C2 (Dell Latitude D620)
|
|
|
|
102801C8
|
|
|
|
102801CC (Dell Latitude D820)
|
|
|
|
102801D4
|
|
|
|
102801D6
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m22_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
|
|
|
|
0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32 pin configs for
|
|
|
|
102801CE (Dell XPS M1710)
|
|
|
|
102801CF (Dell Precision M90)
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m23_pin_configs[8] = {
|
|
|
|
0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
|
|
|
|
0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32 pin configs for
|
|
|
|
102801C9
|
|
|
|
102801CA
|
|
|
|
102801CB (Dell Latitude 120L)
|
|
|
|
102801D3
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m24_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
|
|
|
|
0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32 pin configs for
|
|
|
|
102801BD (Dell Inspiron E1505n)
|
|
|
|
102801EE
|
|
|
|
102801EF
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m25_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
|
|
|
|
0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32 pin configs for
|
|
|
|
102801F5 (Dell Inspiron 1501)
|
|
|
|
102801F6
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m26_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
|
|
|
|
0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9200-32
|
|
|
|
102801CD (Dell Inspiron E1705/9400)
|
|
|
|
*/
|
|
|
|
static unsigned int dell9200_m27_pin_configs[8] = {
|
2007-09-05 21:46:03 +00:00
|
|
|
0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
|
|
|
|
0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
|
2007-08-23 17:04:28 +00:00
|
|
|
};
|
|
|
|
|
2008-02-03 19:31:47 +00:00
|
|
|
static unsigned int oqo9200_pin_configs[8] = {
|
|
|
|
0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
|
|
|
|
0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
|
|
|
|
};
|
|
|
|
|
2007-08-23 17:04:28 +00:00
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
|
|
|
|
[STAC_REF] = ref9200_pin_configs,
|
2008-02-03 19:31:47 +00:00
|
|
|
[STAC_9200_OQO] = oqo9200_pin_configs,
|
2007-08-23 17:04:28 +00:00
|
|
|
[STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
|
|
|
|
[STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
|
|
|
|
[STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
|
|
|
|
[STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
|
|
|
|
[STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
|
|
|
|
[STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
|
|
|
|
[STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
|
|
|
|
[STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
|
|
|
|
[STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
|
|
|
|
[STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
|
2008-08-11 08:18:39 +00:00
|
|
|
[STAC_9200_M4] = gateway9200_m4_pin_configs,
|
|
|
|
[STAC_9200_M4_2] = gateway9200_m4_2_pin_configs,
|
2008-03-18 08:53:23 +00:00
|
|
|
[STAC_9200_PANASONIC] = ref9200_pin_configs,
|
2005-11-29 14:00:51 +00:00
|
|
|
};
|
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
static const char *stac9200_models[STAC_9200_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_AUTO] = "auto",
|
2006-11-24 16:07:44 +00:00
|
|
|
[STAC_REF] = "ref",
|
2008-02-03 19:31:47 +00:00
|
|
|
[STAC_9200_OQO] = "oqo",
|
2007-08-23 17:04:28 +00:00
|
|
|
[STAC_9200_DELL_D21] = "dell-d21",
|
|
|
|
[STAC_9200_DELL_D22] = "dell-d22",
|
|
|
|
[STAC_9200_DELL_D23] = "dell-d23",
|
|
|
|
[STAC_9200_DELL_M21] = "dell-m21",
|
|
|
|
[STAC_9200_DELL_M22] = "dell-m22",
|
|
|
|
[STAC_9200_DELL_M23] = "dell-m23",
|
|
|
|
[STAC_9200_DELL_M24] = "dell-m24",
|
|
|
|
[STAC_9200_DELL_M25] = "dell-m25",
|
|
|
|
[STAC_9200_DELL_M26] = "dell-m26",
|
|
|
|
[STAC_9200_DELL_M27] = "dell-m27",
|
2008-08-11 08:18:39 +00:00
|
|
|
[STAC_9200_M4] = "gateway-m4",
|
|
|
|
[STAC_9200_M4_2] = "gateway-m4-2",
|
2008-03-18 08:53:23 +00:00
|
|
|
[STAC_9200_PANASONIC] = "panasonic",
|
2006-11-24 16:07:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac9200_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
|
|
|
"DFI LanParty", STAC_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_REF),
|
2006-11-06 10:20:38 +00:00
|
|
|
/* Dell laptops have BIOS problem */
|
2007-08-23 17:04:28 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D21),
|
2006-11-24 16:07:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Inspiron 630m", STAC_9200_DELL_M21),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
|
|
|
|
"Dell Inspiron E1505n", STAC_9200_DELL_M25),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D22),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D22),
|
2006-11-24 16:07:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Latitude D620", STAC_9200_DELL_M22),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D23),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D23),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M22),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M24),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M24),
|
2006-11-24 16:07:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Latitude 120L", STAC_9200_DELL_M24),
|
2007-01-30 16:30:55 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Latitude D820", STAC_9200_DELL_M22),
|
2007-02-13 11:46:16 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
|
2007-02-13 11:46:16 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell XPS M1710", STAC_9200_DELL_M23),
|
2007-02-13 23:59:17 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Precision M90", STAC_9200_DELL_M23),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M22),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M22),
|
2007-05-15 09:46:23 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
|
2007-08-23 17:04:28 +00:00
|
|
|
"unknown Dell", STAC_9200_DELL_M22),
|
2007-05-17 07:38:24 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Inspiron 640m", STAC_9200_DELL_M21),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D23),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D23),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D21),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D23),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
|
|
|
|
"unknown Dell", STAC_9200_DELL_D21),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M25),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M25),
|
2007-05-17 07:38:24 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Inspiron 1501", STAC_9200_DELL_M26),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
|
|
|
|
"unknown Dell", STAC_9200_DELL_M26),
|
2007-05-17 07:38:24 +00:00
|
|
|
/* Panasonic */
|
2008-03-18 08:53:23 +00:00
|
|
|
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
|
2007-10-10 08:04:26 +00:00
|
|
|
/* Gateway machines needs EAPD to be set on resume */
|
2008-08-11 08:18:39 +00:00
|
|
|
SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
|
2008-02-03 19:31:47 +00:00
|
|
|
/* OQO Mobile */
|
|
|
|
SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
|
2005-11-29 14:00:51 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static unsigned int ref925x_pin_configs[8] = {
|
|
|
|
0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
|
2008-01-24 10:49:21 +00:00
|
|
|
0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
|
2007-01-08 10:04:17 +00:00
|
|
|
};
|
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static unsigned int stac925xM1_pin_configs[8] = {
|
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
|
2007-01-08 10:04:17 +00:00
|
|
|
};
|
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static unsigned int stac925xM1_2_pin_configs[8] = {
|
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
|
|
|
|
};
|
2008-08-11 08:18:39 +00:00
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static unsigned int stac925xM2_pin_configs[8] = {
|
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
|
2007-05-17 07:36:34 +00:00
|
|
|
};
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static unsigned int stac925xM2_2_pin_configs[8] = {
|
2008-08-11 08:18:39 +00:00
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
|
|
|
|
};
|
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static unsigned int stac925xM3_pin_configs[8] = {
|
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
|
|
|
|
};
|
2008-08-11 08:18:39 +00:00
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static unsigned int stac925xM5_pin_configs[8] = {
|
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int stac925xM6_pin_configs[8] = {
|
|
|
|
0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
|
|
|
|
0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
|
2007-01-08 10:04:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
|
|
|
|
[STAC_REF] = ref925x_pin_configs,
|
2008-08-11 08:18:39 +00:00
|
|
|
[STAC_M1] = stac925xM1_pin_configs,
|
|
|
|
[STAC_M1_2] = stac925xM1_2_pin_configs,
|
|
|
|
[STAC_M2] = stac925xM2_pin_configs,
|
2007-01-08 10:04:17 +00:00
|
|
|
[STAC_M2_2] = stac925xM2_2_pin_configs,
|
2008-08-11 08:18:39 +00:00
|
|
|
[STAC_M3] = stac925xM3_pin_configs,
|
|
|
|
[STAC_M5] = stac925xM5_pin_configs,
|
|
|
|
[STAC_M6] = stac925xM6_pin_configs,
|
2007-01-08 10:04:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *stac925x_models[STAC_925x_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_925x_AUTO] = "auto",
|
2007-01-08 10:04:17 +00:00
|
|
|
[STAC_REF] = "ref",
|
2008-08-11 08:18:39 +00:00
|
|
|
[STAC_M1] = "m1",
|
|
|
|
[STAC_M1_2] = "m1-2",
|
|
|
|
[STAC_M2] = "m2",
|
2007-01-08 10:04:17 +00:00
|
|
|
[STAC_M2_2] = "m2-2",
|
2008-08-11 08:18:39 +00:00
|
|
|
[STAC_M3] = "m3",
|
|
|
|
[STAC_M5] = "m5",
|
|
|
|
[STAC_M6] = "m6",
|
2007-01-08 10:04:17 +00:00
|
|
|
};
|
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
|
2008-08-11 08:18:39 +00:00
|
|
|
SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
|
2008-08-11 08:18:39 +00:00
|
|
|
SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
|
|
|
|
/* Not sure about the brand name for those */
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
|
|
|
|
{} /* terminator */
|
2007-01-08 10:04:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac925x_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
|
2007-05-17 07:36:34 +00:00
|
|
|
SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
|
2008-08-11 08:18:39 +00:00
|
|
|
|
|
|
|
/* Default table for unknown ID */
|
|
|
|
SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2008-02-21 06:51:14 +00:00
|
|
|
static unsigned int ref92hd73xx_pin_configs[13] = {
|
2007-12-13 16:47:21 +00:00
|
|
|
0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
|
|
|
|
0x0181302e, 0x01014010, 0x01014020, 0x01014030,
|
|
|
|
0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
|
2008-02-21 06:51:14 +00:00
|
|
|
0x01452050,
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int dell_m6_pin_configs[13] = {
|
|
|
|
0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
|
2008-04-16 11:13:59 +00:00
|
|
|
0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
|
2008-02-21 06:51:14 +00:00
|
|
|
0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
|
|
|
|
0x4f0000f0,
|
2007-12-13 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
|
2008-02-21 06:51:14 +00:00
|
|
|
[STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
|
2008-11-25 14:18:29 +00:00
|
|
|
[STAC_DELL_M6_AMIC] = dell_m6_pin_configs,
|
|
|
|
[STAC_DELL_M6_DMIC] = dell_m6_pin_configs,
|
|
|
|
[STAC_DELL_M6_BOTH] = dell_m6_pin_configs,
|
2008-11-03 13:12:43 +00:00
|
|
|
[STAC_DELL_EQ] = dell_m6_pin_configs,
|
2007-12-13 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_92HD73XX_AUTO] = "auto",
|
2008-12-17 13:51:01 +00:00
|
|
|
[STAC_92HD73XX_NO_JD] = "no-jd",
|
2007-12-13 16:47:21 +00:00
|
|
|
[STAC_92HD73XX_REF] = "ref",
|
2008-11-25 14:18:29 +00:00
|
|
|
[STAC_DELL_M6_AMIC] = "dell-m6-amic",
|
|
|
|
[STAC_DELL_M6_DMIC] = "dell-m6-dmic",
|
|
|
|
[STAC_DELL_M6_BOTH] = "dell-m6",
|
2008-11-03 13:12:43 +00:00
|
|
|
[STAC_DELL_EQ] = "dell-eq",
|
2007-12-13 16:47:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
2008-02-21 06:51:14 +00:00
|
|
|
"DFI LanParty", STAC_92HD73XX_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_92HD73XX_REF),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
|
2008-11-25 14:18:29 +00:00
|
|
|
"Dell Studio 1535", STAC_DELL_M6_DMIC),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
|
2008-11-25 14:18:29 +00:00
|
|
|
"unknown Dell", STAC_DELL_M6_DMIC),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
|
2008-11-25 14:18:29 +00:00
|
|
|
"unknown Dell", STAC_DELL_M6_BOTH),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
|
2008-11-25 14:18:29 +00:00
|
|
|
"unknown Dell", STAC_DELL_M6_BOTH),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
|
2008-11-25 14:18:29 +00:00
|
|
|
"unknown Dell", STAC_DELL_M6_AMIC),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
|
2008-11-25 14:18:29 +00:00
|
|
|
"unknown Dell", STAC_DELL_M6_AMIC),
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
|
2008-11-25 14:18:29 +00:00
|
|
|
"unknown Dell", STAC_DELL_M6_DMIC),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272,
|
|
|
|
"unknown Dell", STAC_DELL_M6_DMIC),
|
2008-11-21 07:37:03 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
|
2008-11-25 14:18:29 +00:00
|
|
|
"Dell Studio 1537", STAC_DELL_M6_DMIC),
|
2008-12-19 07:13:49 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
|
|
|
|
"Dell Studio 17", STAC_DELL_M6_DMIC),
|
2007-12-13 16:47:21 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2009-02-12 21:50:01 +00:00
|
|
|
static unsigned int ref92hd83xxx_pin_configs[10] = {
|
2008-07-27 08:30:30 +00:00
|
|
|
0x02214030, 0x02211010, 0x02a19020, 0x02170130,
|
|
|
|
0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
|
|
|
|
0x01451160, 0x98560170,
|
|
|
|
};
|
|
|
|
|
2009-02-12 21:50:01 +00:00
|
|
|
static unsigned int dell_s14_pin_configs[10] = {
|
|
|
|
0x02214030, 0x02211010, 0x02a19020, 0x01014050,
|
|
|
|
0x40f000f0, 0x01819040, 0x40f000f0, 0x90a60160,
|
|
|
|
0x40f000f0, 0x40f000f0,
|
|
|
|
};
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
|
|
|
|
[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
|
2009-01-23 01:53:29 +00:00
|
|
|
[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
|
2009-02-12 21:50:01 +00:00
|
|
|
[STAC_DELL_S14] = dell_s14_pin_configs,
|
2008-07-27 08:30:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_92HD83XXX_AUTO] = "auto",
|
2008-07-27 08:30:30 +00:00
|
|
|
[STAC_92HD83XXX_REF] = "ref",
|
2009-01-23 01:53:29 +00:00
|
|
|
[STAC_92HD83XXX_PWR_REF] = "mic-ref",
|
2009-02-12 21:50:01 +00:00
|
|
|
[STAC_DELL_S14] = "dell-s14",
|
2008-07-27 08:30:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
2009-01-13 10:54:49 +00:00
|
|
|
"DFI LanParty", STAC_92HD83XXX_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_92HD83XXX_REF),
|
2009-02-12 21:50:01 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
|
|
|
|
"unknown Dell", STAC_DELL_S14),
|
2008-12-23 18:53:00 +00:00
|
|
|
{} /* terminator */
|
2008-07-27 08:30:30 +00:00
|
|
|
};
|
|
|
|
|
2009-02-04 16:23:19 +00:00
|
|
|
static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
|
2007-11-06 10:53:55 +00:00
|
|
|
0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
|
2008-10-10 13:07:23 +00:00
|
|
|
0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
|
2009-02-04 16:23:19 +00:00
|
|
|
0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
|
|
|
|
0x00000000
|
2007-11-06 10:53:55 +00:00
|
|
|
};
|
|
|
|
|
2009-02-04 16:23:19 +00:00
|
|
|
static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
|
2008-02-21 06:51:14 +00:00
|
|
|
0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
|
2008-03-20 11:10:57 +00:00
|
|
|
0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
|
2009-02-04 16:23:19 +00:00
|
|
|
0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
|
|
|
|
0x00000000
|
2008-02-21 06:51:14 +00:00
|
|
|
};
|
|
|
|
|
2009-02-04 16:23:19 +00:00
|
|
|
static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
|
2008-02-21 06:51:14 +00:00
|
|
|
0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
|
|
|
|
0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
|
2009-02-04 16:23:19 +00:00
|
|
|
0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
|
|
|
|
0x00000000
|
2008-02-21 06:51:14 +00:00
|
|
|
};
|
|
|
|
|
2009-02-04 16:23:19 +00:00
|
|
|
static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
|
2008-11-21 02:21:43 +00:00
|
|
|
0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
|
|
|
|
0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
|
2009-02-04 16:23:19 +00:00
|
|
|
0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
|
|
|
|
0x00000000
|
2008-11-21 02:21:43 +00:00
|
|
|
};
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
|
|
|
|
[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
|
2008-02-21 06:51:14 +00:00
|
|
|
[STAC_DELL_M4_1] = dell_m4_1_pin_configs,
|
|
|
|
[STAC_DELL_M4_2] = dell_m4_2_pin_configs,
|
2008-11-21 02:21:43 +00:00
|
|
|
[STAC_DELL_M4_3] = dell_m4_3_pin_configs,
|
2008-09-12 16:02:30 +00:00
|
|
|
[STAC_HP_M4] = NULL,
|
2009-01-14 07:27:35 +00:00
|
|
|
[STAC_HP_DV5] = NULL,
|
2009-03-08 22:19:05 +00:00
|
|
|
[STAC_HP_HDX] = NULL,
|
2009-05-03 08:00:44 +00:00
|
|
|
[STAC_HP_DV4_1222NR] = NULL,
|
2007-11-06 10:53:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_92HD71BXX_AUTO] = "auto",
|
2007-11-06 10:53:55 +00:00
|
|
|
[STAC_92HD71BXX_REF] = "ref",
|
2008-02-21 06:51:14 +00:00
|
|
|
[STAC_DELL_M4_1] = "dell-m4-1",
|
|
|
|
[STAC_DELL_M4_2] = "dell-m4-2",
|
2008-11-21 02:21:43 +00:00
|
|
|
[STAC_DELL_M4_3] = "dell-m4-3",
|
2008-09-12 16:02:30 +00:00
|
|
|
[STAC_HP_M4] = "hp-m4",
|
2009-01-14 07:27:35 +00:00
|
|
|
[STAC_HP_DV5] = "hp-dv5",
|
2009-03-08 22:19:05 +00:00
|
|
|
[STAC_HP_HDX] = "hp-hdx",
|
2009-05-03 08:00:44 +00:00
|
|
|
[STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
|
2007-11-06 10:53:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
|
|
|
"DFI LanParty", STAC_92HD71BXX_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_92HD71BXX_REF),
|
2009-05-03 08:00:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
|
|
|
|
"HP dv4-1222nr", STAC_HP_DV4_1222NR),
|
2009-03-13 16:04:34 +00:00
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
|
|
|
|
"HP", STAC_HP_DV5),
|
2009-02-16 13:16:36 +00:00
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
|
|
|
|
"HP dv4-7", STAC_HP_DV5),
|
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
|
|
|
|
"HP dv4-7", STAC_HP_DV5),
|
2009-03-10 06:48:57 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
|
|
|
|
"HP HDX", STAC_HP_HDX), /* HDX18 */
|
2008-09-26 14:37:03 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
|
2009-02-16 13:16:36 +00:00
|
|
|
"HP mini 1000", STAC_HP_M4),
|
2009-03-08 22:19:05 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
|
2009-03-10 06:48:57 +00:00
|
|
|
"HP HDX", STAC_HP_HDX), /* HDX16 */
|
2008-02-21 06:51:14 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
|
|
|
|
"unknown Dell", STAC_DELL_M4_1),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
|
|
|
|
"unknown Dell", STAC_DELL_M4_2),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
|
|
|
|
"unknown Dell", STAC_DELL_M4_2),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
|
|
|
|
"unknown Dell", STAC_DELL_M4_2),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
|
|
|
|
"unknown Dell", STAC_DELL_M4_2),
|
2008-11-21 02:21:43 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa,
|
|
|
|
"unknown Dell", STAC_DELL_M4_3),
|
2007-11-06 10:53:55 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
static unsigned int ref922x_pin_configs[10] = {
|
|
|
|
0x01014010, 0x01016011, 0x01012012, 0x0221401f,
|
|
|
|
0x01813122, 0x01011014, 0x01441030, 0x01c41030,
|
2005-04-13 12:45:30 +00:00
|
|
|
0x40000100, 0x40000100,
|
|
|
|
};
|
|
|
|
|
2007-08-23 17:04:28 +00:00
|
|
|
/*
|
|
|
|
STAC 922X pin configs for
|
|
|
|
102801A7
|
|
|
|
102801AB
|
|
|
|
102801A9
|
|
|
|
102801D1
|
|
|
|
102801D2
|
|
|
|
*/
|
|
|
|
static unsigned int dell_922x_d81_pin_configs[10] = {
|
|
|
|
0x02214030, 0x01a19021, 0x01111012, 0x01114010,
|
|
|
|
0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
|
|
|
|
0x01813122, 0x400001f2,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 922X pin configs for
|
|
|
|
102801AC
|
|
|
|
102801D0
|
|
|
|
*/
|
|
|
|
static unsigned int dell_922x_d82_pin_configs[10] = {
|
|
|
|
0x02214030, 0x01a19021, 0x01111012, 0x01114010,
|
|
|
|
0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
|
|
|
|
0x01813122, 0x400001f1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 922X pin configs for
|
|
|
|
102801BF
|
|
|
|
*/
|
|
|
|
static unsigned int dell_922x_m81_pin_configs[10] = {
|
|
|
|
0x0321101f, 0x01112024, 0x01111222, 0x91174220,
|
|
|
|
0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
|
|
|
|
0x40C003f1, 0x405003f0,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9221 A1 pin configs for
|
|
|
|
102801D7 (Dell XPS M1210)
|
|
|
|
*/
|
|
|
|
static unsigned int dell_922x_m82_pin_configs[10] = {
|
2007-11-12 11:43:37 +00:00
|
|
|
0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
|
|
|
|
0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
|
2007-08-23 17:04:28 +00:00
|
|
|
0x508003f3, 0x405003f4,
|
|
|
|
};
|
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
static unsigned int d945gtp3_pin_configs[10] = {
|
2006-01-25 18:20:50 +00:00
|
|
|
0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
|
2005-11-29 14:00:51 +00:00
|
|
|
0x40000100, 0x40000100, 0x40000100, 0x40000100,
|
|
|
|
0x02a19120, 0x40000100,
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int d945gtp5_pin_configs[10] = {
|
2006-01-25 18:20:50 +00:00
|
|
|
0x0221401f, 0x01011012, 0x01813024, 0x01014010,
|
|
|
|
0x01a19021, 0x01016011, 0x01452130, 0x40000100,
|
2005-11-29 14:00:51 +00:00
|
|
|
0x02a19320, 0x40000100,
|
|
|
|
};
|
|
|
|
|
2007-05-29 14:03:00 +00:00
|
|
|
static unsigned int intel_mac_v1_pin_configs[10] = {
|
|
|
|
0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
|
|
|
|
0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
|
|
|
|
0x400000fc, 0x400000fb,
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int intel_mac_v2_pin_configs[10] = {
|
|
|
|
0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
|
|
|
|
0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
|
|
|
|
0x400000fc, 0x400000fb,
|
2007-03-15 11:38:15 +00:00
|
|
|
};
|
|
|
|
|
2007-05-29 14:03:00 +00:00
|
|
|
static unsigned int intel_mac_v3_pin_configs[10] = {
|
|
|
|
0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
|
|
|
|
0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
|
2007-02-16 12:27:18 +00:00
|
|
|
0x400000fc, 0x400000fb,
|
|
|
|
};
|
|
|
|
|
2007-05-29 14:03:00 +00:00
|
|
|
static unsigned int intel_mac_v4_pin_configs[10] = {
|
|
|
|
0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
|
|
|
|
0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
|
2007-04-27 12:22:36 +00:00
|
|
|
0x400000fc, 0x400000fb,
|
|
|
|
};
|
|
|
|
|
2007-05-29 14:03:00 +00:00
|
|
|
static unsigned int intel_mac_v5_pin_configs[10] = {
|
|
|
|
0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
|
|
|
|
0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
|
|
|
|
0x400000fc, 0x400000fb,
|
2007-05-21 10:41:29 +00:00
|
|
|
};
|
|
|
|
|
2008-08-04 13:39:59 +00:00
|
|
|
static unsigned int ecs202_pin_configs[10] = {
|
|
|
|
0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
|
|
|
|
0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
|
|
|
|
0x9037012e, 0x40e000f2,
|
|
|
|
};
|
2007-06-19 10:17:42 +00:00
|
|
|
|
2006-06-28 13:52:16 +00:00
|
|
|
static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
|
2006-11-24 16:07:44 +00:00
|
|
|
[STAC_D945_REF] = ref922x_pin_configs,
|
2006-06-28 13:52:16 +00:00
|
|
|
[STAC_D945GTP3] = d945gtp3_pin_configs,
|
|
|
|
[STAC_D945GTP5] = d945gtp5_pin_configs,
|
2007-05-29 14:03:00 +00:00
|
|
|
[STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
|
|
|
|
[STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
|
|
|
|
[STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
|
|
|
|
[STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
|
|
|
|
[STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
[STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
|
2007-08-23 17:04:28 +00:00
|
|
|
/* for backward compatibility */
|
2007-05-29 14:03:00 +00:00
|
|
|
[STAC_MACMINI] = intel_mac_v3_pin_configs,
|
|
|
|
[STAC_MACBOOK] = intel_mac_v5_pin_configs,
|
|
|
|
[STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
|
|
|
|
[STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
|
|
|
|
[STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
|
|
|
|
[STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
|
2008-08-04 13:39:59 +00:00
|
|
|
[STAC_ECS_202] = ecs202_pin_configs,
|
2007-08-23 17:04:28 +00:00
|
|
|
[STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
|
|
|
|
[STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
|
|
|
|
[STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
|
|
|
|
[STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
|
2005-11-29 14:00:51 +00:00
|
|
|
};
|
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
static const char *stac922x_models[STAC_922X_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_922X_AUTO] = "auto",
|
2006-11-24 16:07:44 +00:00
|
|
|
[STAC_D945_REF] = "ref",
|
|
|
|
[STAC_D945GTP5] = "5stack",
|
|
|
|
[STAC_D945GTP3] = "3stack",
|
2007-05-29 14:03:00 +00:00
|
|
|
[STAC_INTEL_MAC_V1] = "intel-mac-v1",
|
|
|
|
[STAC_INTEL_MAC_V2] = "intel-mac-v2",
|
|
|
|
[STAC_INTEL_MAC_V3] = "intel-mac-v3",
|
|
|
|
[STAC_INTEL_MAC_V4] = "intel-mac-v4",
|
|
|
|
[STAC_INTEL_MAC_V5] = "intel-mac-v5",
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
[STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
|
2007-08-23 17:04:28 +00:00
|
|
|
/* for backward compatibility */
|
2006-11-24 16:07:44 +00:00
|
|
|
[STAC_MACMINI] = "macmini",
|
2007-02-16 12:27:18 +00:00
|
|
|
[STAC_MACBOOK] = "macbook",
|
2007-03-15 11:38:15 +00:00
|
|
|
[STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
|
|
|
|
[STAC_MACBOOK_PRO_V2] = "macbook-pro",
|
2007-04-27 12:22:36 +00:00
|
|
|
[STAC_IMAC_INTEL] = "imac-intel",
|
2007-05-21 10:41:29 +00:00
|
|
|
[STAC_IMAC_INTEL_20] = "imac-intel-20",
|
2008-08-04 13:39:59 +00:00
|
|
|
[STAC_ECS_202] = "ecs202",
|
2007-08-23 17:04:28 +00:00
|
|
|
[STAC_922X_DELL_D81] = "dell-d81",
|
|
|
|
[STAC_922X_DELL_D82] = "dell-d82",
|
|
|
|
[STAC_922X_DELL_M81] = "dell-m81",
|
|
|
|
[STAC_922X_DELL_M82] = "dell-m82",
|
2006-11-24 16:07:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac922x_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
|
|
|
"DFI LanParty", STAC_D945_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_D945_REF),
|
2006-11-24 16:07:44 +00:00
|
|
|
/* Intel 945G based systems */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
|
|
|
|
"Intel D945G", STAC_D945GTP3),
|
|
|
|
/* Intel D945G 5-stack systems */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
|
|
|
|
"Intel D945G", STAC_D945GTP5),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
|
|
|
|
"Intel D945G", STAC_D945GTP5),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
|
|
|
|
"Intel D945G", STAC_D945GTP5),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
|
|
|
|
"Intel D945G", STAC_D945GTP5),
|
|
|
|
/* Intel 945P based systems */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
|
|
|
|
"Intel D945P", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
|
|
|
|
"Intel D945P", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
|
|
|
|
"Intel D945P", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
|
|
|
|
"Intel D945P", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
|
|
|
|
"Intel D945P", STAC_D945GTP3),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
|
|
|
|
"Intel D945P", STAC_D945GTP5),
|
2009-01-23 08:09:43 +00:00
|
|
|
/* other intel */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
|
|
|
|
"Intel D945", STAC_D945_REF),
|
2006-11-24 16:07:44 +00:00
|
|
|
/* other systems */
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
/* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
|
2006-11-24 16:07:44 +00:00
|
|
|
SND_PCI_QUIRK(0x8384, 0x7680,
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
"Mac", STAC_INTEL_MAC_AUTO),
|
2007-08-23 17:04:28 +00:00
|
|
|
/* Dell systems */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D81),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D81),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D81),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D82),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
|
|
|
|
"unknown Dell", STAC_922X_DELL_M81),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D82),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D81),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
|
|
|
|
"unknown Dell", STAC_922X_DELL_D81),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
|
|
|
|
"Dell XPS M1210", STAC_922X_DELL_M82),
|
2008-08-04 13:39:59 +00:00
|
|
|
/* ECS/PC Chips boards */
|
2009-02-09 16:14:52 +00:00
|
|
|
SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000,
|
2009-02-08 21:50:34 +00:00
|
|
|
"ECS/PC chips", STAC_ECS_202),
|
2005-11-29 14:00:51 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
static unsigned int ref927x_pin_configs[14] = {
|
2006-09-01 19:03:12 +00:00
|
|
|
0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
|
|
|
|
0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
|
|
|
|
0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
|
|
|
|
0x01c42190, 0x40000100,
|
2006-01-23 14:27:49 +00:00
|
|
|
};
|
|
|
|
|
2006-09-01 19:03:12 +00:00
|
|
|
static unsigned int d965_3st_pin_configs[14] = {
|
2006-08-22 17:44:45 +00:00
|
|
|
0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
|
|
|
|
0x01a19021, 0x01813024, 0x40000100, 0x40000100,
|
|
|
|
0x40000100, 0x40000100, 0x40000100, 0x40000100,
|
|
|
|
0x40000100, 0x40000100
|
|
|
|
};
|
|
|
|
|
2006-09-01 19:03:12 +00:00
|
|
|
static unsigned int d965_5st_pin_configs[14] = {
|
|
|
|
0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
|
|
|
|
0x01a19040, 0x01011012, 0x01016011, 0x40000100,
|
|
|
|
0x40000100, 0x40000100, 0x40000100, 0x01442070,
|
|
|
|
0x40000100, 0x40000100
|
|
|
|
};
|
|
|
|
|
2007-08-07 09:48:12 +00:00
|
|
|
static unsigned int dell_3st_pin_configs[14] = {
|
|
|
|
0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
|
|
|
|
0x01111212, 0x01116211, 0x01813050, 0x01112214,
|
2007-12-17 10:58:13 +00:00
|
|
|
0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
|
2007-08-07 09:48:12 +00:00
|
|
|
0x40c003fc, 0x40000100
|
|
|
|
};
|
|
|
|
|
2006-09-01 19:03:12 +00:00
|
|
|
static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
|
2008-12-17 12:48:29 +00:00
|
|
|
[STAC_D965_REF_NO_JD] = ref927x_pin_configs,
|
2007-12-17 10:58:13 +00:00
|
|
|
[STAC_D965_REF] = ref927x_pin_configs,
|
|
|
|
[STAC_D965_3ST] = d965_3st_pin_configs,
|
|
|
|
[STAC_D965_5ST] = d965_5st_pin_configs,
|
|
|
|
[STAC_DELL_3ST] = dell_3st_pin_configs,
|
|
|
|
[STAC_DELL_BIOS] = NULL,
|
2006-01-23 14:27:49 +00:00
|
|
|
};
|
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
static const char *stac927x_models[STAC_927X_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_927X_AUTO] = "auto",
|
2008-12-17 12:48:29 +00:00
|
|
|
[STAC_D965_REF_NO_JD] = "ref-no-jd",
|
2007-12-17 10:58:13 +00:00
|
|
|
[STAC_D965_REF] = "ref",
|
|
|
|
[STAC_D965_3ST] = "3stack",
|
|
|
|
[STAC_D965_5ST] = "5stack",
|
|
|
|
[STAC_DELL_3ST] = "dell-3stack",
|
|
|
|
[STAC_DELL_BIOS] = "dell-bios",
|
2006-11-24 16:07:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac927x_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
|
|
|
"DFI LanParty", STAC_D965_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_D965_REF),
|
2006-08-22 17:44:45 +00:00
|
|
|
/* Intel 946 based systems */
|
2006-11-24 16:07:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
|
2006-09-01 19:03:12 +00:00
|
|
|
/* 965 based 3 stack systems */
|
2009-02-09 16:14:52 +00:00
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100,
|
|
|
|
"Intel D965", STAC_D965_3ST),
|
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
|
|
|
|
"Intel D965", STAC_D965_3ST),
|
2007-08-07 09:48:12 +00:00
|
|
|
/* Dell 3 stack systems */
|
2007-12-17 10:58:13 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
|
2007-08-23 17:04:28 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
|
2007-08-07 09:48:12 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
|
2007-12-17 10:58:13 +00:00
|
|
|
/* Dell 3 stack systems with verb table in BIOS */
|
2008-01-10 12:06:26 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
|
2007-12-17 10:58:13 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
|
2008-09-30 10:58:54 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
|
2007-12-17 10:58:13 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
|
2006-09-01 19:03:12 +00:00
|
|
|
/* 965 based 5 stack systems */
|
2009-02-09 16:14:52 +00:00
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300,
|
|
|
|
"Intel D965", STAC_D965_5ST),
|
|
|
|
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
|
|
|
|
"Intel D965", STAC_D965_5ST),
|
2006-01-23 14:27:49 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
static unsigned int ref9205_pin_configs[12] = {
|
|
|
|
0x40000100, 0x40000100, 0x01016011, 0x01014010,
|
2008-01-24 10:49:21 +00:00
|
|
|
0x01813122, 0x01a19021, 0x01019020, 0x40000100,
|
2006-10-26 15:12:59 +00:00
|
|
|
0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
|
2006-07-31 10:49:34 +00:00
|
|
|
};
|
|
|
|
|
2007-08-23 17:04:28 +00:00
|
|
|
/*
|
|
|
|
STAC 9205 pin configs for
|
|
|
|
102801F1
|
|
|
|
102801F2
|
|
|
|
102801FC
|
|
|
|
102801FD
|
|
|
|
10280204
|
|
|
|
1028021F
|
2008-01-11 10:39:06 +00:00
|
|
|
10280228 (Dell Vostro 1500)
|
2007-08-23 17:04:28 +00:00
|
|
|
*/
|
|
|
|
static unsigned int dell_9205_m42_pin_configs[12] = {
|
|
|
|
0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
|
|
|
|
0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
|
|
|
|
0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
STAC 9205 pin configs for
|
|
|
|
102801F9
|
|
|
|
102801FA
|
|
|
|
102801FE
|
|
|
|
102801FF (Dell Precision M4300)
|
|
|
|
10280206
|
|
|
|
10280200
|
|
|
|
10280201
|
|
|
|
*/
|
|
|
|
static unsigned int dell_9205_m43_pin_configs[12] = {
|
2007-08-13 13:50:29 +00:00
|
|
|
0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
|
|
|
|
0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
|
|
|
|
0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
|
|
|
|
};
|
|
|
|
|
2007-08-23 17:04:28 +00:00
|
|
|
static unsigned int dell_9205_m44_pin_configs[12] = {
|
2007-08-13 13:50:29 +00:00
|
|
|
0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
|
|
|
|
0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
|
|
|
|
0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
|
|
|
|
};
|
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
|
2007-08-13 13:50:29 +00:00
|
|
|
[STAC_9205_REF] = ref9205_pin_configs,
|
2007-08-23 17:04:28 +00:00
|
|
|
[STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
|
|
|
|
[STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
|
|
|
|
[STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
|
2009-01-22 16:40:18 +00:00
|
|
|
[STAC_9205_EAPD] = NULL,
|
2006-07-31 10:49:34 +00:00
|
|
|
};
|
|
|
|
|
2006-11-24 16:07:44 +00:00
|
|
|
static const char *stac9205_models[STAC_9205_MODELS] = {
|
2009-02-26 15:50:43 +00:00
|
|
|
[STAC_9205_AUTO] = "auto",
|
2006-11-24 16:07:44 +00:00
|
|
|
[STAC_9205_REF] = "ref",
|
2007-08-23 17:04:28 +00:00
|
|
|
[STAC_9205_DELL_M42] = "dell-m42",
|
2007-08-13 13:50:29 +00:00
|
|
|
[STAC_9205_DELL_M43] = "dell-m43",
|
|
|
|
[STAC_9205_DELL_M44] = "dell-m44",
|
2009-01-22 16:40:18 +00:00
|
|
|
[STAC_9205_EAPD] = "eapd",
|
2006-11-24 16:07:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac9205_cfg_tbl[] = {
|
|
|
|
/* SigmaTel reference board */
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
|
|
|
|
"DFI LanParty", STAC_9205_REF),
|
2009-01-23 03:55:44 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
|
|
|
|
"DFI LanParty", STAC_9205_REF),
|
2009-01-22 16:40:18 +00:00
|
|
|
/* Dell */
|
2007-08-23 17:04:28 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
|
|
|
|
"unknown Dell", STAC_9205_DELL_M42),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
|
|
|
|
"unknown Dell", STAC_9205_DELL_M42),
|
2007-08-13 13:50:29 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
|
2007-09-17 22:52:38 +00:00
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
2007-08-13 13:50:29 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
|
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
|
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
2007-08-23 17:04:28 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
|
|
|
|
"unknown Dell", STAC_9205_DELL_M42),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
|
|
|
|
"unknown Dell", STAC_9205_DELL_M42),
|
2007-08-13 13:50:29 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
|
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
|
2007-08-23 17:04:28 +00:00
|
|
|
"Dell Precision M4300", STAC_9205_DELL_M43),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
|
|
|
|
"unknown Dell", STAC_9205_DELL_M42),
|
2008-06-12 14:27:24 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
|
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
|
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
|
|
|
|
"Dell Precision", STAC_9205_DELL_M43),
|
2007-08-13 13:50:29 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
|
|
|
|
"Dell Inspiron", STAC_9205_DELL_M44),
|
2008-01-11 10:39:06 +00:00
|
|
|
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
|
|
|
|
"Dell Vostro 1500", STAC_9205_DELL_M42),
|
2009-01-22 16:40:18 +00:00
|
|
|
/* Gateway */
|
|
|
|
SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
|
2006-07-31 10:49:34 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2009-02-20 13:33:36 +00:00
|
|
|
static void stac92xx_set_config_regs(struct hda_codec *codec,
|
|
|
|
unsigned int *pincfgs)
|
2006-08-23 16:31:34 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
2009-02-20 13:33:36 +00:00
|
|
|
if (!pincfgs)
|
|
|
|
return;
|
2006-08-23 16:31:34 +00:00
|
|
|
|
2007-07-17 09:52:24 +00:00
|
|
|
for (i = 0; i < spec->num_pins; i++)
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->pin_nids[i] && pincfgs[i])
|
|
|
|
snd_hda_codec_set_pincfg(codec, spec->pin_nids[i],
|
|
|
|
pincfgs[i]);
|
2008-11-18 09:38:56 +00:00
|
|
|
}
|
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
/*
|
2005-06-27 12:59:41 +00:00
|
|
|
* Analog playback callbacks
|
2005-06-14 08:19:34 +00:00
|
|
|
*/
|
2005-06-27 12:59:41 +00:00
|
|
|
static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
2005-06-14 08:19:34 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-08-15 05:45:52 +00:00
|
|
|
if (spec->stream_delay)
|
|
|
|
msleep(spec->stream_delay);
|
2008-02-12 17:37:26 +00:00
|
|
|
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
|
|
|
|
hinfo);
|
2005-04-13 12:45:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2005-11-29 14:00:51 +00:00
|
|
|
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
|
2005-04-13 12:45:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
/*
|
|
|
|
* Digital playback callbacks
|
|
|
|
*/
|
|
|
|
static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-06-14 08:19:34 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-06-14 08:19:34 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
2007-04-05 12:51:48 +00:00
|
|
|
static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
|
|
|
|
stream_tag, format, substream);
|
|
|
|
}
|
|
|
|
|
2009-02-13 10:32:28 +00:00
|
|
|
static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
|
|
|
|
}
|
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
/*
|
|
|
|
* Analog capture callbacks
|
|
|
|
*/
|
|
|
|
static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int stream_tag,
|
|
|
|
unsigned int format,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-08-15 05:45:52 +00:00
|
|
|
hda_nid_t nid = spec->adc_nids[substream->number];
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2008-08-15 05:45:52 +00:00
|
|
|
if (spec->powerdown_adcs) {
|
|
|
|
msleep(40);
|
2008-12-01 10:54:35 +00:00
|
|
|
snd_hda_codec_write(codec, nid, 0,
|
2008-08-15 05:45:52 +00:00
|
|
|
AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
|
|
|
|
}
|
|
|
|
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
|
2005-04-13 12:45:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
|
struct hda_codec *codec,
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_pcm_substream *substream)
|
2005-04-13 12:45:30 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-08-15 05:45:52 +00:00
|
|
|
hda_nid_t nid = spec->adc_nids[substream->number];
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2008-08-15 05:45:52 +00:00
|
|
|
snd_hda_codec_cleanup_stream(codec, nid);
|
|
|
|
if (spec->powerdown_adcs)
|
2008-12-01 10:54:35 +00:00
|
|
|
snd_hda_codec_write(codec, nid, 0,
|
2008-08-15 05:45:52 +00:00
|
|
|
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
2005-04-13 12:45:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
|
|
|
|
.substreams = 1,
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 2,
|
|
|
|
/* NID is set in stac92xx_build_pcms */
|
|
|
|
.ops = {
|
|
|
|
.open = stac92xx_dig_playback_pcm_open,
|
2007-04-05 12:51:48 +00:00
|
|
|
.close = stac92xx_dig_playback_pcm_close,
|
2009-02-13 10:32:28 +00:00
|
|
|
.prepare = stac92xx_dig_playback_pcm_prepare,
|
|
|
|
.cleanup = stac92xx_dig_playback_pcm_cleanup
|
2005-06-14 08:19:34 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
|
|
|
|
.substreams = 1,
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 2,
|
|
|
|
/* NID is set in stac92xx_build_pcms */
|
|
|
|
};
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
|
|
|
|
.substreams = 1,
|
|
|
|
.channels_min = 2,
|
2005-06-27 12:59:41 +00:00
|
|
|
.channels_max = 8,
|
2005-04-13 12:45:30 +00:00
|
|
|
.nid = 0x02, /* NID to query formats and rates */
|
|
|
|
.ops = {
|
|
|
|
.open = stac92xx_playback_pcm_open,
|
|
|
|
.prepare = stac92xx_playback_pcm_prepare,
|
|
|
|
.cleanup = stac92xx_playback_pcm_cleanup
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
|
|
|
|
.substreams = 1,
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 2,
|
|
|
|
.nid = 0x06, /* NID to query formats and rates */
|
|
|
|
.ops = {
|
|
|
|
.open = stac92xx_playback_pcm_open,
|
|
|
|
.prepare = stac92xx_playback_pcm_prepare,
|
|
|
|
.cleanup = stac92xx_playback_pcm_cleanup
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 2,
|
2007-09-03 13:31:02 +00:00
|
|
|
/* NID + .substreams is set in stac92xx_build_pcms */
|
2005-04-13 12:45:30 +00:00
|
|
|
.ops = {
|
|
|
|
.prepare = stac92xx_capture_pcm_prepare,
|
|
|
|
.cleanup = stac92xx_capture_pcm_cleanup
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int stac92xx_build_pcms(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct hda_pcm *info = spec->pcm_rec;
|
|
|
|
|
|
|
|
codec->num_pcms = 1;
|
|
|
|
codec->pcm_info = info;
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
info->name = "STAC92xx Analog";
|
2005-04-13 12:45:30 +00:00
|
|
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
|
2009-01-23 10:55:42 +00:00
|
|
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
|
|
|
|
spec->multiout.dac_nids[0];
|
2005-04-13 12:45:30 +00:00
|
|
|
info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
|
2006-01-23 14:27:49 +00:00
|
|
|
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
|
2007-09-03 13:31:02 +00:00
|
|
|
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
|
2006-01-23 14:27:49 +00:00
|
|
|
|
|
|
|
if (spec->alt_switch) {
|
|
|
|
codec->num_pcms++;
|
|
|
|
info++;
|
|
|
|
info->name = "STAC92xx Analog Alt";
|
|
|
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
|
|
|
|
}
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2005-06-14 08:19:34 +00:00
|
|
|
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
|
|
|
|
codec->num_pcms++;
|
|
|
|
info++;
|
|
|
|
info->name = "STAC92xx Digital";
|
2009-02-11 10:35:15 +00:00
|
|
|
info->pcm_type = spec->autocfg.dig_out_type[0];
|
2005-06-14 08:19:34 +00:00
|
|
|
if (spec->multiout.dig_out_nid) {
|
|
|
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
|
|
|
|
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
|
|
|
|
}
|
|
|
|
if (spec->dig_in_nid) {
|
|
|
|
info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
|
|
|
|
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-23 16:06:28 +00:00
|
|
|
static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
2009-03-23 12:07:47 +00:00
|
|
|
unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
|
2006-03-23 16:06:28 +00:00
|
|
|
pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
|
|
|
|
if (pincap & AC_PINCAP_VREF_100)
|
|
|
|
return AC_PINCTL_VREF_100;
|
|
|
|
if (pincap & AC_PINCAP_VREF_80)
|
|
|
|
return AC_PINCTL_VREF_80;
|
|
|
|
if (pincap & AC_PINCAP_VREF_50)
|
|
|
|
return AC_PINCTL_VREF_50;
|
|
|
|
if (pincap & AC_PINCAP_VREF_GRD)
|
|
|
|
return AC_PINCTL_VREF_GRD;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
|
|
|
|
|
|
|
|
{
|
2007-08-10 15:09:26 +00:00
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
|
2005-11-29 14:00:51 +00:00
|
|
|
}
|
|
|
|
|
2008-04-16 11:13:59 +00:00
|
|
|
#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
|
|
|
|
|
|
|
|
static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
2008-11-12 08:48:04 +00:00
|
|
|
ucontrol->value.integer.value[0] = !!spec->hp_switch;
|
2008-04-16 11:13:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
unsigned char type);
|
|
|
|
|
2008-04-16 11:13:59 +00:00
|
|
|
static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-11-12 08:48:04 +00:00
|
|
|
int nid = kcontrol->private_value;
|
|
|
|
|
|
|
|
spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
|
2008-04-16 11:13:59 +00:00
|
|
|
|
|
|
|
/* check to be sure that the ports are upto date with
|
|
|
|
* switch changes
|
|
|
|
*/
|
2008-11-25 10:58:19 +00:00
|
|
|
stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
|
2008-04-16 11:13:59 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-07-23 13:42:26 +00:00
|
|
|
#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
|
2005-11-29 14:00:51 +00:00
|
|
|
|
|
|
|
static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int io_idx = kcontrol-> private_value & 0xff;
|
|
|
|
|
|
|
|
ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
hda_nid_t nid = kcontrol->private_value >> 8;
|
|
|
|
int io_idx = kcontrol-> private_value & 0xff;
|
2007-11-15 14:54:38 +00:00
|
|
|
unsigned short val = !!ucontrol->value.integer.value[0];
|
2005-11-29 14:00:51 +00:00
|
|
|
|
|
|
|
spec->io_switch[io_idx] = val;
|
|
|
|
|
|
|
|
if (val)
|
|
|
|
stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
|
2006-03-23 16:06:28 +00:00
|
|
|
else {
|
|
|
|
unsigned int pinctl = AC_PINCTL_IN_EN;
|
|
|
|
if (io_idx) /* set VREF for mic */
|
|
|
|
pinctl |= stac92xx_get_vref(codec, nid);
|
|
|
|
stac92xx_auto_set_pinctl(codec, nid, pinctl);
|
|
|
|
}
|
2007-11-12 12:05:16 +00:00
|
|
|
|
|
|
|
/* check the auto-mute again: we need to mute/unmute the speaker
|
|
|
|
* appropriately according to the pin direction
|
|
|
|
*/
|
|
|
|
if (spec->hp_detect)
|
2008-11-25 10:58:19 +00:00
|
|
|
stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
|
2007-11-12 12:05:16 +00:00
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-09-03 13:29:04 +00:00
|
|
|
#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
|
|
|
|
|
|
|
|
static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
ucontrol->value.integer.value[0] = spec->clfe_swap;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
hda_nid_t nid = kcontrol->private_value & 0xff;
|
2007-11-15 14:54:38 +00:00
|
|
|
unsigned int val = !!ucontrol->value.integer.value[0];
|
2007-09-03 13:29:04 +00:00
|
|
|
|
2007-11-15 14:54:38 +00:00
|
|
|
if (spec->clfe_swap == val)
|
2007-09-03 13:29:04 +00:00
|
|
|
return 0;
|
|
|
|
|
2007-11-15 14:54:38 +00:00
|
|
|
spec->clfe_swap = val;
|
2007-09-03 13:29:04 +00:00
|
|
|
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
|
|
|
|
spec->clfe_swap ? 0x4 : 0x0);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-16 11:13:59 +00:00
|
|
|
#define STAC_CODEC_HP_SWITCH(xname) \
|
|
|
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = xname, \
|
|
|
|
.index = 0, \
|
|
|
|
.info = stac92xx_hp_switch_info, \
|
|
|
|
.get = stac92xx_hp_switch_get, \
|
|
|
|
.put = stac92xx_hp_switch_put, \
|
|
|
|
}
|
|
|
|
|
2005-11-29 14:00:51 +00:00
|
|
|
#define STAC_CODEC_IO_SWITCH(xname, xpval) \
|
|
|
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = xname, \
|
|
|
|
.index = 0, \
|
|
|
|
.info = stac92xx_io_switch_info, \
|
|
|
|
.get = stac92xx_io_switch_get, \
|
|
|
|
.put = stac92xx_io_switch_put, \
|
|
|
|
.private_value = xpval, \
|
|
|
|
}
|
|
|
|
|
2007-09-03 13:29:04 +00:00
|
|
|
#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
|
|
|
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
.name = xname, \
|
|
|
|
.index = 0, \
|
|
|
|
.info = stac92xx_clfe_switch_info, \
|
|
|
|
.get = stac92xx_clfe_switch_get, \
|
|
|
|
.put = stac92xx_clfe_switch_put, \
|
|
|
|
.private_value = xpval, \
|
|
|
|
}
|
2005-11-29 14:00:51 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
enum {
|
|
|
|
STAC_CTL_WIDGET_VOL,
|
|
|
|
STAC_CTL_WIDGET_MUTE,
|
2008-01-24 10:49:21 +00:00
|
|
|
STAC_CTL_WIDGET_MONO_MUX,
|
2008-09-11 13:49:39 +00:00
|
|
|
STAC_CTL_WIDGET_AMP_MUX,
|
|
|
|
STAC_CTL_WIDGET_AMP_VOL,
|
2008-04-16 11:13:59 +00:00
|
|
|
STAC_CTL_WIDGET_HP_SWITCH,
|
2005-11-29 14:00:51 +00:00
|
|
|
STAC_CTL_WIDGET_IO_SWITCH,
|
2009-05-15 13:33:30 +00:00
|
|
|
STAC_CTL_WIDGET_CLFE_SWITCH,
|
|
|
|
STAC_CTL_WIDGET_DC_BIAS
|
2005-06-27 12:59:41 +00:00
|
|
|
};
|
|
|
|
|
2005-11-17 13:57:47 +00:00
|
|
|
static struct snd_kcontrol_new stac92xx_control_templates[] = {
|
2005-06-27 12:59:41 +00:00
|
|
|
HDA_CODEC_VOLUME(NULL, 0, 0, 0),
|
|
|
|
HDA_CODEC_MUTE(NULL, 0, 0, 0),
|
2008-01-24 10:49:21 +00:00
|
|
|
STAC_MONO_MUX,
|
2008-09-11 13:49:39 +00:00
|
|
|
STAC_AMP_MUX,
|
|
|
|
STAC_AMP_VOL(NULL, 0, 0, 0, 0),
|
2008-04-16 11:13:59 +00:00
|
|
|
STAC_CODEC_HP_SWITCH(NULL),
|
2005-11-29 14:00:51 +00:00
|
|
|
STAC_CODEC_IO_SWITCH(NULL, 0),
|
2007-09-03 13:29:04 +00:00
|
|
|
STAC_CODEC_CLFE_SWITCH(NULL, 0),
|
2009-05-15 13:33:30 +00:00
|
|
|
DC_BIAS(NULL, 0, 0),
|
2005-06-27 12:59:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* add dynamic controls */
|
2009-01-23 10:57:22 +00:00
|
|
|
static struct snd_kcontrol_new *
|
|
|
|
stac_control_new(struct sigmatel_spec *spec,
|
|
|
|
struct snd_kcontrol_new *ktemp,
|
|
|
|
const char *name)
|
2005-06-27 12:59:41 +00:00
|
|
|
{
|
2005-11-17 13:57:47 +00:00
|
|
|
struct snd_kcontrol_new *knew;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-07-30 13:01:44 +00:00
|
|
|
snd_array_init(&spec->kctls, sizeof(*knew), 32);
|
|
|
|
knew = snd_array_new(&spec->kctls);
|
|
|
|
if (!knew)
|
2009-01-23 10:57:22 +00:00
|
|
|
return NULL;
|
2008-11-12 15:45:04 +00:00
|
|
|
*knew = *ktemp;
|
2005-06-30 08:54:33 +00:00
|
|
|
knew->name = kstrdup(name, GFP_KERNEL);
|
2009-01-23 10:57:22 +00:00
|
|
|
if (!knew->name) {
|
|
|
|
/* roolback */
|
|
|
|
memset(knew, 0, sizeof(*knew));
|
|
|
|
spec->kctls.alloced--;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return knew;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
|
|
|
|
struct snd_kcontrol_new *ktemp,
|
|
|
|
int idx, const char *name,
|
|
|
|
unsigned long val)
|
|
|
|
{
|
|
|
|
struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name);
|
|
|
|
if (!knew)
|
2005-06-27 12:59:41 +00:00
|
|
|
return -ENOMEM;
|
2009-01-23 10:57:22 +00:00
|
|
|
knew->index = idx;
|
2005-06-27 12:59:41 +00:00
|
|
|
knew->private_value = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-12 15:45:04 +00:00
|
|
|
static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
|
|
|
|
int type, int idx, const char *name,
|
|
|
|
unsigned long val)
|
|
|
|
{
|
|
|
|
return stac92xx_add_control_temp(spec,
|
|
|
|
&stac92xx_control_templates[type],
|
|
|
|
idx, name, val);
|
|
|
|
}
|
|
|
|
|
2008-08-15 05:43:24 +00:00
|
|
|
|
|
|
|
/* add dynamic controls */
|
2008-11-12 15:45:04 +00:00
|
|
|
static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
|
|
|
|
const char *name, unsigned long val)
|
2008-08-15 05:43:24 +00:00
|
|
|
{
|
|
|
|
return stac92xx_add_control_idx(spec, type, 0, name, val);
|
|
|
|
}
|
|
|
|
|
2009-01-23 10:57:22 +00:00
|
|
|
static struct snd_kcontrol_new stac_input_src_temp = {
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
.name = "Input Source",
|
|
|
|
.info = stac92xx_mux_enum_info,
|
|
|
|
.get = stac92xx_mux_enum_get,
|
|
|
|
.put = stac92xx_mux_enum_put,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int stac92xx_add_input_source(struct sigmatel_spec *spec)
|
|
|
|
{
|
|
|
|
struct snd_kcontrol_new *knew;
|
|
|
|
struct hda_input_mux *imux = &spec->private_imux;
|
|
|
|
|
|
|
|
if (!spec->num_adcs || imux->num_items <= 1)
|
|
|
|
return 0; /* no need for input source control */
|
|
|
|
knew = stac_control_new(spec, &stac_input_src_temp,
|
|
|
|
stac_input_src_temp.name);
|
|
|
|
if (!knew)
|
|
|
|
return -ENOMEM;
|
|
|
|
knew->count = spec->num_adcs;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
/* check whether the line-input can be used as line-out */
|
|
|
|
static hda_nid_t check_line_out_switch(struct hda_codec *codec)
|
2005-11-29 14:00:51 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-12-19 08:26:08 +00:00
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
hda_nid_t nid;
|
|
|
|
unsigned int pincap;
|
2007-12-17 10:58:13 +00:00
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
|
|
|
|
return 0;
|
|
|
|
nid = cfg->input_pins[AUTO_PIN_LINE];
|
2009-03-23 12:07:47 +00:00
|
|
|
pincap = snd_hda_query_pin_caps(codec, nid);
|
2008-12-19 08:26:08 +00:00
|
|
|
if (pincap & AC_PINCAP_OUT)
|
|
|
|
return nid;
|
|
|
|
return 0;
|
|
|
|
}
|
2005-11-29 14:00:51 +00:00
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
/* check whether the mic-input can be used as line-out */
|
|
|
|
static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
unsigned int def_conf, pincap;
|
|
|
|
unsigned int mic_pin;
|
|
|
|
|
|
|
|
if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
|
|
|
|
return 0;
|
|
|
|
mic_pin = AUTO_PIN_MIC;
|
|
|
|
for (;;) {
|
|
|
|
hda_nid_t nid = cfg->input_pins[mic_pin];
|
2009-02-20 13:33:36 +00:00
|
|
|
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
2008-12-19 08:26:08 +00:00
|
|
|
/* some laptops have an internal analog microphone
|
|
|
|
* which can't be used as a output */
|
|
|
|
if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
|
2009-03-23 12:07:47 +00:00
|
|
|
pincap = snd_hda_query_pin_caps(codec, nid);
|
2008-12-19 08:26:08 +00:00
|
|
|
if (pincap & AC_PINCAP_OUT)
|
|
|
|
return nid;
|
2005-11-29 14:00:51 +00:00
|
|
|
}
|
2008-12-19 08:26:08 +00:00
|
|
|
if (mic_pin == AUTO_PIN_MIC)
|
|
|
|
mic_pin = AUTO_PIN_FRONT_MIC;
|
|
|
|
else
|
|
|
|
break;
|
2005-11-29 14:00:51 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->multiout.num_dacs; i++) {
|
|
|
|
if (spec->multiout.dac_nids[i] == nid)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (is_in_dac_nids(spec, nid))
|
|
|
|
return 1;
|
|
|
|
for (i = 0; i < spec->autocfg.hp_outs; i++)
|
|
|
|
if (spec->hp_dacs[i] == nid)
|
|
|
|
return 1;
|
|
|
|
for (i = 0; i < spec->autocfg.speaker_outs; i++)
|
|
|
|
if (spec->speaker_dacs[i] == nid)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int j, conn_len;
|
|
|
|
hda_nid_t conn[HDA_MAX_CONNECTIONS];
|
|
|
|
unsigned int wcaps, wtype;
|
|
|
|
|
|
|
|
conn_len = snd_hda_get_connections(codec, nid, conn,
|
|
|
|
HDA_MAX_CONNECTIONS);
|
|
|
|
for (j = 0; j < conn_len; j++) {
|
2009-03-23 15:35:39 +00:00
|
|
|
wcaps = get_wcaps(codec, conn[j]);
|
2008-12-19 08:26:08 +00:00
|
|
|
wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
|
|
|
|
/* we check only analog outputs */
|
|
|
|
if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
|
|
|
|
continue;
|
|
|
|
/* if this route has a free DAC, assign it */
|
|
|
|
if (!check_all_dac_nids(spec, conn[j])) {
|
|
|
|
if (conn_len > 1) {
|
|
|
|
/* select this DAC in the pin's input mux */
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL, j);
|
|
|
|
}
|
|
|
|
return conn[j];
|
|
|
|
}
|
|
|
|
}
|
2009-03-06 11:00:24 +00:00
|
|
|
/* if all DACs are already assigned, connect to the primary DAC */
|
|
|
|
if (conn_len > 1) {
|
|
|
|
for (j = 0; j < conn_len; j++) {
|
|
|
|
if (conn[j] == spec->multiout.dac_nids[0]) {
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL, j);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-19 08:26:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
|
|
|
|
static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
/*
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
* Fill in the dac_nids table from the parsed pin configuration
|
|
|
|
* This function only works when every pin in line_out_pins[]
|
|
|
|
* contains atleast one DAC in its connection list. Some 92xx
|
|
|
|
* codecs are not connected directly to a DAC, such as the 9200
|
|
|
|
* and 9202/925x. For those, dac_nids[] must be hard-coded.
|
2006-01-23 14:27:49 +00:00
|
|
|
*/
|
2008-12-19 08:26:08 +00:00
|
|
|
static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
|
2005-06-27 12:59:41 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-12-19 08:26:08 +00:00
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
int i;
|
|
|
|
hda_nid_t nid, dac;
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
for (i = 0; i < cfg->line_outs; i++) {
|
|
|
|
nid = cfg->line_out_pins[i];
|
2008-12-19 08:26:08 +00:00
|
|
|
dac = get_unassigned_dac(codec, nid);
|
|
|
|
if (!dac) {
|
2007-07-02 17:18:00 +00:00
|
|
|
if (spec->multiout.num_dacs > 0) {
|
|
|
|
/* we have already working output pins,
|
|
|
|
* so let's drop the broken ones again
|
|
|
|
*/
|
|
|
|
cfg->line_outs = spec->multiout.num_dacs;
|
|
|
|
break;
|
|
|
|
}
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
/* error out, no available DAC found */
|
|
|
|
snd_printk(KERN_ERR
|
|
|
|
"%s: No available DAC for pin 0x%x\n",
|
|
|
|
__func__, nid);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2008-12-19 08:26:08 +00:00
|
|
|
add_spec_dacs(spec, dac);
|
|
|
|
}
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
|
2009-03-06 11:10:41 +00:00
|
|
|
for (i = 0; i < cfg->hp_outs; i++) {
|
|
|
|
nid = cfg->hp_pins[i];
|
|
|
|
dac = get_unassigned_dac(codec, nid);
|
|
|
|
if (dac) {
|
|
|
|
if (!spec->multiout.hp_nid)
|
|
|
|
spec->multiout.hp_nid = dac;
|
|
|
|
else
|
|
|
|
add_spec_extra_dacs(spec, dac);
|
|
|
|
}
|
|
|
|
spec->hp_dacs[i] = dac;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < cfg->speaker_outs; i++) {
|
|
|
|
nid = cfg->speaker_pins[i];
|
|
|
|
dac = get_unassigned_dac(codec, nid);
|
|
|
|
if (dac)
|
|
|
|
add_spec_extra_dacs(spec, dac);
|
|
|
|
spec->speaker_dacs[i] = dac;
|
|
|
|
}
|
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
/* add line-in as output */
|
|
|
|
nid = check_line_out_switch(codec);
|
|
|
|
if (nid) {
|
|
|
|
dac = get_unassigned_dac(codec, nid);
|
|
|
|
if (dac) {
|
|
|
|
snd_printdd("STAC: Add line-in 0x%x as output %d\n",
|
|
|
|
nid, cfg->line_outs);
|
|
|
|
cfg->line_out_pins[cfg->line_outs] = nid;
|
|
|
|
cfg->line_outs++;
|
|
|
|
spec->line_switch = nid;
|
|
|
|
add_spec_dacs(spec, dac);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* add mic as output */
|
|
|
|
nid = check_mic_out_switch(codec);
|
|
|
|
if (nid) {
|
|
|
|
dac = get_unassigned_dac(codec, nid);
|
|
|
|
if (dac) {
|
|
|
|
snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
|
|
|
|
nid, cfg->line_outs);
|
|
|
|
cfg->line_out_pins[cfg->line_outs] = nid;
|
|
|
|
cfg->line_outs++;
|
|
|
|
spec->mic_switch = nid;
|
|
|
|
add_spec_dacs(spec, dac);
|
|
|
|
}
|
|
|
|
}
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
spec->multiout.num_dacs,
|
|
|
|
spec->multiout.dac_nids[0],
|
|
|
|
spec->multiout.dac_nids[1],
|
|
|
|
spec->multiout.dac_nids[2],
|
|
|
|
spec->multiout.dac_nids[3],
|
|
|
|
spec->multiout.dac_nids[4]);
|
2008-12-19 08:26:08 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-20 15:10:27 +00:00
|
|
|
/* create volume control/switch for the given prefx type */
|
2009-03-06 09:13:24 +00:00
|
|
|
static int create_controls_idx(struct hda_codec *codec, const char *pfx,
|
|
|
|
int idx, hda_nid_t nid, int chs)
|
2006-09-20 15:10:27 +00:00
|
|
|
{
|
2009-01-20 14:28:38 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2006-09-20 15:10:27 +00:00
|
|
|
char name[32];
|
|
|
|
int err;
|
|
|
|
|
2009-01-20 14:28:38 +00:00
|
|
|
if (!spec->check_volume_offset) {
|
|
|
|
unsigned int caps, step, nums, db_scale;
|
|
|
|
caps = query_amp_caps(codec, nid, HDA_OUTPUT);
|
|
|
|
step = (caps & AC_AMPCAP_STEP_SIZE) >>
|
|
|
|
AC_AMPCAP_STEP_SIZE_SHIFT;
|
|
|
|
step = (step + 1) * 25; /* in .01dB unit */
|
|
|
|
nums = (caps & AC_AMPCAP_NUM_STEPS) >>
|
|
|
|
AC_AMPCAP_NUM_STEPS_SHIFT;
|
|
|
|
db_scale = nums * step;
|
|
|
|
/* if dB scale is over -64dB, and finer enough,
|
|
|
|
* let's reduce it to half
|
|
|
|
*/
|
|
|
|
if (db_scale > 6400 && nums >= 0x1f)
|
|
|
|
spec->volume_offset = nums / 2;
|
|
|
|
spec->check_volume_offset = 1;
|
|
|
|
}
|
|
|
|
|
2006-09-20 15:10:27 +00:00
|
|
|
sprintf(name, "%s Playback Volume", pfx);
|
2009-03-06 09:13:24 +00:00
|
|
|
err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name,
|
2009-01-20 14:28:38 +00:00
|
|
|
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
|
|
|
|
spec->volume_offset));
|
2006-09-20 15:10:27 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
sprintf(name, "%s Playback Switch", pfx);
|
2009-03-06 09:13:24 +00:00
|
|
|
err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name,
|
2006-09-20 15:10:27 +00:00
|
|
|
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-06 09:13:24 +00:00
|
|
|
#define create_controls(codec, pfx, nid, chs) \
|
|
|
|
create_controls_idx(codec, pfx, 0, nid, chs)
|
|
|
|
|
2008-02-22 16:55:05 +00:00
|
|
|
static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
|
|
|
|
{
|
2008-12-19 08:26:08 +00:00
|
|
|
if (spec->multiout.num_dacs > 4) {
|
2008-02-22 16:55:05 +00:00
|
|
|
printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
|
|
|
|
spec->multiout.num_dacs++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
|
2008-02-22 16:55:05 +00:00
|
|
|
{
|
2008-12-19 08:26:08 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
|
|
|
|
if (!spec->multiout.extra_out_nid[i]) {
|
|
|
|
spec->multiout.extra_out_nid[i] = nid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
|
|
|
|
return 1;
|
2008-02-22 16:55:05 +00:00
|
|
|
}
|
|
|
|
|
2009-03-06 09:00:05 +00:00
|
|
|
/* Create output controls
|
|
|
|
* The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT)
|
|
|
|
*/
|
|
|
|
static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
|
|
|
|
const hda_nid_t *pins,
|
|
|
|
const hda_nid_t *dac_nids,
|
|
|
|
int type)
|
2005-06-27 12:59:41 +00:00
|
|
|
{
|
2008-12-19 09:09:47 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2006-06-28 13:52:16 +00:00
|
|
|
static const char *chname[4] = {
|
|
|
|
"Front", "Surround", NULL /*CLFE*/, "Side"
|
|
|
|
};
|
2009-03-06 09:00:05 +00:00
|
|
|
hda_nid_t nid;
|
2008-12-19 14:59:40 +00:00
|
|
|
int i, err;
|
|
|
|
unsigned int wid_caps;
|
2007-09-03 13:29:04 +00:00
|
|
|
|
2009-03-06 09:00:05 +00:00
|
|
|
for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
|
2009-04-16 10:20:24 +00:00
|
|
|
if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
|
|
|
|
wid_caps = get_wcaps(codec, pins[i]);
|
|
|
|
if (wid_caps & AC_WCAP_UNSOL_CAP)
|
|
|
|
spec->hp_detect = 1;
|
|
|
|
}
|
2009-03-06 09:00:05 +00:00
|
|
|
nid = dac_nids[i];
|
|
|
|
if (!nid)
|
|
|
|
continue;
|
|
|
|
if (type != AUTO_PIN_HP_OUT && i == 2) {
|
2005-06-27 12:59:41 +00:00
|
|
|
/* Center/LFE */
|
2009-01-20 14:28:38 +00:00
|
|
|
err = create_controls(codec, "Center", nid, 1);
|
2006-09-20 15:10:27 +00:00
|
|
|
if (err < 0)
|
2005-06-27 12:59:41 +00:00
|
|
|
return err;
|
2009-01-20 14:28:38 +00:00
|
|
|
err = create_controls(codec, "LFE", nid, 2);
|
2006-09-20 15:10:27 +00:00
|
|
|
if (err < 0)
|
2005-06-27 12:59:41 +00:00
|
|
|
return err;
|
2007-09-03 13:29:04 +00:00
|
|
|
|
|
|
|
wid_caps = get_wcaps(codec, nid);
|
|
|
|
|
|
|
|
if (wid_caps & AC_WCAP_LR_SWAP) {
|
|
|
|
err = stac92xx_add_control(spec,
|
|
|
|
STAC_CTL_WIDGET_CLFE_SWITCH,
|
|
|
|
"Swap Center/LFE Playback Switch", nid);
|
|
|
|
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
} else {
|
2009-03-06 09:00:05 +00:00
|
|
|
const char *name;
|
2009-03-06 09:13:24 +00:00
|
|
|
int idx;
|
2009-03-06 09:00:05 +00:00
|
|
|
switch (type) {
|
|
|
|
case AUTO_PIN_HP_OUT:
|
2009-03-06 09:13:24 +00:00
|
|
|
name = "Headphone";
|
|
|
|
idx = i;
|
2009-03-06 09:00:05 +00:00
|
|
|
break;
|
|
|
|
case AUTO_PIN_SPEAKER_OUT:
|
2009-03-06 09:13:24 +00:00
|
|
|
name = "Speaker";
|
|
|
|
idx = i;
|
2009-03-06 09:00:05 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
name = chname[i];
|
2009-03-06 09:13:24 +00:00
|
|
|
idx = 0;
|
2009-03-06 09:00:05 +00:00
|
|
|
break;
|
2008-12-19 09:09:47 +00:00
|
|
|
}
|
2009-03-06 09:13:24 +00:00
|
|
|
err = create_controls_idx(codec, name, idx, nid, 3);
|
2006-09-20 15:10:27 +00:00
|
|
|
if (err < 0)
|
2005-06-27 12:59:41 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
2009-03-06 09:00:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add playback controls from the parsed DAC table */
|
|
|
|
static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
|
|
|
|
const struct auto_pin_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
|
|
|
|
spec->multiout.dac_nids,
|
|
|
|
cfg->line_out_type);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-11-24 06:51:11 +00:00
|
|
|
if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
|
2008-04-16 11:13:59 +00:00
|
|
|
err = stac92xx_add_control(spec,
|
|
|
|
STAC_CTL_WIDGET_HP_SWITCH,
|
2008-11-12 08:48:04 +00:00
|
|
|
"Headphone as Line Out Switch",
|
|
|
|
cfg->hp_pins[cfg->hp_outs - 1]);
|
2008-04-16 11:13:59 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-01-25 14:24:50 +00:00
|
|
|
if (spec->line_switch) {
|
2008-12-19 08:26:08 +00:00
|
|
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
|
|
|
|
"Line In as Output Switch",
|
|
|
|
spec->line_switch << 8);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-01-25 14:24:50 +00:00
|
|
|
}
|
2005-11-29 14:00:51 +00:00
|
|
|
|
2008-01-25 14:24:50 +00:00
|
|
|
if (spec->mic_switch) {
|
2009-05-15 13:33:30 +00:00
|
|
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_DC_BIAS,
|
|
|
|
"Mic Jack Mode",
|
|
|
|
spec->mic_switch);
|
2008-12-19 08:26:08 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-01-25 14:24:50 +00:00
|
|
|
}
|
2005-11-29 14:00:51 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-20 15:10:27 +00:00
|
|
|
/* add playback controls for Speaker and HP outputs */
|
|
|
|
static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
|
|
|
|
struct auto_pin_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2009-03-06 09:00:05 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins,
|
|
|
|
spec->hp_dacs, AUTO_PIN_HP_OUT);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins,
|
|
|
|
spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2006-09-20 15:10:27 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-22 11:32:30 +00:00
|
|
|
/* labels for mono mux outputs */
|
2008-07-27 08:30:30 +00:00
|
|
|
static const char *stac92xx_mono_labels[4] = {
|
|
|
|
"DAC0", "DAC1", "Mixer", "DAC2"
|
2008-01-22 11:32:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* create mono mux for mono out on capable codecs */
|
|
|
|
static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct hda_input_mux *mono_mux = &spec->private_mono_mux;
|
|
|
|
int i, num_cons;
|
|
|
|
hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
|
|
|
|
|
|
|
|
num_cons = snd_hda_get_connections(codec,
|
|
|
|
spec->mono_nid,
|
|
|
|
con_lst,
|
|
|
|
HDA_MAX_NUM_INPUTS);
|
|
|
|
if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (i = 0; i < num_cons; i++) {
|
|
|
|
mono_mux->items[mono_mux->num_items].label =
|
|
|
|
stac92xx_mono_labels[i];
|
|
|
|
mono_mux->items[mono_mux->num_items].index = i;
|
|
|
|
mono_mux->num_items++;
|
|
|
|
}
|
2008-01-24 10:49:21 +00:00
|
|
|
|
|
|
|
return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
|
|
|
|
"Mono Mux", spec->mono_nid);
|
2008-01-22 11:32:30 +00:00
|
|
|
}
|
|
|
|
|
2008-09-11 13:49:39 +00:00
|
|
|
/* labels for amp mux outputs */
|
|
|
|
static const char *stac92xx_amp_labels[3] = {
|
2008-10-10 13:07:23 +00:00
|
|
|
"Front Microphone", "Microphone", "Line In",
|
2008-09-11 13:49:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* create amp out controls mux on capable codecs */
|
|
|
|
static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct hda_input_mux *amp_mux = &spec->private_amp_mux;
|
|
|
|
int i, err;
|
|
|
|
|
2008-09-13 20:45:39 +00:00
|
|
|
for (i = 0; i < spec->num_amps; i++) {
|
2008-09-11 13:49:39 +00:00
|
|
|
amp_mux->items[amp_mux->num_items].label =
|
|
|
|
stac92xx_amp_labels[i];
|
|
|
|
amp_mux->items[amp_mux->num_items].index = i;
|
|
|
|
amp_mux->num_items++;
|
|
|
|
}
|
|
|
|
|
2008-09-13 20:45:39 +00:00
|
|
|
if (spec->num_amps > 1) {
|
|
|
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
|
|
|
|
"Amp Selector Capture Switch", 0);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-09-11 13:49:39 +00:00
|
|
|
return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
|
|
|
|
"Amp Capture Volume",
|
|
|
|
HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-18 16:20:52 +00:00
|
|
|
/* create PC beep volume controls */
|
|
|
|
static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
|
|
|
|
hda_nid_t nid)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* check for mute support for the the amp */
|
|
|
|
if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
|
|
|
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
|
|
|
|
"PC Beep Playback Switch",
|
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check to see if there is volume support for the amp */
|
|
|
|
if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
|
|
|
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
|
|
|
|
"PC Beep Playback Volume",
|
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-12 15:45:04 +00:00
|
|
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
|
|
|
#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
|
|
|
|
|
|
|
|
static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
ucontrol->value.integer.value[0] = codec->beep->enabled;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
|
{
|
|
|
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
|
int enabled = !!ucontrol->value.integer.value[0];
|
|
|
|
if (codec->beep->enabled != enabled) {
|
|
|
|
codec->beep->enabled = enabled;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
|
|
|
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
.info = stac92xx_dig_beep_switch_info,
|
|
|
|
.get = stac92xx_dig_beep_switch_get,
|
|
|
|
.put = stac92xx_dig_beep_switch_put,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
|
|
|
|
0, "PC Beep Playback Switch", 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-08-15 05:43:24 +00:00
|
|
|
static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int wcaps, nid, i, err = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->num_muxes; i++) {
|
|
|
|
nid = spec->mux_nids[i];
|
|
|
|
wcaps = get_wcaps(codec, nid);
|
|
|
|
|
|
|
|
if (wcaps & AC_WCAP_OUT_AMP) {
|
|
|
|
err = stac92xx_add_control_idx(spec,
|
|
|
|
STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
|
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
static const char *stac92xx_spdif_labels[3] = {
|
2008-09-16 14:39:37 +00:00
|
|
|
"Digital Playback", "Analog Mux 1", "Analog Mux 2",
|
2008-09-07 10:03:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct hda_input_mux *spdif_mux = &spec->private_smux;
|
2008-09-16 14:39:37 +00:00
|
|
|
const char **labels = spec->spdif_labels;
|
2008-09-07 10:03:41 +00:00
|
|
|
int i, num_cons;
|
2008-09-16 14:39:37 +00:00
|
|
|
hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
|
2008-09-07 10:03:41 +00:00
|
|
|
|
|
|
|
num_cons = snd_hda_get_connections(codec,
|
|
|
|
spec->smux_nids[0],
|
|
|
|
con_lst,
|
|
|
|
HDA_MAX_NUM_INPUTS);
|
2008-09-16 14:39:37 +00:00
|
|
|
if (!num_cons)
|
2008-09-07 10:03:41 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2008-09-16 14:39:37 +00:00
|
|
|
if (!labels)
|
|
|
|
labels = stac92xx_spdif_labels;
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
for (i = 0; i < num_cons; i++) {
|
2008-09-16 14:39:37 +00:00
|
|
|
spdif_mux->items[spdif_mux->num_items].label = labels[i];
|
2008-09-07 10:03:41 +00:00
|
|
|
spdif_mux->items[spdif_mux->num_items].index = i;
|
|
|
|
spdif_mux->num_items++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-26 15:12:59 +00:00
|
|
|
/* labels for dmic mux inputs */
|
2006-11-20 11:03:44 +00:00
|
|
|
static const char *stac92xx_dmic_labels[5] = {
|
2006-10-26 15:12:59 +00:00
|
|
|
"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
|
|
|
|
"Digital Mic 3", "Digital Mic 4"
|
|
|
|
};
|
|
|
|
|
|
|
|
/* create playback/capture controls for input pins on dmic capable codecs */
|
|
|
|
static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
|
|
|
|
const struct auto_pin_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct hda_input_mux *dimux = &spec->private_dimux;
|
|
|
|
hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
|
2008-01-08 11:10:50 +00:00
|
|
|
int err, i, j;
|
|
|
|
char name[32];
|
2006-10-26 15:12:59 +00:00
|
|
|
|
|
|
|
dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
|
|
|
|
dimux->items[dimux->num_items].index = 0;
|
|
|
|
dimux->num_items++;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->num_dmics; i++) {
|
2008-01-08 11:10:50 +00:00
|
|
|
hda_nid_t nid;
|
2006-10-26 15:12:59 +00:00
|
|
|
int index;
|
|
|
|
int num_cons;
|
2008-01-08 11:10:50 +00:00
|
|
|
unsigned int wcaps;
|
2006-10-26 15:12:59 +00:00
|
|
|
unsigned int def_conf;
|
|
|
|
|
2009-02-20 13:33:36 +00:00
|
|
|
def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
|
2006-10-26 15:12:59 +00:00
|
|
|
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
|
|
|
|
continue;
|
|
|
|
|
2008-01-08 11:10:50 +00:00
|
|
|
nid = spec->dmic_nids[i];
|
2006-10-26 15:12:59 +00:00
|
|
|
num_cons = snd_hda_get_connections(codec,
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->dmux_nids[0],
|
2006-10-26 15:12:59 +00:00
|
|
|
con_lst,
|
|
|
|
HDA_MAX_NUM_INPUTS);
|
|
|
|
for (j = 0; j < num_cons; j++)
|
2008-01-08 11:10:50 +00:00
|
|
|
if (con_lst[j] == nid) {
|
2006-10-26 15:12:59 +00:00
|
|
|
index = j;
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
found:
|
2008-07-27 08:30:30 +00:00
|
|
|
wcaps = get_wcaps(codec, nid) &
|
|
|
|
(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
|
2008-01-08 11:10:50 +00:00
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
if (wcaps) {
|
2008-01-08 11:10:50 +00:00
|
|
|
sprintf(name, "%s Capture Volume",
|
|
|
|
stac92xx_dmic_labels[dimux->num_items]);
|
|
|
|
|
|
|
|
err = stac92xx_add_control(spec,
|
|
|
|
STAC_CTL_WIDGET_VOL,
|
|
|
|
name,
|
2008-07-27 08:30:30 +00:00
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
|
|
|
|
(wcaps & AC_WCAP_OUT_AMP) ?
|
|
|
|
HDA_OUTPUT : HDA_INPUT));
|
2008-01-08 11:10:50 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-10-26 15:12:59 +00:00
|
|
|
dimux->items[dimux->num_items].label =
|
|
|
|
stac92xx_dmic_labels[dimux->num_items];
|
|
|
|
dimux->items[dimux->num_items].index = index;
|
|
|
|
dimux->num_items++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
/* create playback/capture controls for input pins */
|
|
|
|
static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct hda_input_mux *imux = &spec->private_imux;
|
|
|
|
hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
|
|
|
|
int i, j, k;
|
|
|
|
|
|
|
|
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
2006-09-21 09:56:18 +00:00
|
|
|
int index;
|
|
|
|
|
|
|
|
if (!cfg->input_pins[i])
|
|
|
|
continue;
|
|
|
|
index = -1;
|
|
|
|
for (j = 0; j < spec->num_muxes; j++) {
|
|
|
|
int num_cons;
|
|
|
|
num_cons = snd_hda_get_connections(codec,
|
|
|
|
spec->mux_nids[j],
|
|
|
|
con_lst,
|
|
|
|
HDA_MAX_NUM_INPUTS);
|
|
|
|
for (k = 0; k < num_cons; k++)
|
|
|
|
if (con_lst[k] == cfg->input_pins[i]) {
|
|
|
|
index = k;
|
|
|
|
goto found;
|
|
|
|
}
|
2005-06-27 12:59:41 +00:00
|
|
|
}
|
2006-09-21 09:56:18 +00:00
|
|
|
continue;
|
|
|
|
found:
|
|
|
|
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
|
|
|
|
imux->items[imux->num_items].index = index;
|
|
|
|
imux->num_items++;
|
2005-06-27 12:59:41 +00:00
|
|
|
}
|
|
|
|
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
if (imux->num_items) {
|
2006-05-10 13:09:17 +00:00
|
|
|
/*
|
|
|
|
* Set the current input for the muxes.
|
|
|
|
* The STAC9221 has two input muxes with identical source
|
|
|
|
* NID lists. Hopefully this won't get confused.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < spec->num_muxes; i++) {
|
2007-08-10 15:09:26 +00:00
|
|
|
snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL,
|
|
|
|
imux->items[0].index);
|
2006-05-10 13:09:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->autocfg.line_outs; i++) {
|
|
|
|
hda_nid_t nid = spec->autocfg.line_out_pins[i];
|
|
|
|
stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2006-09-20 15:10:27 +00:00
|
|
|
int i;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2006-09-20 15:10:27 +00:00
|
|
|
for (i = 0; i < spec->autocfg.hp_outs; i++) {
|
|
|
|
hda_nid_t pin;
|
|
|
|
pin = spec->autocfg.hp_pins[i];
|
|
|
|
if (pin) /* connect to front */
|
|
|
|
stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
|
|
|
|
}
|
|
|
|
for (i = 0; i < spec->autocfg.speaker_outs; i++) {
|
|
|
|
hda_nid_t pin;
|
|
|
|
pin = spec->autocfg.speaker_pins[i];
|
|
|
|
if (pin) /* connect to front */
|
|
|
|
stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
|
|
|
|
}
|
2005-06-27 12:59:41 +00:00
|
|
|
}
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
|
2005-06-27 12:59:41 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2009-03-06 09:00:05 +00:00
|
|
|
int hp_swap = 0;
|
2005-06-27 12:59:41 +00:00
|
|
|
int err;
|
|
|
|
|
2006-10-26 15:12:59 +00:00
|
|
|
if ((err = snd_hda_parse_pin_def_config(codec,
|
|
|
|
&spec->autocfg,
|
|
|
|
spec->dmic_nids)) < 0)
|
2005-06-27 12:59:41 +00:00
|
|
|
return err;
|
2006-03-21 10:24:42 +00:00
|
|
|
if (! spec->autocfg.line_outs)
|
2006-01-25 18:20:50 +00:00
|
|
|
return 0; /* can't find valid pin config */
|
2006-06-28 13:52:16 +00:00
|
|
|
|
2007-11-12 11:57:03 +00:00
|
|
|
/* If we have no real line-out pin and multiple hp-outs, HPs should
|
|
|
|
* be set up as multi-channel outputs.
|
|
|
|
*/
|
|
|
|
if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
|
|
|
|
spec->autocfg.hp_outs > 1) {
|
|
|
|
/* Copy hp_outs to line_outs, backup line_outs in
|
|
|
|
* speaker_outs so that the following routines can handle
|
|
|
|
* HP pins as primary outputs.
|
|
|
|
*/
|
2008-12-19 08:26:08 +00:00
|
|
|
snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
|
2007-11-12 11:57:03 +00:00
|
|
|
memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
|
|
|
|
sizeof(spec->autocfg.line_out_pins));
|
|
|
|
spec->autocfg.speaker_outs = spec->autocfg.line_outs;
|
|
|
|
memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
|
|
|
|
sizeof(spec->autocfg.hp_pins));
|
|
|
|
spec->autocfg.line_outs = spec->autocfg.hp_outs;
|
2008-12-19 08:26:08 +00:00
|
|
|
spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
|
|
|
|
spec->autocfg.hp_outs = 0;
|
2009-03-06 09:00:05 +00:00
|
|
|
hp_swap = 1;
|
2007-11-12 11:57:03 +00:00
|
|
|
}
|
2008-01-24 10:49:21 +00:00
|
|
|
if (spec->autocfg.mono_out_pin) {
|
2008-07-27 08:30:30 +00:00
|
|
|
int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
|
|
|
|
(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
|
2008-01-24 10:49:21 +00:00
|
|
|
u32 caps = query_amp_caps(codec,
|
|
|
|
spec->autocfg.mono_out_pin, dir);
|
|
|
|
hda_nid_t conn_list[1];
|
|
|
|
|
|
|
|
/* get the mixer node and then the mono mux if it exists */
|
|
|
|
if (snd_hda_get_connections(codec,
|
|
|
|
spec->autocfg.mono_out_pin, conn_list, 1) &&
|
|
|
|
snd_hda_get_connections(codec, conn_list[0],
|
|
|
|
conn_list, 1)) {
|
|
|
|
|
|
|
|
int wcaps = get_wcaps(codec, conn_list[0]);
|
|
|
|
int wid_type = (wcaps & AC_WCAP_TYPE)
|
|
|
|
>> AC_WCAP_TYPE_SHIFT;
|
|
|
|
/* LR swap check, some stac925x have a mux that
|
|
|
|
* changes the DACs output path instead of the
|
|
|
|
* mono-mux path.
|
|
|
|
*/
|
|
|
|
if (wid_type == AC_WID_AUD_SEL &&
|
|
|
|
!(wcaps & AC_WCAP_LR_SWAP))
|
|
|
|
spec->mono_nid = conn_list[0];
|
|
|
|
}
|
2008-07-27 08:30:30 +00:00
|
|
|
if (dir) {
|
|
|
|
hda_nid_t nid = spec->autocfg.mono_out_pin;
|
|
|
|
|
|
|
|
/* most mono outs have a least a mute/unmute switch */
|
|
|
|
dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
|
|
|
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
|
|
|
|
"Mono Playback Switch",
|
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
|
2008-01-24 10:49:21 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-07-27 08:30:30 +00:00
|
|
|
/* check for volume support for the amp */
|
|
|
|
if ((caps & AC_AMPCAP_NUM_STEPS)
|
|
|
|
>> AC_AMPCAP_NUM_STEPS_SHIFT) {
|
|
|
|
err = stac92xx_add_control(spec,
|
|
|
|
STAC_CTL_WIDGET_VOL,
|
|
|
|
"Mono Playback Volume",
|
|
|
|
HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-01-24 10:49:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
|
|
|
|
AC_PINCTL_OUT_EN);
|
|
|
|
}
|
2007-11-12 11:57:03 +00:00
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
if (!spec->multiout.num_dacs) {
|
|
|
|
err = stac92xx_auto_fill_dac_nids(codec);
|
|
|
|
if (err < 0)
|
2006-06-28 13:52:16 +00:00
|
|
|
return err;
|
2009-01-15 16:31:00 +00:00
|
|
|
err = stac92xx_auto_create_multi_out_ctls(codec,
|
|
|
|
&spec->autocfg);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-12-19 08:26:08 +00:00
|
|
|
}
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-07-18 16:20:52 +00:00
|
|
|
/* setup analog beep controls */
|
|
|
|
if (spec->anabeep_nid > 0) {
|
|
|
|
err = stac92xx_auto_create_beep_ctls(codec,
|
|
|
|
spec->anabeep_nid);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* setup digital beep controls and input device */
|
|
|
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
|
|
|
if (spec->digbeep_nid > 0) {
|
|
|
|
hda_nid_t nid = spec->digbeep_nid;
|
2008-11-12 15:45:04 +00:00
|
|
|
unsigned int caps;
|
2008-07-18 16:20:52 +00:00
|
|
|
|
|
|
|
err = stac92xx_auto_create_beep_ctls(codec, nid);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
err = snd_hda_attach_beep_device(codec, nid);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-11-12 15:45:04 +00:00
|
|
|
/* if no beep switch is available, make its own one */
|
|
|
|
caps = query_amp_caps(codec, nid, HDA_OUTPUT);
|
|
|
|
if (codec->beep &&
|
|
|
|
!((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
|
|
|
|
err = stac92xx_beep_switch_ctl(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-07-18 16:20:52 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-03 13:29:04 +00:00
|
|
|
err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2009-03-06 09:00:05 +00:00
|
|
|
/* All output parsing done, now restore the swapped hp pins */
|
|
|
|
if (hp_swap) {
|
|
|
|
memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
|
|
|
|
sizeof(spec->autocfg.hp_pins));
|
|
|
|
spec->autocfg.hp_outs = spec->autocfg.line_outs;
|
|
|
|
spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
|
|
|
|
spec->autocfg.line_outs = 0;
|
|
|
|
}
|
2007-09-03 13:29:04 +00:00
|
|
|
|
2009-03-06 09:00:05 +00:00
|
|
|
err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
|
2007-09-03 13:29:04 +00:00
|
|
|
if (err < 0)
|
2005-06-27 12:59:41 +00:00
|
|
|
return err;
|
|
|
|
|
2008-01-22 11:32:30 +00:00
|
|
|
if (spec->mono_nid > 0) {
|
|
|
|
err = stac92xx_auto_create_mono_output_ctls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-09-13 20:45:39 +00:00
|
|
|
if (spec->num_amps > 0) {
|
2008-09-11 13:49:39 +00:00
|
|
|
err = stac92xx_auto_create_amp_output_ctls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-09-13 20:45:39 +00:00
|
|
|
if (spec->num_dmics > 0 && !spec->dinput_mux)
|
2006-10-26 15:12:59 +00:00
|
|
|
if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
|
|
|
|
&spec->autocfg)) < 0)
|
|
|
|
return err;
|
2008-08-15 05:43:24 +00:00
|
|
|
if (spec->num_muxes > 0) {
|
|
|
|
err = stac92xx_auto_create_mux_input_ctls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2008-09-07 10:03:41 +00:00
|
|
|
if (spec->num_smuxes > 0) {
|
|
|
|
err = stac92xx_auto_create_spdif_mux_ctls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
2006-10-26 15:12:59 +00:00
|
|
|
|
2009-01-23 10:57:22 +00:00
|
|
|
err = stac92xx_add_input_source(spec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
|
2005-11-29 14:00:51 +00:00
|
|
|
if (spec->multiout.max_channels > 2)
|
2005-06-27 12:59:41 +00:00
|
|
|
spec->surr_switch = 1;
|
|
|
|
|
2009-02-11 10:35:15 +00:00
|
|
|
if (spec->autocfg.dig_outs)
|
2006-01-23 14:27:49 +00:00
|
|
|
spec->multiout.dig_out_nid = dig_out;
|
2008-07-27 08:30:30 +00:00
|
|
|
if (dig_in && spec->autocfg.dig_in_pin)
|
2006-01-23 14:27:49 +00:00
|
|
|
spec->dig_in_nid = dig_in;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-07-30 13:01:44 +00:00
|
|
|
if (spec->kctls.list)
|
|
|
|
spec->mixers[spec->num_mixers++] = spec->kctls.list;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
spec->input_mux = &spec->private_imux;
|
2008-12-20 22:36:28 +00:00
|
|
|
if (!spec->dinput_mux)
|
|
|
|
spec->dinput_mux = &spec->private_dimux;
|
2008-09-07 10:03:41 +00:00
|
|
|
spec->sinput_mux = &spec->private_smux;
|
2008-01-22 11:32:30 +00:00
|
|
|
spec->mono_mux = &spec->private_mono_mux;
|
2008-09-11 13:49:39 +00:00
|
|
|
spec->amp_mux = &spec->private_amp_mux;
|
2005-06-27 12:59:41 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-03-21 10:24:42 +00:00
|
|
|
/* add playback controls for HP output */
|
|
|
|
static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
|
|
|
|
struct auto_pin_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2006-09-20 15:10:27 +00:00
|
|
|
hda_nid_t pin = cfg->hp_pins[0];
|
2006-03-21 10:24:42 +00:00
|
|
|
unsigned int wid_caps;
|
|
|
|
|
|
|
|
if (! pin)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
wid_caps = get_wcaps(codec, pin);
|
2006-03-27 10:51:52 +00:00
|
|
|
if (wid_caps & AC_WCAP_UNSOL_CAP)
|
2006-03-21 10:24:42 +00:00
|
|
|
spec->hp_detect = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-06 11:58:25 +00:00
|
|
|
/* add playback controls for LFE output */
|
|
|
|
static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
|
|
|
|
struct auto_pin_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int err;
|
|
|
|
hda_nid_t lfe_pin = 0x0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* search speaker outs and line outs for a mono speaker pin
|
|
|
|
* with an amp. If one is found, add LFE controls
|
|
|
|
* for it.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
|
|
|
|
hda_nid_t pin = spec->autocfg.speaker_pins[i];
|
2008-02-29 10:57:53 +00:00
|
|
|
unsigned int wcaps = get_wcaps(codec, pin);
|
2006-09-06 11:58:25 +00:00
|
|
|
wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
|
|
|
|
if (wcaps == AC_WCAP_OUT_AMP)
|
|
|
|
/* found a mono speaker with an amp, must be lfe */
|
|
|
|
lfe_pin = pin;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if speaker_outs is 0, then speakers may be in line_outs */
|
|
|
|
if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
|
|
|
|
for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
|
|
|
|
hda_nid_t pin = spec->autocfg.line_out_pins[i];
|
2008-02-29 10:57:53 +00:00
|
|
|
unsigned int defcfg;
|
2009-02-20 13:33:36 +00:00
|
|
|
defcfg = snd_hda_codec_get_pincfg(codec, pin);
|
2008-02-29 10:56:48 +00:00
|
|
|
if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
|
2008-02-29 10:57:53 +00:00
|
|
|
unsigned int wcaps = get_wcaps(codec, pin);
|
2006-09-06 11:58:25 +00:00
|
|
|
wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
|
|
|
|
if (wcaps == AC_WCAP_OUT_AMP)
|
|
|
|
/* found a mono speaker with an amp,
|
|
|
|
must be lfe */
|
|
|
|
lfe_pin = pin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lfe_pin) {
|
2009-01-20 14:28:38 +00:00
|
|
|
err = create_controls(codec, "LFE", lfe_pin, 1);
|
2006-09-06 11:58:25 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
static int stac9200_parse_auto_config(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int err;
|
|
|
|
|
2005-12-05 18:42:22 +00:00
|
|
|
if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
|
2005-06-27 12:59:41 +00:00
|
|
|
return err;
|
|
|
|
|
|
|
|
if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
|
|
|
|
return err;
|
|
|
|
|
2006-03-21 10:24:42 +00:00
|
|
|
if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
|
|
|
|
return err;
|
|
|
|
|
2006-09-06 11:58:25 +00:00
|
|
|
if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
|
|
|
|
return err;
|
|
|
|
|
2008-11-11 15:46:19 +00:00
|
|
|
if (spec->num_muxes > 0) {
|
|
|
|
err = stac92xx_auto_create_mux_input_ctls(codec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-01-23 10:57:22 +00:00
|
|
|
err = stac92xx_add_input_source(spec);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2009-02-11 10:35:15 +00:00
|
|
|
if (spec->autocfg.dig_outs)
|
2005-06-27 12:59:41 +00:00
|
|
|
spec->multiout.dig_out_nid = 0x05;
|
2006-03-21 10:24:42 +00:00
|
|
|
if (spec->autocfg.dig_in_pin)
|
2005-06-27 12:59:41 +00:00
|
|
|
spec->dig_in_nid = 0x04;
|
|
|
|
|
2008-07-30 13:01:44 +00:00
|
|
|
if (spec->kctls.list)
|
|
|
|
spec->mixers[spec->num_mixers++] = spec->kctls.list;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
spec->input_mux = &spec->private_imux;
|
2006-10-26 15:12:59 +00:00
|
|
|
spec->dinput_mux = &spec->private_dimux;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-05-10 13:09:17 +00:00
|
|
|
/*
|
|
|
|
* Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
|
|
|
|
* funky external mute control using GPIO pins.
|
|
|
|
*/
|
|
|
|
|
2008-01-15 10:39:08 +00:00
|
|
|
static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
|
2008-01-29 14:28:44 +00:00
|
|
|
unsigned int dir_mask, unsigned int data)
|
2006-05-10 13:09:17 +00:00
|
|
|
{
|
|
|
|
unsigned int gpiostate, gpiomask, gpiodir;
|
|
|
|
|
|
|
|
gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_GET_GPIO_DATA, 0);
|
2008-01-29 14:28:44 +00:00
|
|
|
gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
|
2006-05-10 13:09:17 +00:00
|
|
|
|
|
|
|
gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_GET_GPIO_MASK, 0);
|
2008-01-15 10:39:08 +00:00
|
|
|
gpiomask |= mask;
|
2006-05-10 13:09:17 +00:00
|
|
|
|
|
|
|
gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_GET_GPIO_DIRECTION, 0);
|
2008-01-29 14:28:44 +00:00
|
|
|
gpiodir |= dir_mask;
|
2006-05-10 13:09:17 +00:00
|
|
|
|
2008-01-15 10:39:08 +00:00
|
|
|
/* Configure GPIOx as CMOS */
|
2006-05-10 13:09:17 +00:00
|
|
|
snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
|
|
|
|
|
|
|
|
snd_hda_codec_write(codec, codec->afg, 0,
|
|
|
|
AC_VERB_SET_GPIO_MASK, gpiomask);
|
2008-01-15 10:39:08 +00:00
|
|
|
snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
|
2006-05-10 13:09:17 +00:00
|
|
|
|
|
|
|
msleep(1);
|
|
|
|
|
2008-01-15 10:39:08 +00:00
|
|
|
snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
|
2006-05-10 13:09:17 +00:00
|
|
|
}
|
|
|
|
|
2009-04-14 14:15:29 +00:00
|
|
|
#ifdef CONFIG_SND_JACK
|
|
|
|
static void stac92xx_free_jack_priv(struct snd_jack *jack)
|
|
|
|
{
|
|
|
|
struct sigmatel_jack *jacks = jack->private_data;
|
|
|
|
jacks->nid = 0;
|
|
|
|
jacks->jack = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-10-25 05:06:04 +00:00
|
|
|
static int stac92xx_add_jack(struct hda_codec *codec,
|
|
|
|
hda_nid_t nid, int type)
|
|
|
|
{
|
2008-11-18 08:32:42 +00:00
|
|
|
#ifdef CONFIG_SND_JACK
|
2008-10-25 05:06:04 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct sigmatel_jack *jack;
|
2009-02-20 13:33:36 +00:00
|
|
|
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
2008-10-25 05:06:04 +00:00
|
|
|
int connectivity = get_defcfg_connect(def_conf);
|
|
|
|
char name[32];
|
2009-04-14 14:15:29 +00:00
|
|
|
int err;
|
2008-10-25 05:06:04 +00:00
|
|
|
|
|
|
|
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
snd_array_init(&spec->jacks, sizeof(*jack), 32);
|
|
|
|
jack = snd_array_new(&spec->jacks);
|
|
|
|
if (!jack)
|
|
|
|
return -ENOMEM;
|
|
|
|
jack->nid = nid;
|
|
|
|
jack->type = type;
|
|
|
|
|
|
|
|
sprintf(name, "%s at %s %s Jack",
|
|
|
|
snd_hda_get_jack_type(def_conf),
|
|
|
|
snd_hda_get_jack_connectivity(def_conf),
|
|
|
|
snd_hda_get_jack_location(def_conf));
|
|
|
|
|
2009-04-14 14:15:29 +00:00
|
|
|
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
|
|
|
|
if (err < 0) {
|
|
|
|
jack->nid = 0;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
jack->jack->private_data = jack;
|
|
|
|
jack->jack->private_free = stac92xx_free_jack_priv;
|
2008-11-18 08:32:42 +00:00
|
|
|
#endif
|
2009-04-14 14:15:29 +00:00
|
|
|
return 0;
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
|
|
|
|
unsigned char type, int data)
|
2008-10-25 05:06:04 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_event *event;
|
|
|
|
|
|
|
|
snd_array_init(&spec->events, sizeof(*event), 32);
|
|
|
|
event = snd_array_new(&spec->events);
|
|
|
|
if (!event)
|
|
|
|
return -ENOMEM;
|
|
|
|
event->nid = nid;
|
2008-11-25 10:58:19 +00:00
|
|
|
event->type = type;
|
|
|
|
event->tag = spec->events.used;
|
2008-10-25 05:06:04 +00:00
|
|
|
event->data = data;
|
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
return event->tag;
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
|
|
|
|
hda_nid_t nid, unsigned char type)
|
2008-10-25 05:06:04 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-11-25 10:58:19 +00:00
|
|
|
struct sigmatel_event *event = spec->events.list;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->events.used; i++, event++) {
|
|
|
|
if (event->nid == nid && event->type == type)
|
|
|
|
return event;
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
2008-11-25 10:58:19 +00:00
|
|
|
return NULL;
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
|
|
|
|
unsigned char tag)
|
2006-09-21 09:56:18 +00:00
|
|
|
{
|
2008-11-25 10:58:19 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct sigmatel_event *event = spec->events.list;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < spec->events.used; i++, event++) {
|
|
|
|
if (event->tag == tag)
|
|
|
|
return event;
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
2008-11-25 10:58:19 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
unsigned int type)
|
|
|
|
{
|
|
|
|
struct sigmatel_event *event;
|
|
|
|
int tag;
|
|
|
|
|
|
|
|
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
|
|
|
|
return;
|
|
|
|
event = stac_get_event(codec, nid, type);
|
|
|
|
if (event)
|
|
|
|
tag = event->tag;
|
|
|
|
else
|
|
|
|
tag = stac_add_event(codec->spec, nid, type, 0);
|
|
|
|
if (tag < 0)
|
|
|
|
return;
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_UNSOLICITED_ENABLE,
|
|
|
|
AC_USRSP_EN | tag);
|
2006-09-21 09:56:18 +00:00
|
|
|
}
|
|
|
|
|
2008-01-10 15:55:06 +00:00
|
|
|
static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < cfg->hp_outs; i++)
|
|
|
|
if (cfg->hp_pins[i] == nid)
|
|
|
|
return 1; /* nid is a HP-Out */
|
|
|
|
|
|
|
|
return 0; /* nid is not a HP-Out */
|
|
|
|
};
|
|
|
|
|
2008-02-06 13:49:44 +00:00
|
|
|
static void stac92xx_power_down(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
/* power down inactive DACs */
|
|
|
|
hda_nid_t *dac;
|
|
|
|
for (dac = spec->dac_list; *dac; dac++)
|
2008-12-19 08:26:08 +00:00
|
|
|
if (!check_all_dac_nids(spec, *dac))
|
2008-12-01 10:54:35 +00:00
|
|
|
snd_hda_codec_write(codec, *dac, 0,
|
2008-02-06 13:49:44 +00:00
|
|
|
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
|
|
|
}
|
|
|
|
|
2008-11-25 07:21:51 +00:00
|
|
|
static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
int enable);
|
|
|
|
|
2009-03-02 13:38:35 +00:00
|
|
|
/* override some hints from the hwdep entry */
|
|
|
|
static void stac_store_hints(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
const char *p;
|
|
|
|
int val;
|
|
|
|
|
|
|
|
val = snd_hda_get_bool_hint(codec, "hp_detect");
|
|
|
|
if (val >= 0)
|
|
|
|
spec->hp_detect = val;
|
|
|
|
p = snd_hda_get_hint(codec, "gpio_mask");
|
|
|
|
if (p) {
|
|
|
|
spec->gpio_mask = simple_strtoul(p, NULL, 0);
|
|
|
|
spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
|
|
|
|
spec->gpio_mask;
|
|
|
|
}
|
|
|
|
p = snd_hda_get_hint(codec, "gpio_dir");
|
|
|
|
if (p)
|
|
|
|
spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
|
|
|
|
p = snd_hda_get_hint(codec, "gpio_data");
|
|
|
|
if (p)
|
|
|
|
spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
|
|
|
|
p = snd_hda_get_hint(codec, "eapd_mask");
|
|
|
|
if (p)
|
|
|
|
spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
|
|
|
|
val = snd_hda_get_bool_hint(codec, "eapd_switch");
|
|
|
|
if (val >= 0)
|
|
|
|
spec->eapd_switch = val;
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
static int stac92xx_init(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2006-03-21 10:24:42 +00:00
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
2008-11-25 07:21:51 +00:00
|
|
|
unsigned int gpio;
|
2008-11-18 08:32:42 +00:00
|
|
|
int i;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
snd_hda_sequence_write(codec, spec->init);
|
|
|
|
|
2008-08-15 05:45:52 +00:00
|
|
|
/* power down adcs initially */
|
|
|
|
if (spec->powerdown_adcs)
|
|
|
|
for (i = 0; i < spec->num_adcs; i++)
|
2008-12-01 10:54:35 +00:00
|
|
|
snd_hda_codec_write(codec,
|
2008-08-15 05:45:52 +00:00
|
|
|
spec->adc_nids[i], 0,
|
|
|
|
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
|
2008-11-25 07:21:51 +00:00
|
|
|
|
2009-03-02 13:38:35 +00:00
|
|
|
/* override some hints */
|
|
|
|
stac_store_hints(codec);
|
|
|
|
|
2008-11-25 07:21:51 +00:00
|
|
|
/* set up GPIO */
|
|
|
|
gpio = spec->gpio_data;
|
|
|
|
/* turn on EAPD statically when spec->eapd_switch isn't set.
|
|
|
|
* otherwise, unsol event will turn it on/off dynamically
|
|
|
|
*/
|
|
|
|
if (!spec->eapd_switch)
|
|
|
|
gpio |= spec->eapd_mask;
|
|
|
|
stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
|
|
|
|
|
2006-03-21 10:24:42 +00:00
|
|
|
/* set up pins */
|
|
|
|
if (spec->hp_detect) {
|
2006-03-27 10:51:52 +00:00
|
|
|
/* Enable unsolicited responses on the HP widget */
|
2008-10-25 05:06:04 +00:00
|
|
|
for (i = 0; i < cfg->hp_outs; i++) {
|
|
|
|
hda_nid_t nid = cfg->hp_pins[i];
|
2008-11-25 10:58:19 +00:00
|
|
|
enable_pin_detect(codec, nid, STAC_HP_EVENT);
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
2007-03-13 09:40:23 +00:00
|
|
|
/* force to enable the first line-out; the others are set up
|
|
|
|
* in unsol_event
|
|
|
|
*/
|
|
|
|
stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
|
2008-10-25 05:06:04 +00:00
|
|
|
AC_PINCTL_OUT_EN);
|
2006-03-21 10:24:42 +00:00
|
|
|
/* fake event to set up pins */
|
2008-11-25 10:58:19 +00:00
|
|
|
stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
|
|
|
|
STAC_HP_EVENT);
|
2006-03-21 10:24:42 +00:00
|
|
|
} else {
|
|
|
|
stac92xx_auto_init_multi_out(codec);
|
|
|
|
stac92xx_auto_init_hp_out(codec);
|
2008-12-05 12:09:27 +00:00
|
|
|
for (i = 0; i < cfg->hp_outs; i++)
|
|
|
|
stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
|
2006-03-21 10:24:42 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < AUTO_PIN_LAST; i++) {
|
2006-03-23 16:06:28 +00:00
|
|
|
hda_nid_t nid = cfg->input_pins[i];
|
|
|
|
if (nid) {
|
2008-12-05 12:09:27 +00:00
|
|
|
unsigned int pinctl, conf;
|
2008-11-11 15:47:24 +00:00
|
|
|
if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
|
|
|
|
/* for mic pins, force to initialize */
|
|
|
|
pinctl = stac92xx_get_vref(codec, nid);
|
2008-12-05 12:09:27 +00:00
|
|
|
pinctl |= AC_PINCTL_IN_EN;
|
|
|
|
stac92xx_auto_set_pinctl(codec, nid, pinctl);
|
2008-11-11 15:47:24 +00:00
|
|
|
} else {
|
|
|
|
pinctl = snd_hda_codec_read(codec, nid, 0,
|
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
|
/* if PINCTL already set then skip */
|
2009-05-07 14:22:53 +00:00
|
|
|
/* Also, if both INPUT and OUTPUT are set,
|
|
|
|
* it must be a BIOS bug; need to override, too
|
|
|
|
*/
|
|
|
|
if (!(pinctl & AC_PINCTL_IN_EN) ||
|
|
|
|
(pinctl & AC_PINCTL_OUT_EN)) {
|
|
|
|
pinctl &= ~AC_PINCTL_OUT_EN;
|
2008-12-05 12:09:27 +00:00
|
|
|
pinctl |= AC_PINCTL_IN_EN;
|
|
|
|
stac92xx_auto_set_pinctl(codec, nid,
|
|
|
|
pinctl);
|
|
|
|
}
|
|
|
|
}
|
2009-02-20 13:33:36 +00:00
|
|
|
conf = snd_hda_codec_get_pincfg(codec, nid);
|
2008-12-05 12:09:27 +00:00
|
|
|
if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
|
|
|
|
enable_pin_detect(codec, nid,
|
|
|
|
STAC_INSERT_EVENT);
|
|
|
|
stac_issue_unsol_event(codec, nid,
|
|
|
|
STAC_INSERT_EVENT);
|
2008-11-11 15:47:24 +00:00
|
|
|
}
|
2006-03-23 16:06:28 +00:00
|
|
|
}
|
2006-03-21 10:24:42 +00:00
|
|
|
}
|
2008-01-10 15:55:06 +00:00
|
|
|
for (i = 0; i < spec->num_dmics; i++)
|
|
|
|
stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
|
|
|
|
AC_PINCTL_IN_EN);
|
2009-02-11 10:35:15 +00:00
|
|
|
if (cfg->dig_out_pins[0])
|
|
|
|
stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0],
|
2008-11-25 07:21:51 +00:00
|
|
|
AC_PINCTL_OUT_EN);
|
|
|
|
if (cfg->dig_in_pin)
|
|
|
|
stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
|
|
|
|
AC_PINCTL_IN_EN);
|
2008-01-10 15:55:06 +00:00
|
|
|
for (i = 0; i < spec->num_pwrs; i++) {
|
2008-11-25 07:21:51 +00:00
|
|
|
hda_nid_t nid = spec->pwr_nids[i];
|
|
|
|
int pinctl, def_conf;
|
|
|
|
|
2008-12-19 15:39:48 +00:00
|
|
|
/* power on when no jack detection is available */
|
|
|
|
if (!spec->hp_detect) {
|
|
|
|
stac_toggle_power_map(codec, nid, 1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_nid_hp_pin(cfg, nid))
|
2008-11-25 07:21:51 +00:00
|
|
|
continue; /* already has an unsol event */
|
|
|
|
|
|
|
|
pinctl = snd_hda_codec_read(codec, nid, 0,
|
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
2008-01-10 15:55:06 +00:00
|
|
|
/* outputs are only ports capable of power management
|
|
|
|
* any attempts on powering down a input port cause the
|
|
|
|
* referenced VREF to act quirky.
|
|
|
|
*/
|
2008-12-19 15:39:48 +00:00
|
|
|
if (pinctl & AC_PINCTL_IN_EN) {
|
|
|
|
stac_toggle_power_map(codec, nid, 1);
|
2008-01-10 15:55:06 +00:00
|
|
|
continue;
|
2008-12-19 15:39:48 +00:00
|
|
|
}
|
2009-02-20 13:33:36 +00:00
|
|
|
def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
2008-11-25 07:21:51 +00:00
|
|
|
def_conf = get_defcfg_connect(def_conf);
|
2008-06-13 16:04:33 +00:00
|
|
|
/* skip any ports that don't have jacks since presence
|
|
|
|
* detection is useless */
|
2008-11-25 07:21:51 +00:00
|
|
|
if (def_conf != AC_JACK_PORT_COMPLEX) {
|
|
|
|
if (def_conf != AC_JACK_PORT_NONE)
|
|
|
|
stac_toggle_power_map(codec, nid, 1);
|
2008-02-29 11:07:43 +00:00
|
|
|
continue;
|
2008-11-25 07:21:51 +00:00
|
|
|
}
|
2008-12-05 12:09:27 +00:00
|
|
|
if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
|
|
|
|
enable_pin_detect(codec, nid, STAC_PWR_EVENT);
|
|
|
|
stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
|
|
|
|
}
|
2008-01-10 15:55:06 +00:00
|
|
|
}
|
2008-02-06 13:49:44 +00:00
|
|
|
if (spec->dac_list)
|
|
|
|
stac92xx_power_down(codec);
|
2005-06-27 12:59:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-25 05:06:04 +00:00
|
|
|
static void stac92xx_free_jacks(struct hda_codec *codec)
|
|
|
|
{
|
2008-11-18 08:32:42 +00:00
|
|
|
#ifdef CONFIG_SND_JACK
|
2008-11-21 08:08:06 +00:00
|
|
|
/* free jack instances manually when clearing/reconfiguring */
|
2008-10-25 05:06:04 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-11-21 08:08:06 +00:00
|
|
|
if (!codec->bus->shutdown && spec->jacks.list) {
|
2008-10-25 05:06:04 +00:00
|
|
|
struct sigmatel_jack *jacks = spec->jacks.list;
|
|
|
|
int i;
|
2009-04-14 14:15:29 +00:00
|
|
|
for (i = 0; i < spec->jacks.used; i++, jacks++) {
|
|
|
|
if (jacks->jack)
|
|
|
|
snd_device_free(codec->bus->card, jacks->jack);
|
|
|
|
}
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
|
|
|
snd_array_free(&spec->jacks);
|
2008-11-18 08:32:42 +00:00
|
|
|
#endif
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
|
|
|
|
2008-07-30 13:01:44 +00:00
|
|
|
static void stac92xx_free_kctls(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (spec->kctls.list) {
|
|
|
|
struct snd_kcontrol_new *kctl = spec->kctls.list;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < spec->kctls.used; i++)
|
|
|
|
kfree(kctl[i].name);
|
|
|
|
}
|
|
|
|
snd_array_free(&spec->kctls);
|
|
|
|
}
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static void stac92xx_free(struct hda_codec *codec)
|
|
|
|
{
|
2005-06-27 12:59:41 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
|
|
|
if (! spec)
|
|
|
|
return;
|
|
|
|
|
2008-10-25 05:06:04 +00:00
|
|
|
stac92xx_free_jacks(codec);
|
|
|
|
snd_array_free(&spec->events);
|
2006-08-23 16:31:34 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
kfree(spec);
|
2008-07-18 16:20:52 +00:00
|
|
|
snd_hda_detach_beep_device(codec);
|
2005-04-13 12:45:30 +00:00
|
|
|
}
|
|
|
|
|
2005-07-04 15:51:39 +00:00
|
|
|
static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
unsigned int flag)
|
|
|
|
{
|
2009-01-22 15:59:20 +00:00
|
|
|
unsigned int old_ctl, pin_ctl;
|
|
|
|
|
|
|
|
pin_ctl = snd_hda_codec_read(codec, nid,
|
2005-07-04 15:51:39 +00:00
|
|
|
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
|
2007-05-29 16:01:06 +00:00
|
|
|
if (pin_ctl & AC_PINCTL_IN_EN) {
|
|
|
|
/*
|
|
|
|
* we need to check the current set-up direction of
|
|
|
|
* shared input pins since they can be switched via
|
|
|
|
* "xxx as Output" mixer switch
|
|
|
|
*/
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-12-19 08:26:08 +00:00
|
|
|
if (nid == spec->line_switch || nid == spec->mic_switch)
|
2007-05-29 16:01:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-22 15:59:20 +00:00
|
|
|
old_ctl = pin_ctl;
|
[ALSA] hda-codec - bug fixes for stac92xx HDA codecs.
* fixed surround playback on stac922x. Pin direction control bits were
not being set correctly in stac92xx_set_pinctl(). Specifically it
would refuse to set the port as an output if the port was already
configured as an input. Last hunk (#8).
* fixed an input mux bug on 92xx codecs. When there is more than one
possible input calculated for the muxes, the actual mux widget never
gets set from its reset default, which is index 0, in the stac9221
case that is port E. So alsamixer/amixer/gnome-mixer report the Mic
as being the selected input source, but in fact is something else
(line-in port E in stac9221 case). Another problem with this is that
if you actually try to set the mux input to 'Mic', nothing happens
because *cur_val == idx (see snd_hda_input_mux_put). You have to
actually toggle input source to line-in then back to mic to actually
set the mux widget. Hunk #7.
* fixed some typos in patch_sigmatel.c. Hunk #6.
* fix to stac92xx_add_dyn_out_pins() that fixes surround playback on
codecs with less that 4 DACs (stac9205 for example). It reads the widget
caps cache created by hda_codec to count the total number of analog DACs
found. It then uses that to determine whether there will be enough
independent DACs available for line/mic switch controls. Hunk #1, #2,
and #3.
* improvements to stac92xx_auto_fill_dac_nids() to make it more general.
This fixes surround playback on some codecs in combination with the
fix to stac92xx_add_dyn_out_pins() above. It reads the full connection
list now, instead of just the first entry, and then locates an analog
DAC in the list. If one is found and it's free, assign it to that line-out.
If no free DAC is found for the line-out, return -ENODEV. It also makes
sure to actually select the chosen DAC if more than one DAC is input to
the pin. Hunks #4, #5.
Signed-off-by: Steve Longerbeam <stevel@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
2007-05-03 18:50:03 +00:00
|
|
|
/* if setting pin direction bits, clear the current
|
|
|
|
direction bits first */
|
|
|
|
if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
|
|
|
|
pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
|
|
|
|
|
2009-01-22 15:59:20 +00:00
|
|
|
pin_ctl |= flag;
|
|
|
|
if (old_ctl != pin_ctl)
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
|
pin_ctl);
|
2005-07-04 15:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
unsigned int flag)
|
|
|
|
{
|
|
|
|
unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
|
|
|
|
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
|
2009-01-22 15:59:20 +00:00
|
|
|
if (pin_ctl & flag)
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_PIN_WIDGET_CONTROL,
|
|
|
|
pin_ctl & ~flag);
|
2005-07-04 15:51:39 +00:00
|
|
|
}
|
|
|
|
|
2008-12-05 11:54:56 +00:00
|
|
|
static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
|
2006-09-21 09:56:18 +00:00
|
|
|
{
|
|
|
|
if (!nid)
|
|
|
|
return 0;
|
|
|
|
if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
|
2008-12-05 11:54:56 +00:00
|
|
|
& (1 << 31))
|
|
|
|
return 1;
|
2006-09-21 09:56:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-12 08:48:04 +00:00
|
|
|
/* return non-zero if the hp-pin of the given array index isn't
|
|
|
|
* a jack-detection target
|
|
|
|
*/
|
|
|
|
static int no_hp_sensing(struct sigmatel_spec *spec, int i)
|
|
|
|
{
|
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
|
|
|
|
/* ignore sensing of shared line and mic jacks */
|
2008-12-19 08:26:08 +00:00
|
|
|
if (cfg->hp_pins[i] == spec->line_switch)
|
2008-11-12 08:48:04 +00:00
|
|
|
return 1;
|
2008-12-19 08:26:08 +00:00
|
|
|
if (cfg->hp_pins[i] == spec->mic_switch)
|
2008-11-12 08:48:04 +00:00
|
|
|
return 1;
|
|
|
|
/* ignore if the pin is set as line-out */
|
|
|
|
if (cfg->hp_pins[i] == spec->hp_switch)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
static void stac92xx_hp_detect(struct hda_codec *codec)
|
2005-07-04 15:51:39 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
|
|
|
int i, presence;
|
|
|
|
|
2006-09-20 15:10:27 +00:00
|
|
|
presence = 0;
|
2008-01-29 14:28:44 +00:00
|
|
|
if (spec->gpio_mute)
|
|
|
|
presence = !(snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
|
|
|
|
|
2006-09-20 15:10:27 +00:00
|
|
|
for (i = 0; i < cfg->hp_outs; i++) {
|
2006-09-21 09:56:18 +00:00
|
|
|
if (presence)
|
|
|
|
break;
|
2008-11-12 08:48:04 +00:00
|
|
|
if (no_hp_sensing(spec, i))
|
|
|
|
continue;
|
2008-12-05 11:54:56 +00:00
|
|
|
presence = get_pin_presence(codec, cfg->hp_pins[i]);
|
|
|
|
if (presence) {
|
|
|
|
unsigned int pinctl;
|
|
|
|
pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
|
|
|
|
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
|
|
|
|
if (pinctl & AC_PINCTL_IN_EN)
|
|
|
|
presence = 0; /* mic- or line-input */
|
|
|
|
}
|
2006-09-20 15:10:27 +00:00
|
|
|
}
|
2005-07-04 15:51:39 +00:00
|
|
|
|
|
|
|
if (presence) {
|
2008-11-12 08:48:04 +00:00
|
|
|
/* disable lineouts */
|
2008-04-16 11:13:59 +00:00
|
|
|
if (spec->hp_switch)
|
2008-11-12 08:48:04 +00:00
|
|
|
stac92xx_reset_pinctl(codec, spec->hp_switch,
|
|
|
|
AC_PINCTL_OUT_EN);
|
2005-07-04 15:51:39 +00:00
|
|
|
for (i = 0; i < cfg->line_outs; i++)
|
|
|
|
stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
|
|
|
|
AC_PINCTL_OUT_EN);
|
2006-09-20 15:10:27 +00:00
|
|
|
for (i = 0; i < cfg->speaker_outs; i++)
|
|
|
|
stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
|
|
|
|
AC_PINCTL_OUT_EN);
|
2008-11-16 16:42:34 +00:00
|
|
|
if (spec->eapd_mask && spec->eapd_switch)
|
2008-04-14 11:32:54 +00:00
|
|
|
stac_gpio_set(codec, spec->gpio_mask,
|
|
|
|
spec->gpio_dir, spec->gpio_data &
|
|
|
|
~spec->eapd_mask);
|
2005-07-04 15:51:39 +00:00
|
|
|
} else {
|
2008-11-12 08:48:04 +00:00
|
|
|
/* enable lineouts */
|
2008-04-16 11:13:59 +00:00
|
|
|
if (spec->hp_switch)
|
2008-11-12 08:48:04 +00:00
|
|
|
stac92xx_set_pinctl(codec, spec->hp_switch,
|
|
|
|
AC_PINCTL_OUT_EN);
|
2005-07-04 15:51:39 +00:00
|
|
|
for (i = 0; i < cfg->line_outs; i++)
|
|
|
|
stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
|
|
|
|
AC_PINCTL_OUT_EN);
|
2006-09-20 15:10:27 +00:00
|
|
|
for (i = 0; i < cfg->speaker_outs; i++)
|
|
|
|
stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
|
|
|
|
AC_PINCTL_OUT_EN);
|
2008-11-16 16:42:34 +00:00
|
|
|
if (spec->eapd_mask && spec->eapd_switch)
|
2008-04-14 11:32:54 +00:00
|
|
|
stac_gpio_set(codec, spec->gpio_mask,
|
|
|
|
spec->gpio_dir, spec->gpio_data |
|
|
|
|
spec->eapd_mask);
|
2005-07-04 15:51:39 +00:00
|
|
|
}
|
2008-11-12 08:48:04 +00:00
|
|
|
/* toggle hp outs */
|
|
|
|
for (i = 0; i < cfg->hp_outs; i++) {
|
|
|
|
unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
|
|
|
|
if (no_hp_sensing(spec, i))
|
|
|
|
continue;
|
|
|
|
if (presence)
|
|
|
|
stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
|
2009-01-14 06:56:51 +00:00
|
|
|
#if 0 /* FIXME */
|
|
|
|
/* Resetting the pinctl like below may lead to (a sort of) regressions
|
|
|
|
* on some devices since they use the HP pin actually for line/speaker
|
|
|
|
* outs although the default pin config shows a different pin (that is
|
|
|
|
* wrong and useless).
|
|
|
|
*
|
|
|
|
* So, it's basically a problem of default pin configs, likely a BIOS issue.
|
|
|
|
* But, disabling the code below just works around it, and I'm too tired of
|
|
|
|
* bug reports with such devices...
|
|
|
|
*/
|
2008-11-12 08:48:04 +00:00
|
|
|
else
|
|
|
|
stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
|
2009-01-14 06:56:51 +00:00
|
|
|
#endif /* FIXME */
|
2008-11-12 08:48:04 +00:00
|
|
|
}
|
2005-07-04 15:51:39 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 07:21:51 +00:00
|
|
|
static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
int enable)
|
2008-01-10 15:55:06 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-11-25 07:21:51 +00:00
|
|
|
unsigned int idx, val;
|
|
|
|
|
|
|
|
for (idx = 0; idx < spec->num_pwrs; idx++) {
|
|
|
|
if (spec->pwr_nids[idx] == nid)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (idx >= spec->num_pwrs)
|
|
|
|
return;
|
2008-07-27 08:30:30 +00:00
|
|
|
|
|
|
|
/* several codecs have two power down bits */
|
|
|
|
if (spec->pwr_mapping)
|
|
|
|
idx = spec->pwr_mapping[idx];
|
|
|
|
else
|
|
|
|
idx = 1 << idx;
|
2008-01-10 15:55:06 +00:00
|
|
|
|
2008-11-25 07:21:51 +00:00
|
|
|
val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
|
|
|
|
if (enable)
|
2008-01-10 15:55:06 +00:00
|
|
|
val &= ~idx;
|
|
|
|
else
|
|
|
|
val |= idx;
|
|
|
|
|
|
|
|
/* power down unused output ports */
|
|
|
|
snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
|
2008-10-25 05:06:04 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 07:21:51 +00:00
|
|
|
static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
2008-12-05 11:54:56 +00:00
|
|
|
stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
|
2008-11-25 07:21:51 +00:00
|
|
|
}
|
2008-01-10 15:55:06 +00:00
|
|
|
|
2008-10-25 05:06:04 +00:00
|
|
|
static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
struct sigmatel_jack *jacks = spec->jacks.list;
|
|
|
|
|
|
|
|
if (jacks) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < spec->jacks.used; i++) {
|
|
|
|
if (jacks->nid == nid) {
|
|
|
|
unsigned int pin_ctl =
|
|
|
|
snd_hda_codec_read(codec, nid,
|
|
|
|
0, AC_VERB_GET_PIN_WIDGET_CONTROL,
|
|
|
|
0x00);
|
|
|
|
int type = jacks->type;
|
|
|
|
if (type == (SND_JACK_LINEOUT
|
|
|
|
| SND_JACK_HEADPHONE))
|
|
|
|
type = (pin_ctl & AC_PINCTL_HP_EN)
|
|
|
|
? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
|
|
|
|
snd_jack_report(jacks->jack,
|
2008-12-05 11:54:56 +00:00
|
|
|
get_pin_presence(codec, nid)
|
2008-10-25 05:06:04 +00:00
|
|
|
? type : 0);
|
|
|
|
}
|
|
|
|
jacks++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-10 15:55:06 +00:00
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
|
|
|
|
unsigned char type)
|
|
|
|
{
|
|
|
|
struct sigmatel_event *event = stac_get_event(codec, nid, type);
|
|
|
|
if (!event)
|
|
|
|
return;
|
|
|
|
codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
|
|
|
|
}
|
|
|
|
|
2006-09-21 09:56:18 +00:00
|
|
|
static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
|
|
|
|
{
|
2008-01-10 15:55:06 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2008-11-25 10:58:19 +00:00
|
|
|
struct sigmatel_event *event;
|
|
|
|
int tag, data;
|
2008-01-10 15:55:06 +00:00
|
|
|
|
2008-11-25 10:58:19 +00:00
|
|
|
tag = (res >> 26) & 0x7f;
|
|
|
|
event = stac_get_event_from_tag(codec, tag);
|
|
|
|
if (!event)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (event->type) {
|
2006-09-21 09:56:18 +00:00
|
|
|
case STAC_HP_EVENT:
|
2008-11-25 10:58:19 +00:00
|
|
|
stac92xx_hp_detect(codec);
|
2008-01-10 15:55:06 +00:00
|
|
|
/* fallthru */
|
2008-10-25 05:06:04 +00:00
|
|
|
case STAC_INSERT_EVENT:
|
2008-01-10 15:55:06 +00:00
|
|
|
case STAC_PWR_EVENT:
|
2008-11-25 10:58:19 +00:00
|
|
|
if (spec->num_pwrs > 0)
|
|
|
|
stac92xx_pin_sense(codec, event->nid);
|
|
|
|
stac92xx_report_jack(codec, event->nid);
|
2009-04-06 13:30:46 +00:00
|
|
|
|
|
|
|
switch (codec->subsystem_id) {
|
|
|
|
case 0x103c308f:
|
|
|
|
if (event->nid == 0xb) {
|
|
|
|
int pin = AC_PINCTL_IN_EN;
|
|
|
|
|
|
|
|
if (get_pin_presence(codec, 0xa)
|
|
|
|
&& get_pin_presence(codec, 0xb))
|
|
|
|
pin |= AC_PINCTL_VREF_80;
|
|
|
|
if (!get_pin_presence(codec, 0xb))
|
|
|
|
pin |= AC_PINCTL_VREF_80;
|
|
|
|
|
|
|
|
/* toggle VREF state based on mic + hp pin
|
|
|
|
* status
|
|
|
|
*/
|
|
|
|
stac92xx_auto_set_pinctl(codec, 0x0a, pin);
|
|
|
|
}
|
|
|
|
}
|
2008-10-09 13:32:17 +00:00
|
|
|
break;
|
2008-11-25 10:58:19 +00:00
|
|
|
case STAC_VREF_EVENT:
|
|
|
|
data = snd_hda_codec_read(codec, codec->afg, 0,
|
|
|
|
AC_VERB_GET_GPIO_DATA, 0);
|
2008-10-09 13:32:17 +00:00
|
|
|
/* toggle VREF state based on GPIOx status */
|
|
|
|
snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
|
2008-11-25 10:58:19 +00:00
|
|
|
!!(data & (1 << event->data)));
|
2008-10-09 13:32:17 +00:00
|
|
|
break;
|
2006-09-21 09:56:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-28 13:35:16 +00:00
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
|
|
|
|
struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
if (nid == codec->afg)
|
|
|
|
snd_iprintf(buffer, "Power-Map: 0x%02x\n",
|
|
|
|
snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
|
|
|
|
struct hda_codec *codec,
|
|
|
|
unsigned int verb)
|
|
|
|
{
|
|
|
|
snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
|
|
|
|
snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stac92hd71bxx, stac92hd73xx */
|
|
|
|
static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
|
|
|
|
struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
stac92hd_proc_hook(buffer, codec, nid);
|
|
|
|
if (nid == codec->afg)
|
|
|
|
analog_loop_proc_hook(buffer, codec, 0xfa0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stac9205_proc_hook(struct snd_info_buffer *buffer,
|
|
|
|
struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
if (nid == codec->afg)
|
|
|
|
analog_loop_proc_hook(buffer, codec, 0xfe0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stac927x_proc_hook(struct snd_info_buffer *buffer,
|
|
|
|
struct hda_codec *codec, hda_nid_t nid)
|
|
|
|
{
|
|
|
|
if (nid == codec->afg)
|
|
|
|
analog_loop_proc_hook(buffer, codec, 0xfeb);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define stac92hd_proc_hook NULL
|
|
|
|
#define stac92hd7x_proc_hook NULL
|
|
|
|
#define stac9205_proc_hook NULL
|
|
|
|
#define stac927x_proc_hook NULL
|
|
|
|
#endif
|
|
|
|
|
2007-08-10 15:21:45 +00:00
|
|
|
#ifdef SND_HDA_NEEDS_RESUME
|
2005-06-27 13:06:52 +00:00
|
|
|
static int stac92xx_resume(struct hda_codec *codec)
|
|
|
|
{
|
2007-09-03 07:36:36 +00:00
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
|
2008-11-18 08:36:55 +00:00
|
|
|
stac92xx_init(codec);
|
2007-08-10 15:09:26 +00:00
|
|
|
snd_hda_codec_resume_amp(codec);
|
|
|
|
snd_hda_codec_resume_cache(codec);
|
2008-11-18 08:36:55 +00:00
|
|
|
/* fake event to set up pins again to override cached values */
|
2007-09-03 07:36:36 +00:00
|
|
|
if (spec->hp_detect)
|
2008-11-25 10:58:19 +00:00
|
|
|
stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
|
|
|
|
STAC_HP_EVENT);
|
2005-06-27 13:06:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-11-19 01:54:17 +00:00
|
|
|
|
2009-03-08 22:19:05 +00:00
|
|
|
/*
|
2009-05-03 08:00:44 +00:00
|
|
|
* using power check for controlling mute led of HP notebooks
|
2009-03-08 22:19:05 +00:00
|
|
|
* check for mute state only on Speakers (nid = 0x10)
|
|
|
|
*
|
|
|
|
* For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
|
|
|
|
* the LED is NOT working properly !
|
2009-05-03 08:00:44 +00:00
|
|
|
*
|
|
|
|
* Changed name to reflect that it now works for any designated
|
|
|
|
* model, not just HP HDX.
|
2009-03-08 22:19:05 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
2009-05-03 08:00:44 +00:00
|
|
|
static int stac92xx_hp_check_power_status(struct hda_codec *codec,
|
2009-03-10 06:48:57 +00:00
|
|
|
hda_nid_t nid)
|
2009-03-08 22:19:05 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
2009-05-03 08:00:44 +00:00
|
|
|
unsigned int gpio_bit = 0; /* gets rid of compiler warning */
|
|
|
|
|
|
|
|
switch (spec->board_config) {
|
|
|
|
case STAC_HP_DV4_1222NR:
|
|
|
|
gpio_bit = 0x01;
|
|
|
|
break;
|
|
|
|
case STAC_HP_HDX:
|
|
|
|
gpio_bit = 0x08;
|
|
|
|
}
|
2009-03-10 06:48:57 +00:00
|
|
|
|
|
|
|
if (nid == 0x10) {
|
|
|
|
if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
|
2009-03-08 22:19:05 +00:00
|
|
|
HDA_AMP_MUTE)
|
2009-05-03 08:00:44 +00:00
|
|
|
spec->gpio_data &= ~gpio_bit; /* orange */
|
2009-03-08 22:19:05 +00:00
|
|
|
else
|
2009-05-03 08:00:44 +00:00
|
|
|
spec->gpio_data |= gpio_bit; /* white */
|
2009-03-10 06:48:57 +00:00
|
|
|
|
|
|
|
stac_gpio_set(codec, spec->gpio_mask,
|
|
|
|
spec->gpio_dir,
|
2009-03-08 22:19:05 +00:00
|
|
|
spec->gpio_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-11-19 01:54:17 +00:00
|
|
|
static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
if (spec->eapd_mask)
|
|
|
|
stac_gpio_set(codec, spec->gpio_mask,
|
|
|
|
spec->gpio_dir, spec->gpio_data &
|
|
|
|
~spec->eapd_mask);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-06-27 13:06:52 +00:00
|
|
|
#endif
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static struct hda_codec_ops stac92xx_patch_ops = {
|
|
|
|
.build_controls = stac92xx_build_controls,
|
|
|
|
.build_pcms = stac92xx_build_pcms,
|
|
|
|
.init = stac92xx_init,
|
|
|
|
.free = stac92xx_free,
|
2005-07-04 15:51:39 +00:00
|
|
|
.unsol_event = stac92xx_unsol_event,
|
2007-08-10 15:21:45 +00:00
|
|
|
#ifdef SND_HDA_NEEDS_RESUME
|
2008-11-19 01:54:17 +00:00
|
|
|
.suspend = stac92xx_suspend,
|
2005-06-27 13:06:52 +00:00
|
|
|
.resume = stac92xx_resume,
|
|
|
|
#endif
|
2005-04-13 12:45:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int patch_stac9200(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
2005-06-27 12:59:41 +00:00
|
|
|
int err;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 12:21:46 +00:00
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
2005-04-13 12:45:30 +00:00
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2007-07-06 16:17:04 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
|
2006-08-23 16:31:34 +00:00
|
|
|
spec->pin_nids = stac9200_pin_nids;
|
2006-11-24 16:07:44 +00:00
|
|
|
spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
|
|
|
|
stac9200_models,
|
|
|
|
stac9200_cfg_tbl);
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2006-08-23 16:31:34 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac9200_brd_tbl[spec->board_config]);
|
2005-04-13 12:45:30 +00:00
|
|
|
|
|
|
|
spec->multiout.max_channels = 2;
|
|
|
|
spec->multiout.num_dacs = 1;
|
|
|
|
spec->multiout.dac_nids = stac9200_dac_nids;
|
|
|
|
spec->adc_nids = stac9200_adc_nids;
|
|
|
|
spec->mux_nids = stac9200_mux_nids;
|
2005-06-14 08:19:34 +00:00
|
|
|
spec->num_muxes = 1;
|
2006-10-26 15:12:59 +00:00
|
|
|
spec->num_dmics = 0;
|
2007-09-03 13:31:02 +00:00
|
|
|
spec->num_adcs = 1;
|
2008-01-10 15:55:06 +00:00
|
|
|
spec->num_pwrs = 0;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-08-11 08:18:39 +00:00
|
|
|
if (spec->board_config == STAC_9200_M4 ||
|
|
|
|
spec->board_config == STAC_9200_M4_2 ||
|
2008-02-03 19:31:47 +00:00
|
|
|
spec->board_config == STAC_9200_OQO)
|
2007-10-10 08:04:26 +00:00
|
|
|
spec->init = stac9200_eapd_init;
|
|
|
|
else
|
|
|
|
spec->init = stac9200_core_init;
|
2005-04-13 12:45:30 +00:00
|
|
|
spec->mixer = stac9200_mixer;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
2008-03-18 08:53:23 +00:00
|
|
|
if (spec->board_config == STAC_9200_PANASONIC) {
|
|
|
|
spec->gpio_mask = spec->gpio_dir = 0x09;
|
|
|
|
spec->gpio_data = 0x00;
|
|
|
|
}
|
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
err = stac9200_parse_auto_config(codec);
|
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2009-01-09 15:57:14 +00:00
|
|
|
/* CF-74 has no headphone detection, and the driver should *NOT*
|
|
|
|
* do detection and HP/speaker toggle because the hardware does it.
|
|
|
|
*/
|
|
|
|
if (spec->board_config == STAC_9200_PANASONIC)
|
|
|
|
spec->hp_detect = 0;
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-08 10:04:17 +00:00
|
|
|
static int patch_stac925x(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2007-07-06 16:17:04 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
|
2007-01-08 10:04:17 +00:00
|
|
|
spec->pin_nids = stac925x_pin_nids;
|
2008-08-11 08:18:39 +00:00
|
|
|
|
|
|
|
/* Check first for codec ID */
|
|
|
|
spec->board_config = snd_hda_check_board_codec_sid_config(codec,
|
|
|
|
STAC_925x_MODELS,
|
|
|
|
stac925x_models,
|
|
|
|
stac925x_codec_id_cfg_tbl);
|
|
|
|
|
|
|
|
/* Now checks for PCI ID, if codec ID is not found */
|
|
|
|
if (spec->board_config < 0)
|
|
|
|
spec->board_config = snd_hda_check_board_config(codec,
|
|
|
|
STAC_925x_MODELS,
|
2007-01-08 10:04:17 +00:00
|
|
|
stac925x_models,
|
|
|
|
stac925x_cfg_tbl);
|
2007-02-08 16:50:10 +00:00
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2008-08-11 08:18:39 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
|
2007-05-17 07:36:34 +00:00
|
|
|
"using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac925x_brd_tbl[spec->board_config]);
|
2007-01-08 10:04:17 +00:00
|
|
|
|
|
|
|
spec->multiout.max_channels = 2;
|
|
|
|
spec->multiout.num_dacs = 1;
|
|
|
|
spec->multiout.dac_nids = stac925x_dac_nids;
|
|
|
|
spec->adc_nids = stac925x_adc_nids;
|
|
|
|
spec->mux_nids = stac925x_mux_nids;
|
|
|
|
spec->num_muxes = 1;
|
2007-09-03 13:31:02 +00:00
|
|
|
spec->num_adcs = 1;
|
2008-01-10 15:55:06 +00:00
|
|
|
spec->num_pwrs = 0;
|
2007-05-17 07:36:34 +00:00
|
|
|
switch (codec->vendor_id) {
|
|
|
|
case 0x83847632: /* STAC9202 */
|
|
|
|
case 0x83847633: /* STAC9202D */
|
|
|
|
case 0x83847636: /* STAC9251 */
|
|
|
|
case 0x83847637: /* STAC9251D */
|
2007-10-16 12:27:04 +00:00
|
|
|
spec->num_dmics = STAC925X_NUM_DMICS;
|
2007-05-17 07:36:34 +00:00
|
|
|
spec->dmic_nids = stac925x_dmic_nids;
|
2007-12-18 17:05:52 +00:00
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
|
|
|
|
spec->dmux_nids = stac925x_dmux_nids;
|
2007-05-17 07:36:34 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
spec->num_dmics = 0;
|
|
|
|
break;
|
|
|
|
}
|
2007-01-08 10:04:17 +00:00
|
|
|
|
|
|
|
spec->init = stac925x_core_init;
|
|
|
|
spec->mixer = stac925x_mixer;
|
|
|
|
|
|
|
|
err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
|
2007-02-08 16:50:10 +00:00
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_925x_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
2007-01-08 10:04:17 +00:00
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
static struct hda_input_mux stac92hd73xx_dmux = {
|
|
|
|
.num_items = 4,
|
|
|
|
.items = {
|
|
|
|
{ "Analog Inputs", 0x0b },
|
|
|
|
{ "Digital Mic 1", 0x09 },
|
|
|
|
{ "Digital Mic 2", 0x0a },
|
2008-09-13 20:45:39 +00:00
|
|
|
{ "CD", 0x08 },
|
2007-12-13 16:47:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int patch_stac92hd73xx(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
|
|
|
hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
|
|
|
|
int err = 0;
|
2008-12-19 08:26:08 +00:00
|
|
|
int num_dacs;
|
2007-12-13 16:47:21 +00:00
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2008-09-09 08:46:38 +00:00
|
|
|
codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
|
|
|
|
spec->pin_nids = stac92hd73xx_pin_nids;
|
|
|
|
spec->board_config = snd_hda_check_board_config(codec,
|
|
|
|
STAC_92HD73XX_MODELS,
|
|
|
|
stac92hd73xx_models,
|
|
|
|
stac92hd73xx_cfg_tbl);
|
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2007-12-13 16:47:21 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
|
|
|
|
" STAC92HD73XX, using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac92hd73xx_brd_tbl[spec->board_config]);
|
2007-12-13 16:47:21 +00:00
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
num_dacs = snd_hda_get_connections(codec, 0x0a,
|
2007-12-13 16:47:21 +00:00
|
|
|
conn, STAC92HD73_DAC_COUNT + 2) - 1;
|
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
if (num_dacs < 3 || num_dacs > 5) {
|
2007-12-13 16:47:21 +00:00
|
|
|
printk(KERN_WARNING "hda_codec: Could not determine "
|
|
|
|
"number of channels defaulting to DAC count\n");
|
2008-12-19 08:26:08 +00:00
|
|
|
num_dacs = STAC92HD73_DAC_COUNT;
|
2007-12-13 16:47:21 +00:00
|
|
|
}
|
2008-12-19 08:26:08 +00:00
|
|
|
switch (num_dacs) {
|
2007-12-13 16:47:21 +00:00
|
|
|
case 0x3: /* 6 Channel */
|
|
|
|
spec->mixer = stac92hd73xx_6ch_mixer;
|
|
|
|
spec->init = stac92hd73xx_6ch_core_init;
|
2009-03-02 13:26:25 +00:00
|
|
|
spec->aloopback_ctl = stac92hd73xx_6ch_loopback;
|
2007-12-13 16:47:21 +00:00
|
|
|
break;
|
|
|
|
case 0x4: /* 8 Channel */
|
|
|
|
spec->mixer = stac92hd73xx_8ch_mixer;
|
|
|
|
spec->init = stac92hd73xx_8ch_core_init;
|
2009-03-02 13:26:25 +00:00
|
|
|
spec->aloopback_ctl = stac92hd73xx_8ch_loopback;
|
2007-12-13 16:47:21 +00:00
|
|
|
break;
|
|
|
|
case 0x5: /* 10 Channel */
|
|
|
|
spec->mixer = stac92hd73xx_10ch_mixer;
|
|
|
|
spec->init = stac92hd73xx_10ch_core_init;
|
2009-03-02 13:26:25 +00:00
|
|
|
spec->aloopback_ctl = stac92hd73xx_10ch_loopback;
|
|
|
|
break;
|
2008-12-19 08:26:08 +00:00
|
|
|
}
|
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
2007-12-13 16:47:21 +00:00
|
|
|
|
|
|
|
spec->aloopback_mask = 0x01;
|
|
|
|
spec->aloopback_shift = 8;
|
|
|
|
|
2008-07-18 16:20:52 +00:00
|
|
|
spec->digbeep_nid = 0x1c;
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->mux_nids = stac92hd73xx_mux_nids;
|
|
|
|
spec->adc_nids = stac92hd73xx_adc_nids;
|
|
|
|
spec->dmic_nids = stac92hd73xx_dmic_nids;
|
|
|
|
spec->dmux_nids = stac92hd73xx_dmux_nids;
|
2008-09-07 10:03:41 +00:00
|
|
|
spec->smux_nids = stac92hd73xx_smux_nids;
|
2008-09-11 13:49:39 +00:00
|
|
|
spec->amp_nids = stac92hd73xx_amp_nids;
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
|
2007-12-13 16:47:21 +00:00
|
|
|
|
|
|
|
spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
|
|
|
|
spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
|
2007-12-18 17:05:52 +00:00
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
|
2008-09-13 20:45:39 +00:00
|
|
|
memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
|
|
|
|
sizeof(stac92hd73xx_dmux));
|
|
|
|
|
2008-02-21 06:51:14 +00:00
|
|
|
switch (spec->board_config) {
|
2008-11-03 13:12:43 +00:00
|
|
|
case STAC_DELL_EQ:
|
2008-03-14 07:46:51 +00:00
|
|
|
spec->init = dell_eq_core_init;
|
2008-11-03 13:12:43 +00:00
|
|
|
/* fallthru */
|
2008-11-25 14:18:29 +00:00
|
|
|
case STAC_DELL_M6_AMIC:
|
|
|
|
case STAC_DELL_M6_DMIC:
|
|
|
|
case STAC_DELL_M6_BOTH:
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->num_smuxes = 0;
|
|
|
|
spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
|
|
|
|
spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
|
2008-11-16 16:42:34 +00:00
|
|
|
spec->eapd_switch = 0;
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->num_amps = 1;
|
2008-11-03 13:12:43 +00:00
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
if (spec->board_config != STAC_DELL_EQ)
|
2008-11-03 13:12:43 +00:00
|
|
|
spec->init = dell_m6_core_init;
|
2008-11-25 14:18:29 +00:00
|
|
|
switch (spec->board_config) {
|
|
|
|
case STAC_DELL_M6_AMIC: /* Analog Mics */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
|
2008-02-21 06:51:14 +00:00
|
|
|
spec->num_dmics = 0;
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->private_dimux.num_items = 1;
|
2008-02-21 06:51:14 +00:00
|
|
|
break;
|
2008-11-25 14:18:29 +00:00
|
|
|
case STAC_DELL_M6_DMIC: /* Digital Mics */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
|
2008-02-21 06:51:14 +00:00
|
|
|
spec->num_dmics = 1;
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->private_dimux.num_items = 2;
|
2008-02-21 06:51:14 +00:00
|
|
|
break;
|
2008-11-25 14:18:29 +00:00
|
|
|
case STAC_DELL_M6_BOTH: /* Both */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
|
|
|
|
snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
|
2008-02-21 06:51:14 +00:00
|
|
|
spec->num_dmics = 1;
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->private_dimux.num_items = 2;
|
2008-02-21 06:51:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
spec->num_dmics = STAC92HD73XX_NUM_DMICS;
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
|
2008-11-16 16:42:34 +00:00
|
|
|
spec->eapd_switch = 1;
|
2008-02-21 06:51:14 +00:00
|
|
|
}
|
2008-09-26 14:06:40 +00:00
|
|
|
if (spec->board_config > STAC_92HD73XX_REF) {
|
|
|
|
/* GPIO0 High = Enable EAPD */
|
|
|
|
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
|
|
|
|
spec->gpio_data = 0x01;
|
|
|
|
}
|
2008-09-13 20:45:39 +00:00
|
|
|
spec->dinput_mux = &spec->private_dimux;
|
2008-02-21 06:51:14 +00:00
|
|
|
|
2008-01-10 15:55:06 +00:00
|
|
|
spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
|
|
|
|
spec->pwr_nids = stac92hd73xx_pwr_nids;
|
|
|
|
|
2008-09-07 10:03:41 +00:00
|
|
|
err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
|
2007-12-13 16:47:21 +00:00
|
|
|
|
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_92HD73XX_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-12-17 13:51:01 +00:00
|
|
|
if (spec->board_config == STAC_92HD73XX_NO_JD)
|
|
|
|
spec->hp_detect = 0;
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
2008-11-28 13:35:16 +00:00
|
|
|
codec->proc_widget_hook = stac92hd7x_proc_hook;
|
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
static struct hda_input_mux stac92hd83xxx_dmux = {
|
|
|
|
.num_items = 3,
|
|
|
|
.items = {
|
|
|
|
{ "Analog Inputs", 0x03 },
|
|
|
|
{ "Digital Mic 1", 0x04 },
|
|
|
|
{ "Digital Mic 2", 0x05 },
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int patch_stac92hd83xxx(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
2009-01-20 21:50:25 +00:00
|
|
|
hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
|
2008-07-27 08:30:30 +00:00
|
|
|
int err;
|
2009-01-20 21:50:25 +00:00
|
|
|
int num_dacs;
|
2009-02-12 21:50:01 +00:00
|
|
|
hda_nid_t nid;
|
2008-07-27 08:30:30 +00:00
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2008-09-08 15:20:05 +00:00
|
|
|
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
|
2008-07-27 08:30:30 +00:00
|
|
|
spec->mono_nid = 0x19;
|
|
|
|
spec->digbeep_nid = 0x21;
|
|
|
|
spec->dmic_nids = stac92hd83xxx_dmic_nids;
|
|
|
|
spec->dmux_nids = stac92hd83xxx_dmux_nids;
|
|
|
|
spec->adc_nids = stac92hd83xxx_adc_nids;
|
|
|
|
spec->pwr_nids = stac92hd83xxx_pwr_nids;
|
2009-01-13 18:30:07 +00:00
|
|
|
spec->amp_nids = stac92hd83xxx_amp_nids;
|
2008-07-27 08:30:30 +00:00
|
|
|
spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
|
|
|
|
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
|
2008-12-19 08:26:08 +00:00
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
2008-07-27 08:30:30 +00:00
|
|
|
|
|
|
|
spec->init = stac92hd83xxx_core_init;
|
|
|
|
spec->mixer = stac92hd83xxx_mixer;
|
|
|
|
spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
|
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
|
|
|
|
spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
|
2009-01-13 18:30:07 +00:00
|
|
|
spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids);
|
2008-07-27 08:30:30 +00:00
|
|
|
spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
|
|
|
|
spec->dinput_mux = &stac92hd83xxx_dmux;
|
|
|
|
spec->pin_nids = stac92hd83xxx_pin_nids;
|
|
|
|
spec->board_config = snd_hda_check_board_config(codec,
|
|
|
|
STAC_92HD83XXX_MODELS,
|
|
|
|
stac92hd83xxx_models,
|
|
|
|
stac92hd83xxx_cfg_tbl);
|
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2008-07-27 08:30:30 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
|
|
|
|
" STAC92HD83XXX, using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac92hd83xxx_brd_tbl[spec->board_config]);
|
2008-07-27 08:30:30 +00:00
|
|
|
|
2009-01-23 01:53:29 +00:00
|
|
|
switch (codec->vendor_id) {
|
|
|
|
case 0x111d7604:
|
|
|
|
case 0x111d7605:
|
2009-04-01 18:49:48 +00:00
|
|
|
case 0x111d76d5:
|
2009-01-23 01:53:29 +00:00
|
|
|
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
|
|
|
|
break;
|
|
|
|
spec->num_pwrs = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
err = stac92xx_parse_auto_config(codec, 0x1d, 0);
|
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_92HD83XXX_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2009-02-12 21:50:01 +00:00
|
|
|
switch (spec->board_config) {
|
|
|
|
case STAC_DELL_S14:
|
|
|
|
nid = 0xf;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nid = 0xe;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_dacs = snd_hda_get_connections(codec, nid,
|
|
|
|
conn, STAC92HD83_DAC_COUNT + 1) - 1;
|
|
|
|
|
|
|
|
/* set port X to select the last DAC
|
|
|
|
*/
|
|
|
|
snd_hda_codec_write_cache(codec, nid, 0,
|
|
|
|
AC_VERB_SET_CONNECT_SEL, num_dacs);
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
2008-11-28 13:35:16 +00:00
|
|
|
codec->proc_widget_hook = stac92hd_proc_hook;
|
|
|
|
|
2008-07-27 08:30:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-04 16:34:22 +00:00
|
|
|
static struct hda_input_mux stac92hd71bxx_dmux_nomixer = {
|
|
|
|
.num_items = 3,
|
|
|
|
.items = {
|
|
|
|
{ "Analog Inputs", 0x00 },
|
|
|
|
{ "Digital Mic 1", 0x02 },
|
|
|
|
{ "Digital Mic 2", 0x03 },
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct hda_input_mux stac92hd71bxx_dmux_amixer = {
|
2008-10-10 13:07:23 +00:00
|
|
|
.num_items = 4,
|
|
|
|
.items = {
|
|
|
|
{ "Analog Inputs", 0x00 },
|
|
|
|
{ "Mixer", 0x01 },
|
|
|
|
{ "Digital Mic 1", 0x02 },
|
|
|
|
{ "Digital Mic 2", 0x03 },
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-02-20 13:33:36 +00:00
|
|
|
/* get the pin connection (fixed, none, etc) */
|
|
|
|
static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
unsigned int cfg;
|
|
|
|
|
|
|
|
cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
|
|
|
|
return get_defcfg_connect(cfg);
|
|
|
|
}
|
|
|
|
|
2009-02-04 16:34:22 +00:00
|
|
|
static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
|
|
|
|
hda_nid_t *nids, int num_nids)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int idx, num;
|
|
|
|
unsigned int def_conf;
|
|
|
|
|
|
|
|
for (num = 0; num < num_nids; num++) {
|
|
|
|
for (idx = 0; idx < spec->num_pins; idx++)
|
|
|
|
if (spec->pin_nids[idx] == nids[num])
|
|
|
|
break;
|
|
|
|
if (idx >= spec->num_pins)
|
|
|
|
break;
|
2009-02-20 13:33:36 +00:00
|
|
|
def_conf = stac_get_defcfg_connect(codec, idx);
|
2009-02-04 16:34:22 +00:00
|
|
|
if (def_conf == AC_JACK_PORT_NONE)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
|
|
|
|
hda_nid_t dig0pin)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec = codec->spec;
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
for (idx = 0; idx < spec->num_pins; idx++)
|
|
|
|
if (spec->pin_nids[idx] == dig0pin)
|
|
|
|
break;
|
|
|
|
if ((idx + 2) >= spec->num_pins)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* dig1pin case */
|
2009-02-20 13:33:36 +00:00
|
|
|
if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE)
|
2009-02-04 16:34:22 +00:00
|
|
|
return 2;
|
|
|
|
|
|
|
|
/* dig0pin + dig2pin case */
|
2009-02-20 13:33:36 +00:00
|
|
|
if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE)
|
2009-02-04 16:34:22 +00:00
|
|
|
return 2;
|
2009-02-20 13:33:36 +00:00
|
|
|
if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE)
|
2009-02-04 16:34:22 +00:00
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
static int patch_stac92hd71bxx(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
2009-01-26 14:33:52 +00:00
|
|
|
struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
|
2007-11-06 10:53:55 +00:00
|
|
|
int err = 0;
|
2009-02-04 16:34:22 +00:00
|
|
|
unsigned int ndmic_nids = 0;
|
2007-11-06 10:53:55 +00:00
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2008-08-15 05:45:52 +00:00
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
2009-02-04 16:23:19 +00:00
|
|
|
spec->num_pins = STAC92HD71BXX_NUM_PINS;
|
|
|
|
switch (codec->vendor_id) {
|
|
|
|
case 0x111d76b6:
|
|
|
|
case 0x111d76b7:
|
|
|
|
spec->pin_nids = stac92hd71bxx_pin_nids_4port;
|
|
|
|
break;
|
|
|
|
case 0x111d7603:
|
|
|
|
case 0x111d7608:
|
|
|
|
/* On 92HD75Bx 0x27 isn't a pin nid */
|
|
|
|
spec->num_pins--;
|
|
|
|
/* fallthrough */
|
|
|
|
default:
|
|
|
|
spec->pin_nids = stac92hd71bxx_pin_nids_6port;
|
|
|
|
}
|
2008-06-13 16:04:33 +00:00
|
|
|
spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
|
2007-11-06 10:53:55 +00:00
|
|
|
spec->board_config = snd_hda_check_board_config(codec,
|
|
|
|
STAC_92HD71BXX_MODELS,
|
|
|
|
stac92hd71bxx_models,
|
|
|
|
stac92hd71bxx_cfg_tbl);
|
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2007-11-06 10:53:55 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
|
|
|
|
" STAC92HD71BXX, using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac92hd71bxx_brd_tbl[spec->board_config]);
|
2007-11-06 10:53:55 +00:00
|
|
|
|
2008-11-18 09:45:15 +00:00
|
|
|
if (spec->board_config > STAC_92HD71BXX_REF) {
|
|
|
|
/* GPIO0 = EAPD */
|
|
|
|
spec->gpio_mask = 0x01;
|
|
|
|
spec->gpio_dir = 0x01;
|
|
|
|
spec->gpio_data = 0x01;
|
|
|
|
}
|
|
|
|
|
2009-02-04 16:34:22 +00:00
|
|
|
spec->dmic_nids = stac92hd71bxx_dmic_nids;
|
|
|
|
spec->dmux_nids = stac92hd71bxx_dmux_nids;
|
|
|
|
|
2007-12-14 11:08:04 +00:00
|
|
|
switch (codec->vendor_id) {
|
|
|
|
case 0x111d76b6: /* 4 Port without Analog Mixer */
|
|
|
|
case 0x111d76b7:
|
2009-02-08 21:51:28 +00:00
|
|
|
unmute_init++;
|
|
|
|
/* fallthru */
|
2007-12-14 11:08:04 +00:00
|
|
|
case 0x111d76b4: /* 6 Port without Analog Mixer */
|
|
|
|
case 0x111d76b5:
|
2009-02-04 16:34:22 +00:00
|
|
|
memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer,
|
|
|
|
sizeof(stac92hd71bxx_dmux_nomixer));
|
2007-12-14 11:08:04 +00:00
|
|
|
spec->mixer = stac92hd71bxx_mixer;
|
|
|
|
spec->init = stac92hd71bxx_core_init;
|
2008-09-08 15:20:05 +00:00
|
|
|
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
|
2009-02-04 16:34:22 +00:00
|
|
|
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
|
|
|
|
stac92hd71bxx_dmic_nids,
|
|
|
|
STAC92HD71BXX_NUM_DMICS);
|
|
|
|
if (spec->num_dmics) {
|
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
|
|
|
|
spec->dinput_mux = &spec->private_dimux;
|
|
|
|
ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
|
|
|
|
}
|
2007-12-14 11:08:04 +00:00
|
|
|
break;
|
2008-06-13 16:04:33 +00:00
|
|
|
case 0x111d7608: /* 5 Port with Analog Mixer */
|
2009-02-04 16:34:22 +00:00
|
|
|
memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
|
|
|
|
sizeof(stac92hd71bxx_dmux_amixer));
|
|
|
|
spec->private_dimux.num_items--;
|
2008-11-15 18:28:54 +00:00
|
|
|
switch (spec->board_config) {
|
|
|
|
case STAC_HP_M4:
|
2008-10-09 13:32:17 +00:00
|
|
|
/* Enable VREF power saving on GPIO1 detect */
|
2008-11-25 10:58:19 +00:00
|
|
|
err = stac_add_event(spec, codec->afg,
|
|
|
|
STAC_VREF_EVENT, 0x02);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-11-18 09:55:36 +00:00
|
|
|
snd_hda_codec_write_cache(codec, codec->afg, 0,
|
2008-10-09 13:32:17 +00:00
|
|
|
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
|
|
|
|
snd_hda_codec_write_cache(codec, codec->afg, 0,
|
2008-10-25 05:06:04 +00:00
|
|
|
AC_VERB_SET_UNSOLICITED_ENABLE,
|
2008-11-25 10:58:19 +00:00
|
|
|
AC_USRSP_EN | err);
|
2008-10-09 13:32:17 +00:00
|
|
|
spec->gpio_mask |= 0x02;
|
|
|
|
break;
|
|
|
|
}
|
2008-08-15 05:45:52 +00:00
|
|
|
if ((codec->revision_id & 0xf) == 0 ||
|
2008-12-01 10:54:35 +00:00
|
|
|
(codec->revision_id & 0xf) == 1)
|
2008-08-15 05:45:52 +00:00
|
|
|
spec->stream_delay = 40; /* 40 milliseconds */
|
|
|
|
|
2008-06-13 16:04:33 +00:00
|
|
|
/* no output amps */
|
|
|
|
spec->num_pwrs = 0;
|
|
|
|
spec->mixer = stac92hd71bxx_analog_mixer;
|
2008-10-10 13:07:23 +00:00
|
|
|
spec->dinput_mux = &spec->private_dimux;
|
2008-06-13 16:04:33 +00:00
|
|
|
|
|
|
|
/* disable VSW */
|
|
|
|
spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
|
2009-01-26 14:33:52 +00:00
|
|
|
unmute_init++;
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
|
|
|
|
snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
|
2009-02-04 16:34:22 +00:00
|
|
|
stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
|
|
|
|
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
|
|
|
|
stac92hd71bxx_dmic_nids,
|
|
|
|
STAC92HD71BXX_NUM_DMICS - 1);
|
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
|
|
|
|
ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2;
|
2008-06-13 16:04:33 +00:00
|
|
|
break;
|
|
|
|
case 0x111d7603: /* 6 Port with Analog Mixer */
|
2008-12-01 10:54:35 +00:00
|
|
|
if ((codec->revision_id & 0xf) == 1)
|
2008-08-15 05:45:52 +00:00
|
|
|
spec->stream_delay = 40; /* 40 milliseconds */
|
|
|
|
|
2008-06-13 16:04:33 +00:00
|
|
|
/* no output amps */
|
|
|
|
spec->num_pwrs = 0;
|
|
|
|
/* fallthru */
|
2007-12-14 11:08:04 +00:00
|
|
|
default:
|
2009-02-04 16:34:22 +00:00
|
|
|
memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
|
|
|
|
sizeof(stac92hd71bxx_dmux_amixer));
|
2008-10-10 13:07:23 +00:00
|
|
|
spec->dinput_mux = &spec->private_dimux;
|
2007-12-14 11:08:04 +00:00
|
|
|
spec->mixer = stac92hd71bxx_analog_mixer;
|
|
|
|
spec->init = stac92hd71bxx_analog_core_init;
|
2008-09-08 15:20:05 +00:00
|
|
|
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
|
2009-02-04 16:34:22 +00:00
|
|
|
spec->num_dmics = stac92hd71bxx_connected_ports(codec,
|
|
|
|
stac92hd71bxx_dmic_nids,
|
|
|
|
STAC92HD71BXX_NUM_DMICS);
|
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
|
|
|
|
ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
|
2007-12-14 11:08:04 +00:00
|
|
|
}
|
|
|
|
|
2009-01-26 14:33:52 +00:00
|
|
|
if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
|
|
|
|
snd_hda_sequence_write_cache(codec, unmute_init);
|
|
|
|
|
2009-03-02 13:26:25 +00:00
|
|
|
spec->aloopback_ctl = stac92hd71bxx_loopback;
|
2008-10-10 13:07:23 +00:00
|
|
|
spec->aloopback_mask = 0x50;
|
2007-12-14 11:08:04 +00:00
|
|
|
spec->aloopback_shift = 0;
|
|
|
|
|
2008-08-15 05:45:52 +00:00
|
|
|
spec->powerdown_adcs = 1;
|
2008-07-18 16:20:52 +00:00
|
|
|
spec->digbeep_nid = 0x26;
|
2007-11-06 10:53:55 +00:00
|
|
|
spec->mux_nids = stac92hd71bxx_mux_nids;
|
|
|
|
spec->adc_nids = stac92hd71bxx_adc_nids;
|
2008-09-07 10:03:41 +00:00
|
|
|
spec->smux_nids = stac92hd71bxx_smux_nids;
|
2008-06-13 16:04:33 +00:00
|
|
|
spec->pwr_nids = stac92hd71bxx_pwr_nids;
|
2007-11-06 10:53:55 +00:00
|
|
|
|
|
|
|
spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
|
|
|
|
spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
|
2009-02-04 16:34:22 +00:00
|
|
|
spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
|
2007-11-06 10:53:55 +00:00
|
|
|
|
2008-09-12 16:02:30 +00:00
|
|
|
switch (spec->board_config) {
|
|
|
|
case STAC_HP_M4:
|
|
|
|
/* enable internal microphone */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
|
2008-10-09 12:37:28 +00:00
|
|
|
stac92xx_auto_set_pinctl(codec, 0x0e,
|
|
|
|
AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
|
2008-11-21 02:21:43 +00:00
|
|
|
/* fallthru */
|
|
|
|
case STAC_DELL_M4_2:
|
|
|
|
spec->num_dmics = 0;
|
|
|
|
spec->num_smuxes = 0;
|
|
|
|
spec->num_dmuxes = 0;
|
|
|
|
break;
|
|
|
|
case STAC_DELL_M4_1:
|
|
|
|
case STAC_DELL_M4_3:
|
|
|
|
spec->num_dmics = 1;
|
|
|
|
spec->num_smuxes = 0;
|
2009-02-27 16:36:33 +00:00
|
|
|
spec->num_dmuxes = 1;
|
2008-09-12 16:02:30 +00:00
|
|
|
break;
|
2009-05-03 08:00:44 +00:00
|
|
|
case STAC_HP_DV4_1222NR:
|
|
|
|
spec->num_dmics = 1;
|
|
|
|
/* I don't know if it needs 1 or 2 smuxes - will wait for
|
|
|
|
* bug reports to fix if needed
|
|
|
|
*/
|
|
|
|
spec->num_smuxes = 1;
|
|
|
|
spec->num_dmuxes = 1;
|
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
|
|
|
/* This controls MUTE LED */
|
|
|
|
spec->gpio_mask |= 0x01;
|
|
|
|
spec->gpio_dir |= 0x01;
|
|
|
|
spec->gpio_data |= 0x01;
|
|
|
|
codec->patch_ops.check_power_status =
|
|
|
|
stac92xx_hp_check_power_status;
|
|
|
|
#endif
|
|
|
|
/* fallthrough */
|
2009-02-16 09:23:00 +00:00
|
|
|
case STAC_HP_DV5:
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
|
2009-02-16 09:23:00 +00:00
|
|
|
stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
|
|
|
|
break;
|
2009-03-08 22:19:05 +00:00
|
|
|
case STAC_HP_HDX:
|
|
|
|
spec->num_dmics = 1;
|
|
|
|
spec->num_dmuxes = 1;
|
|
|
|
spec->num_smuxes = 1;
|
2009-03-10 06:48:57 +00:00
|
|
|
/*
|
2009-03-09 23:05:56 +00:00
|
|
|
* For controlling MUTE LED on HP HDX16/HDX18 notebooks,
|
|
|
|
* the CONFIG_SND_HDA_POWER_SAVE is needed to be set.
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
|
|
|
/* orange/white mute led on GPIO3, orange=0, white=1 */
|
|
|
|
spec->gpio_mask |= 0x08;
|
|
|
|
spec->gpio_dir |= 0x08;
|
|
|
|
spec->gpio_data |= 0x08; /* set to white */
|
|
|
|
|
|
|
|
/* register check_power_status callback. */
|
2009-03-10 06:48:57 +00:00
|
|
|
codec->patch_ops.check_power_status =
|
2009-05-03 08:00:44 +00:00
|
|
|
stac92xx_hp_check_power_status;
|
2009-03-09 23:05:56 +00:00
|
|
|
#endif
|
2009-03-08 22:19:05 +00:00
|
|
|
break;
|
2008-09-12 16:02:30 +00:00
|
|
|
};
|
|
|
|
|
2008-12-19 08:26:08 +00:00
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
2008-10-10 13:07:23 +00:00
|
|
|
if (spec->dinput_mux)
|
2009-02-04 16:34:22 +00:00
|
|
|
spec->private_dimux.num_items += spec->num_dmics - ndmic_nids;
|
2007-11-06 10:53:55 +00:00
|
|
|
|
2009-02-04 16:37:27 +00:00
|
|
|
err = stac92xx_parse_auto_config(codec, 0x21, 0);
|
2007-11-06 10:53:55 +00:00
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_92HD71BXX_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-11-28 13:35:16 +00:00
|
|
|
codec->proc_widget_hook = stac92hd7x_proc_hook;
|
|
|
|
|
2007-11-06 10:53:55 +00:00
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
static int patch_stac922x(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
2005-06-27 12:59:41 +00:00
|
|
|
int err;
|
2005-04-13 12:45:30 +00:00
|
|
|
|
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 12:21:46 +00:00
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
2005-04-13 12:45:30 +00:00
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2007-07-06 16:17:04 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
|
2006-08-23 16:31:34 +00:00
|
|
|
spec->pin_nids = stac922x_pin_nids;
|
2006-11-24 16:07:44 +00:00
|
|
|
spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
|
|
|
|
stac922x_models,
|
|
|
|
stac922x_cfg_tbl);
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
if (spec->board_config == STAC_INTEL_MAC_AUTO) {
|
2008-01-29 14:28:44 +00:00
|
|
|
spec->gpio_mask = spec->gpio_dir = 0x03;
|
|
|
|
spec->gpio_data = 0x03;
|
2007-02-16 12:27:18 +00:00
|
|
|
/* Intel Macs have all same PCI SSID, so we need to check
|
|
|
|
* codec SSID to distinguish the exact models
|
|
|
|
*/
|
2007-03-15 11:38:15 +00:00
|
|
|
printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
|
2007-02-16 12:27:18 +00:00
|
|
|
switch (codec->subsystem_id) {
|
2007-05-29 14:03:00 +00:00
|
|
|
|
|
|
|
case 0x106b0800:
|
|
|
|
spec->board_config = STAC_INTEL_MAC_V1;
|
2007-04-17 09:57:16 +00:00
|
|
|
break;
|
2007-05-29 14:03:00 +00:00
|
|
|
case 0x106b0600:
|
|
|
|
case 0x106b0700:
|
|
|
|
spec->board_config = STAC_INTEL_MAC_V2;
|
2007-03-15 11:38:15 +00:00
|
|
|
break;
|
2007-05-29 14:03:00 +00:00
|
|
|
case 0x106b0e00:
|
|
|
|
case 0x106b0f00:
|
|
|
|
case 0x106b1600:
|
|
|
|
case 0x106b1700:
|
|
|
|
case 0x106b0200:
|
|
|
|
case 0x106b1e00:
|
|
|
|
spec->board_config = STAC_INTEL_MAC_V3;
|
2007-02-16 12:27:18 +00:00
|
|
|
break;
|
2007-05-29 14:03:00 +00:00
|
|
|
case 0x106b1a00:
|
|
|
|
case 0x00000100:
|
|
|
|
spec->board_config = STAC_INTEL_MAC_V4;
|
2007-04-27 12:22:36 +00:00
|
|
|
break;
|
2007-05-29 14:03:00 +00:00
|
|
|
case 0x106b0a00:
|
|
|
|
case 0x106b2200:
|
|
|
|
spec->board_config = STAC_INTEL_MAC_V5;
|
2007-05-21 10:41:29 +00:00
|
|
|
break;
|
ALSA: Allow to force model to intel-mac-v3 in snd_hda_intel (sigmatel).
Currently, even if you pass model=intel-mac-v3 as a module parameter to
snd_hda_intel, the function patch_stac922x (patch_sigmatel.c) will still
try to auto-detect the model type. This is a problem on my MacBook Pro 1st
generation, which needs intel-mac-v3, but sometimes incorrectly reports
0x00000100 as subsystem id, which causes the switch in patch_stac922x to
select intel-mac-v4.
To fix this, I added a new model called intel-mac-auto, so in case no
module parameter is passed, and an Intel Mac board is detected, the
model will be automatically detected, while no detection will be done
if the model is forced to intel-mac-v3.
This problem has been around for quite a while, and I used to fix it
by moving the case statement for 0x00000100 in patch_stac922x so that
intel-mac-v3 is chosen.
Another way to fix the problem would be to check if a module parameter
was set directly in patch_stac922x, using something like this:
if (spec->board_config == STAC_INTEL_MAC_V3 &&
!codec->bus->modelname) {
But I think it is less elegant (if you prefer that way, I can prepare a
patch).
Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2008-07-21 14:18:01 +00:00
|
|
|
default:
|
|
|
|
spec->board_config = STAC_INTEL_MAC_V3;
|
|
|
|
break;
|
2007-02-16 12:27:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-08 16:50:10 +00:00
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2006-08-23 16:31:34 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
|
|
|
|
"using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac922x_brd_tbl[spec->board_config]);
|
2005-04-13 12:45:30 +00:00
|
|
|
|
2005-06-27 12:59:41 +00:00
|
|
|
spec->adc_nids = stac922x_adc_nids;
|
|
|
|
spec->mux_nids = stac922x_mux_nids;
|
2007-03-12 11:36:16 +00:00
|
|
|
spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
|
2007-09-03 13:31:02 +00:00
|
|
|
spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
|
2006-10-26 15:12:59 +00:00
|
|
|
spec->num_dmics = 0;
|
2008-01-10 15:55:06 +00:00
|
|
|
spec->num_pwrs = 0;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
spec->init = stac922x_core_init;
|
2005-04-13 12:45:30 +00:00
|
|
|
spec->mixer = stac922x_mixer;
|
2005-06-27 12:59:41 +00:00
|
|
|
|
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
2006-06-28 13:52:16 +00:00
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
|
2007-02-08 16:50:10 +00:00
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_D945_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
2006-01-23 14:27:49 +00:00
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
2007-05-29 17:01:37 +00:00
|
|
|
/* Fix Mux capture level; max to 2 */
|
|
|
|
snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
|
|
|
|
(0 << AC_AMPCAP_OFFSET_SHIFT) |
|
|
|
|
(2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
|
|
|
|
(0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
|
|
|
|
(0 << AC_AMPCAP_MUTE_SHIFT));
|
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int patch_stac927x(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2009-02-04 22:49:41 +00:00
|
|
|
codec->slave_dig_outs = stac927x_slave_dig_outs;
|
2007-07-06 16:17:04 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
|
2006-08-23 16:31:34 +00:00
|
|
|
spec->pin_nids = stac927x_pin_nids;
|
2006-11-24 16:07:44 +00:00
|
|
|
spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
|
|
|
|
stac927x_models,
|
|
|
|
stac927x_cfg_tbl);
|
2007-02-08 16:50:10 +00:00
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2009-02-11 22:33:15 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for"
|
|
|
|
"STAC927x, using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac927x_brd_tbl[spec->board_config]);
|
2006-01-23 14:27:49 +00:00
|
|
|
|
2008-07-18 16:20:52 +00:00
|
|
|
spec->digbeep_nid = 0x23;
|
2007-12-17 10:58:13 +00:00
|
|
|
spec->adc_nids = stac927x_adc_nids;
|
|
|
|
spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
|
|
|
|
spec->mux_nids = stac927x_mux_nids;
|
|
|
|
spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
|
2008-09-07 10:03:41 +00:00
|
|
|
spec->smux_nids = stac927x_smux_nids;
|
|
|
|
spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
|
2008-09-16 14:39:37 +00:00
|
|
|
spec->spdif_labels = stac927x_spdif_labels;
|
2008-02-06 13:49:44 +00:00
|
|
|
spec->dac_list = stac927x_dac_nids;
|
2007-12-17 10:58:13 +00:00
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
|
|
|
|
2006-08-22 17:44:45 +00:00
|
|
|
switch (spec->board_config) {
|
2006-09-01 19:03:12 +00:00
|
|
|
case STAC_D965_3ST:
|
|
|
|
case STAC_D965_5ST:
|
2007-12-17 10:58:13 +00:00
|
|
|
/* GPIO0 High = Enable EAPD */
|
2008-04-14 11:32:54 +00:00
|
|
|
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
|
2008-01-29 14:28:44 +00:00
|
|
|
spec->gpio_data = 0x01;
|
2007-12-17 10:58:13 +00:00
|
|
|
spec->num_dmics = 0;
|
|
|
|
|
2006-09-01 19:03:12 +00:00
|
|
|
spec->init = d965_core_init;
|
2007-09-03 13:31:02 +00:00
|
|
|
spec->mixer = stac927x_mixer;
|
2006-08-22 17:44:45 +00:00
|
|
|
break;
|
2007-12-17 10:58:13 +00:00
|
|
|
case STAC_DELL_BIOS:
|
2008-04-14 11:32:27 +00:00
|
|
|
switch (codec->subsystem_id) {
|
|
|
|
case 0x10280209:
|
|
|
|
case 0x1028022e:
|
|
|
|
/* correct the device field to SPDIF out */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070);
|
2008-04-14 11:32:27 +00:00
|
|
|
break;
|
|
|
|
};
|
2008-02-21 06:51:46 +00:00
|
|
|
/* configure the analog microphone on some laptops */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130);
|
2008-01-10 12:06:26 +00:00
|
|
|
/* correct the front output jack as a hp out */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f);
|
2008-01-07 11:18:28 +00:00
|
|
|
/* correct the front input jack as a mic */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130);
|
2008-01-07 11:18:28 +00:00
|
|
|
/* fallthru */
|
2007-12-17 10:58:13 +00:00
|
|
|
case STAC_DELL_3ST:
|
|
|
|
/* GPIO2 High = Enable EAPD */
|
2008-04-14 11:32:54 +00:00
|
|
|
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
|
2008-01-29 14:28:44 +00:00
|
|
|
spec->gpio_data = 0x04;
|
2007-10-18 15:38:17 +00:00
|
|
|
spec->dmic_nids = stac927x_dmic_nids;
|
|
|
|
spec->num_dmics = STAC927X_NUM_DMICS;
|
2007-11-05 14:30:13 +00:00
|
|
|
|
2007-12-17 10:58:13 +00:00
|
|
|
spec->init = d965_core_init;
|
|
|
|
spec->mixer = stac927x_mixer;
|
|
|
|
spec->dmux_nids = stac927x_dmux_nids;
|
2007-12-18 17:05:52 +00:00
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
|
2007-10-18 15:38:17 +00:00
|
|
|
break;
|
|
|
|
default:
|
2008-09-26 14:06:40 +00:00
|
|
|
if (spec->board_config > STAC_D965_REF) {
|
|
|
|
/* GPIO0 High = Enable EAPD */
|
|
|
|
spec->eapd_mask = spec->gpio_mask = 0x01;
|
|
|
|
spec->gpio_dir = spec->gpio_data = 0x01;
|
|
|
|
}
|
2007-12-17 10:58:13 +00:00
|
|
|
spec->num_dmics = 0;
|
|
|
|
|
|
|
|
spec->init = stac927x_core_init;
|
|
|
|
spec->mixer = stac927x_mixer;
|
2007-10-18 15:38:17 +00:00
|
|
|
}
|
|
|
|
|
2008-01-10 15:55:06 +00:00
|
|
|
spec->num_pwrs = 0;
|
2009-03-02 13:26:25 +00:00
|
|
|
spec->aloopback_ctl = stac927x_loopback;
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->aloopback_mask = 0x40;
|
|
|
|
spec->aloopback_shift = 0;
|
2008-11-16 16:42:34 +00:00
|
|
|
spec->eapd_switch = 1;
|
2007-12-17 10:58:13 +00:00
|
|
|
|
2006-01-23 14:27:49 +00:00
|
|
|
err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
|
2007-02-08 16:50:10 +00:00
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_D965_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
2005-06-27 12:59:41 +00:00
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
2005-04-13 12:45:30 +00:00
|
|
|
|
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
2008-11-28 13:35:16 +00:00
|
|
|
codec->proc_widget_hook = stac927x_proc_hook;
|
|
|
|
|
2008-01-16 15:09:47 +00:00
|
|
|
/*
|
|
|
|
* !!FIXME!!
|
|
|
|
* The STAC927x seem to require fairly long delays for certain
|
|
|
|
* command sequences. With too short delays (even if the answer
|
|
|
|
* is set to RIRB properly), it results in the silence output
|
|
|
|
* on some hardwares like Dell.
|
|
|
|
*
|
|
|
|
* The below flag enables the longer delay (see get_response
|
|
|
|
* in hda_intel.c).
|
|
|
|
*/
|
|
|
|
codec->bus->needs_damn_long_delay = 1;
|
|
|
|
|
2008-12-17 12:48:29 +00:00
|
|
|
/* no jack detecion for ref-no-jd model */
|
|
|
|
if (spec->board_config == STAC_D965_REF_NO_JD)
|
|
|
|
spec->hp_detect = 0;
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
static int patch_stac9205(struct hda_codec *codec)
|
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
2007-07-31 13:56:24 +00:00
|
|
|
int err;
|
2006-07-31 10:49:34 +00:00
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
codec->spec = spec;
|
2007-07-06 16:17:04 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
|
2006-08-23 16:31:34 +00:00
|
|
|
spec->pin_nids = stac9205_pin_nids;
|
2006-11-24 16:07:44 +00:00
|
|
|
spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
|
|
|
|
stac9205_models,
|
|
|
|
stac9205_cfg_tbl);
|
2007-02-08 16:50:10 +00:00
|
|
|
again:
|
2009-02-20 13:33:36 +00:00
|
|
|
if (spec->board_config < 0)
|
2006-08-23 16:31:34 +00:00
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
|
2009-02-20 13:33:36 +00:00
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
2008-11-18 09:38:56 +00:00
|
|
|
stac9205_brd_tbl[spec->board_config]);
|
2006-07-31 10:49:34 +00:00
|
|
|
|
2008-07-18 16:20:52 +00:00
|
|
|
spec->digbeep_nid = 0x23;
|
2006-07-31 10:49:34 +00:00
|
|
|
spec->adc_nids = stac9205_adc_nids;
|
2007-09-03 13:31:02 +00:00
|
|
|
spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
|
2006-07-31 10:49:34 +00:00
|
|
|
spec->mux_nids = stac9205_mux_nids;
|
2007-03-12 11:36:16 +00:00
|
|
|
spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
|
2008-09-07 10:03:41 +00:00
|
|
|
spec->smux_nids = stac9205_smux_nids;
|
|
|
|
spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
|
2006-10-26 15:12:59 +00:00
|
|
|
spec->dmic_nids = stac9205_dmic_nids;
|
2007-10-16 12:27:04 +00:00
|
|
|
spec->num_dmics = STAC9205_NUM_DMICS;
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->dmux_nids = stac9205_dmux_nids;
|
2007-12-18 17:05:52 +00:00
|
|
|
spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
|
2008-01-10 15:55:06 +00:00
|
|
|
spec->num_pwrs = 0;
|
2006-07-31 10:49:34 +00:00
|
|
|
|
|
|
|
spec->init = stac9205_core_init;
|
|
|
|
spec->mixer = stac9205_mixer;
|
2009-03-02 13:26:25 +00:00
|
|
|
spec->aloopback_ctl = stac9205_loopback;
|
2006-07-31 10:49:34 +00:00
|
|
|
|
2007-12-13 16:47:21 +00:00
|
|
|
spec->aloopback_mask = 0x40;
|
|
|
|
spec->aloopback_shift = 0;
|
2009-01-22 16:40:18 +00:00
|
|
|
/* Turn on/off EAPD per HP plugging */
|
|
|
|
if (spec->board_config != STAC_9205_EAPD)
|
|
|
|
spec->eapd_switch = 1;
|
2006-07-31 10:49:34 +00:00
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
2007-07-17 09:52:24 +00:00
|
|
|
|
2007-08-13 13:50:29 +00:00
|
|
|
switch (spec->board_config){
|
|
|
|
case STAC_9205_DELL_M43:
|
2007-07-17 09:52:24 +00:00
|
|
|
/* Enable SPDIF in/out */
|
2009-02-20 13:33:36 +00:00
|
|
|
snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030);
|
|
|
|
snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030);
|
2007-07-17 09:52:24 +00:00
|
|
|
|
2008-01-29 14:28:44 +00:00
|
|
|
/* Enable unsol response for GPIO4/Dock HP connection */
|
2008-11-25 10:58:19 +00:00
|
|
|
err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2008-11-18 09:55:36 +00:00
|
|
|
snd_hda_codec_write_cache(codec, codec->afg, 0,
|
2008-01-29 14:28:44 +00:00
|
|
|
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
|
|
|
|
snd_hda_codec_write_cache(codec, codec->afg, 0,
|
2008-11-25 10:58:19 +00:00
|
|
|
AC_VERB_SET_UNSOLICITED_ENABLE,
|
|
|
|
AC_USRSP_EN | err);
|
2008-01-29 14:28:44 +00:00
|
|
|
|
|
|
|
spec->gpio_dir = 0x0b;
|
2008-04-14 11:32:54 +00:00
|
|
|
spec->eapd_mask = 0x01;
|
2008-01-29 14:28:44 +00:00
|
|
|
spec->gpio_mask = 0x1b;
|
|
|
|
spec->gpio_mute = 0x10;
|
2008-01-24 14:32:15 +00:00
|
|
|
/* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
|
2008-01-29 14:28:44 +00:00
|
|
|
* GPIO3 Low = DRM
|
2007-07-17 09:52:24 +00:00
|
|
|
*/
|
2008-01-29 14:28:44 +00:00
|
|
|
spec->gpio_data = 0x01;
|
2007-08-13 13:50:29 +00:00
|
|
|
break;
|
2008-09-26 14:06:40 +00:00
|
|
|
case STAC_9205_REF:
|
|
|
|
/* SPDIF-In enabled */
|
|
|
|
break;
|
2007-08-13 13:50:29 +00:00
|
|
|
default:
|
|
|
|
/* GPIO0 High = EAPD */
|
2008-04-14 11:32:54 +00:00
|
|
|
spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
|
2008-01-29 14:28:44 +00:00
|
|
|
spec->gpio_data = 0x01;
|
2007-08-13 13:50:29 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-12-18 12:17:28 +00:00
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
|
2007-02-08 16:50:10 +00:00
|
|
|
if (!err) {
|
|
|
|
if (spec->board_config < 0) {
|
|
|
|
printk(KERN_WARNING "hda_codec: No auto-config is "
|
|
|
|
"available, default to model=ref\n");
|
|
|
|
spec->board_config = STAC_9205_REF;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
2006-07-31 10:49:34 +00:00
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
|
|
|
|
2008-11-28 13:35:16 +00:00
|
|
|
codec->proc_widget_hook = stac9205_proc_hook;
|
|
|
|
|
2006-07-31 10:49:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-16 15:04:58 +00:00
|
|
|
/*
|
2006-08-22 15:15:47 +00:00
|
|
|
* STAC9872 hack
|
2006-03-16 15:04:58 +00:00
|
|
|
*/
|
|
|
|
|
2009-01-21 06:41:22 +00:00
|
|
|
static struct hda_verb stac9872_core_init[] = {
|
2007-07-05 11:10:51 +00:00
|
|
|
{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
|
2006-08-22 15:15:47 +00:00
|
|
|
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2009-01-20 16:19:01 +00:00
|
|
|
static struct snd_kcontrol_new stac9872_mixer[] = {
|
|
|
|
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
|
|
|
|
HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
|
|
|
|
{ } /* end */
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9872_pin_nids[] = {
|
|
|
|
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
|
|
0x11, 0x13, 0x14,
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9872_adc_nids[] = {
|
|
|
|
0x8 /*,0x6*/
|
|
|
|
};
|
|
|
|
|
|
|
|
static hda_nid_t stac9872_mux_nids[] = {
|
|
|
|
0x15
|
|
|
|
};
|
|
|
|
|
2009-03-12 17:17:58 +00:00
|
|
|
static unsigned int stac9872_vaio_pin_configs[9] = {
|
|
|
|
0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
|
|
|
|
0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
|
|
|
|
0x90a7013e
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *stac9872_models[STAC_9872_MODELS] = {
|
|
|
|
[STAC_9872_AUTO] = "auto",
|
|
|
|
[STAC_9872_VAIO] = "vaio",
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
|
|
|
|
[STAC_9872_VAIO] = stac9872_vaio_pin_configs,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct snd_pci_quirk stac9872_cfg_tbl[] = {
|
|
|
|
{} /* terminator */
|
|
|
|
};
|
|
|
|
|
2006-08-22 15:15:47 +00:00
|
|
|
static int patch_stac9872(struct hda_codec *codec)
|
2006-03-16 15:04:58 +00:00
|
|
|
{
|
|
|
|
struct sigmatel_spec *spec;
|
2009-01-21 06:41:22 +00:00
|
|
|
int err;
|
2006-03-16 15:04:58 +00:00
|
|
|
|
|
|
|
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
|
|
|
|
if (spec == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
codec->spec = spec;
|
2009-01-20 16:19:01 +00:00
|
|
|
|
|
|
|
spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
|
|
|
|
stac9872_models,
|
|
|
|
stac9872_cfg_tbl);
|
2009-03-12 17:17:58 +00:00
|
|
|
if (spec->board_config < 0)
|
|
|
|
snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9872, "
|
|
|
|
"using BIOS defaults\n");
|
|
|
|
else
|
|
|
|
stac92xx_set_config_regs(codec,
|
|
|
|
stac9872_brd_tbl[spec->board_config]);
|
2006-03-16 15:04:58 +00:00
|
|
|
|
2009-01-21 06:41:22 +00:00
|
|
|
spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
|
|
|
|
spec->pin_nids = stac9872_pin_nids;
|
|
|
|
spec->multiout.dac_nids = spec->dac_nids;
|
|
|
|
spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
|
|
|
|
spec->adc_nids = stac9872_adc_nids;
|
|
|
|
spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
|
|
|
|
spec->mux_nids = stac9872_mux_nids;
|
|
|
|
spec->mixer = stac9872_mixer;
|
|
|
|
spec->init = stac9872_core_init;
|
|
|
|
|
|
|
|
err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
|
|
|
|
if (err < 0) {
|
|
|
|
stac92xx_free(codec);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
spec->input_mux = &spec->private_imux;
|
|
|
|
codec->patch_ops = stac92xx_patch_ops;
|
2006-03-16 15:04:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-13 12:45:30 +00:00
|
|
|
/*
|
|
|
|
* patch entries
|
|
|
|
*/
|
2008-11-27 14:47:11 +00:00
|
|
|
static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
|
2005-04-13 12:45:30 +00:00
|
|
|
{ .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
|
|
|
|
{ .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
|
|
|
|
{ .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
|
|
|
|
{ .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
|
|
|
|
{ .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
|
|
|
|
{ .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
|
|
|
|
{ .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
|
2006-07-06 16:49:10 +00:00
|
|
|
{ .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
|
2006-01-23 14:27:49 +00:00
|
|
|
{ .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
|
2007-01-08 10:04:17 +00:00
|
|
|
{ .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
|
|
|
|
{ .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
|
|
|
|
{ .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
|
|
|
|
{ .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
|
|
|
|
{ .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
|
|
|
|
{ .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
|
2008-05-02 10:28:02 +00:00
|
|
|
{ .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
|
|
|
|
{ .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
|
2006-08-22 15:15:47 +00:00
|
|
|
/* The following does not take into account .id=0x83847661 when subsys =
|
|
|
|
* 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
|
|
|
|
* currently not fully supported.
|
|
|
|
*/
|
|
|
|
{ .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
|
|
|
|
{ .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
|
|
|
|
{ .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
|
2006-07-31 10:49:34 +00:00
|
|
|
{ .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
|
|
|
|
{ .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
|
2008-06-13 16:04:33 +00:00
|
|
|
{ .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
|
2008-07-27 08:30:30 +00:00
|
|
|
{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
|
|
|
|
{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
|
2009-04-01 18:49:48 +00:00
|
|
|
{ .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
|
2008-06-13 16:04:33 +00:00
|
|
|
{ .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
|
2007-12-14 11:08:04 +00:00
|
|
|
{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
|
|
|
|
{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
|
2007-12-13 16:47:21 +00:00
|
|
|
{ .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
|
2007-12-14 11:08:04 +00:00
|
|
|
{ .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
|
|
|
|
{ .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
|
2005-04-13 12:45:30 +00:00
|
|
|
{} /* terminator */
|
|
|
|
};
|
2008-11-27 14:47:11 +00:00
|
|
|
|
|
|
|
MODULE_ALIAS("snd-hda-codec-id:8384*");
|
|
|
|
MODULE_ALIAS("snd-hda-codec-id:111d*");
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
|
|
|
|
|
|
|
|
static struct hda_codec_preset_list sigmatel_list = {
|
|
|
|
.preset = snd_hda_preset_sigmatel,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init patch_sigmatel_init(void)
|
|
|
|
{
|
|
|
|
return snd_hda_add_codec_preset(&sigmatel_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit patch_sigmatel_exit(void)
|
|
|
|
{
|
|
|
|
snd_hda_delete_codec_preset(&sigmatel_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(patch_sigmatel_init)
|
|
|
|
module_exit(patch_sigmatel_exit)
|