Commit 506ecbca authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda' into for-linus

parents aa5c14d5 0e7adbe2
...@@ -57,9 +57,11 @@ dead. However, this detection isn't perfect on some devices. In such ...@@ -57,9 +57,11 @@ dead. However, this detection isn't perfect on some devices. In such
a case, you can change the default method via `position_fix` option. a case, you can change the default method via `position_fix` option.
`position_fix=1` means to use LPIB method explicitly. `position_fix=1` means to use LPIB method explicitly.
`position_fix=2` means to use the position-buffer. 0 is the default `position_fix=2` means to use the position-buffer.
value, the automatic check and fallback to LPIB as described in the `position_fix=3` means to use a combination of both methods, needed
above. If you get a problem of repeated sounds, this option might for some VIA and ATI controllers. 0 is the default value for all other
controllers, the automatic check and fallback to LPIB as described in
the above. If you get a problem of repeated sounds, this option might
help. help.
In addition to that, every controller is known to be broken regarding In addition to that, every controller is known to be broken regarding
......
...@@ -38,9 +38,11 @@ ...@@ -38,9 +38,11 @@
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */ #define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */ #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
#define TLV_DB_SCALE_MASK 0xffff
#define TLV_DB_SCALE_MUTE 0x10000
#define TLV_DB_SCALE_ITEM(min, step, mute) \ #define TLV_DB_SCALE_ITEM(min, step, mute) \
SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \ SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
(min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0) (min), ((step) & TLV_DB_SCALE_MASK) | ((mute) ? TLV_DB_SCALE_MUTE : 0)
#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \ #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) } unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
......
...@@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA ...@@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
snd-hda-codec-via. snd-hda-codec-via.
This module is automatically loaded at probing. This module is automatically loaded at probing.
config SND_HDA_CODEC_ATIHDMI config SND_HDA_CODEC_HDMI
bool "Build ATI HDMI HD-audio codec support" bool "Build HDMI/DisplayPort HD-audio codec support"
default y
help
Say Y here to include ATI HDMI HD-audio codec support in
snd-hda-intel driver, such as ATI RS600 HDMI.
When the HD-audio driver is built as a module, the codec
support code is also built as another module,
snd-hda-codec-atihdmi.
This module is automatically loaded at probing.
config SND_HDA_CODEC_NVHDMI
bool "Build NVIDIA HDMI HD-audio codec support"
default y
help
Say Y here to include NVIDIA HDMI HD-audio codec support in
snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
When the HD-audio driver is built as a module, the codec
support code is also built as another module,
snd-hda-codec-nvhdmi.
This module is automatically loaded at probing.
config SND_HDA_CODEC_INTELHDMI
bool "Build INTEL HDMI HD-audio codec support"
select SND_DYNAMIC_MINORS select SND_DYNAMIC_MINORS
default y default y
help help
Say Y here to include INTEL HDMI HD-audio codec support in Say Y here to include HDMI and DisplayPort HD-audio codec
snd-hda-intel driver, such as Eaglelake integrated HDMI. support in snd-hda-intel driver. This includes all AMD/ATI,
Intel and Nvidia HDMI/DisplayPort codecs.
When the HD-audio driver is built as a module, the codec When the HD-audio driver is built as a module, the codec
support code is also built as another module, support code is also built as another module,
snd-hda-codec-intelhdmi. snd-hda-codec-hdmi.
This module is automatically loaded at probing. This module is automatically loaded at probing.
config SND_HDA_ELD
def_bool y
depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
config SND_HDA_CODEC_CIRRUS config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support" bool "Build Cirrus Logic codec support"
depends on SND_HDA_INTEL depends on SND_HDA_INTEL
......
...@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o ...@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
snd-hda-codec-y := hda_codec.o snd-hda-codec-y := hda_codec.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
...@@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs := patch_cmedia.o ...@@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs := patch_cmedia.o
snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-analog-objs := patch_analog.o
snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-idt-objs := patch_sigmatel.o
snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-si3054-objs := patch_si3054.o
snd-hda-codec-atihdmi-objs := patch_atihdmi.o
snd-hda-codec-cirrus-objs := patch_cirrus.o snd-hda-codec-cirrus-objs := patch_cirrus.o
snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-ca0110-objs := patch_ca0110.o
snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-conexant-objs := patch_conexant.o
snd-hda-codec-via-objs := patch_via.o snd-hda-codec-via-objs := patch_via.o
snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o
# common driver # common driver
obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
...@@ -39,9 +36,6 @@ endif ...@@ -39,9 +36,6 @@ endif
ifdef CONFIG_SND_HDA_CODEC_SI3054 ifdef CONFIG_SND_HDA_CODEC_SI3054
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
endif endif
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
endif
ifdef CONFIG_SND_HDA_CODEC_CIRRUS ifdef CONFIG_SND_HDA_CODEC_CIRRUS
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
endif endif
...@@ -54,11 +48,8 @@ endif ...@@ -54,11 +48,8 @@ endif
ifdef CONFIG_SND_HDA_CODEC_VIA ifdef CONFIG_SND_HDA_CODEC_VIA
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
endif endif
ifdef CONFIG_SND_HDA_CODEC_NVHDMI ifdef CONFIG_SND_HDA_CODEC_HDMI
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
endif
ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
endif endif
# this must be the last entry after codec drivers; # this must be the last entry after codec drivers;
......
This diff is collapsed.
...@@ -850,6 +850,7 @@ struct hda_codec { ...@@ -850,6 +850,7 @@ struct hda_codec {
unsigned int pin_amp_workaround:1; /* pin out-amp takes index unsigned int pin_amp_workaround:1; /* pin out-amp takes index
* (e.g. Conexant codecs) * (e.g. Conexant codecs)
*/ */
unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
unsigned int pins_shutup:1; /* pins are shut up */ unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
...@@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus); ...@@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
int snd_hda_resume(struct hda_bus *bus); int snd_hda_resume(struct hda_bus *bus);
#endif #endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
static inline
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
if (codec->patch_ops.check_power_status)
return codec->patch_ops.check_power_status(codec, nid);
return 0;
}
#else
#define hda_call_check_power_status(codec, nid) 0
#endif
/* /*
* get widget information * get widget information
*/ */
......
...@@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) ...@@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
AC_DIPSIZE_ELD_BUF); AC_DIPSIZE_ELD_BUF);
} }
EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
int snd_hdmi_get_eld(struct hdmi_eld *eld, int snd_hdmi_get_eld(struct hdmi_eld *eld,
struct hda_codec *codec, hda_nid_t nid) struct hda_codec *codec, hda_nid_t nid)
...@@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, ...@@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
kfree(buf); kfree(buf);
return ret; return ret;
} }
EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
static void hdmi_show_short_audio_desc(struct cea_sad *a) static void hdmi_show_short_audio_desc(struct cea_sad *a)
{ {
...@@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) ...@@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
} }
buf[j] = '\0'; /* necessary when j == 0 */ buf[j] = '\0'; /* necessary when j == 0 */
} }
EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
void snd_hdmi_show_eld(struct hdmi_eld *e) void snd_hdmi_show_eld(struct hdmi_eld *e)
{ {
...@@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) ...@@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
for (i = 0; i < e->sad_count; i++) for (i = 0; i < e->sad_count; i++)
hdmi_show_short_audio_desc(e->sad + i); hdmi_show_short_audio_desc(e->sad + i);
} }
EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, ...@@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
return 0; return 0;
} }
EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
{ {
...@@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) ...@@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
eld->proc_entry = NULL; eld->proc_entry = NULL;
} }
} }
EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
...@@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, ...@@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
} }
EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
...@@ -61,7 +61,6 @@ struct hda_gspec { ...@@ -61,7 +61,6 @@ struct hda_gspec {
struct hda_gnode *cap_vol_node; /* Node for capture volume */ struct hda_gnode *cap_vol_node; /* Node for capture volume */
unsigned int cur_cap_src; /* current capture source */ unsigned int cur_cap_src; /* current capture source */
struct hda_input_mux input_mux; struct hda_input_mux input_mux;
char cap_labels[HDA_MAX_NUM_INPUTS][16];
unsigned int def_amp_in_caps; unsigned int def_amp_in_caps;
unsigned int def_amp_out_caps; unsigned int def_amp_out_caps;
...@@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) ...@@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
* returns 0 if not found, 1 if found, or a negative error code. * returns 0 if not found, 1 if found, or a negative error code.
*/ */
static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
struct hda_gnode *node) struct hda_gnode *node, int idx)
{ {
int i, err; int i, err;
unsigned int pinctl; unsigned int pinctl;
char *label;
const char *type; const char *type;
if (node->checked) if (node->checked)
...@@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, ...@@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
child = hda_get_node(spec, node->conn_list[i]); child = hda_get_node(spec, node->conn_list[i]);
if (! child) if (! child)
continue; continue;
err = parse_adc_sub_nodes(codec, spec, child); err = parse_adc_sub_nodes(codec, spec, child, idx);
if (err < 0) if (err < 0)
return err; return err;
if (err > 0) { if (err > 0) {
...@@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, ...@@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
return 0; return 0;
type = "Input"; type = "Input";
} }
label = spec->cap_labels[spec->input_mux.num_items]; snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
strcpy(label, type);
spec->input_mux.items[spec->input_mux.num_items].label = label;
/* unmute the PIN external input */ /* unmute the PIN external input */
unmute_input(codec, node, 0); /* index = 0? */ unmute_input(codec, node, 0); /* index = 0? */
...@@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, ...@@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
return 1; /* found */ return 1; /* found */
} }
/* add a capture source element */
static void add_cap_src(struct hda_gspec *spec, int idx)
{
struct hda_input_mux_item *csrc;
char *buf;
int num, ocap;
num = spec->input_mux.num_items;
csrc = &spec->input_mux.items[num];
buf = spec->cap_labels[num];
for (ocap = 0; ocap < num; ocap++) {
if (! strcmp(buf, spec->cap_labels[ocap])) {
/* same label already exists,
* put the index number to be unique
*/
sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
break;
}
}
csrc->index = idx;
spec->input_mux.num_items++;
}
/* /*
* parse input * parse input
*/ */
...@@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) ...@@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
for (i = 0; i < adc_node->nconns; i++) { for (i = 0; i < adc_node->nconns; i++) {
node = hda_get_node(spec, adc_node->conn_list[i]); node = hda_get_node(spec, adc_node->conn_list[i]);
if (node && node->type == AC_WID_PIN) { if (node && node->type == AC_WID_PIN) {
err = parse_adc_sub_nodes(codec, spec, node); err = parse_adc_sub_nodes(codec, spec, node, i);
if (err < 0) if (err < 0)
return err; return err;
else if (err > 0)
add_cap_src(spec, i);
} }
} }
/* ... then check the rests, more complicated connections */ /* ... then check the rests, more complicated connections */
for (i = 0; i < adc_node->nconns; i++) { for (i = 0; i < adc_node->nconns; i++) {
node = hda_get_node(spec, adc_node->conn_list[i]); node = hda_get_node(spec, adc_node->conn_list[i]);
if (node && node->type != AC_WID_PIN) { if (node && node->type != AC_WID_PIN) {
err = parse_adc_sub_nodes(codec, spec, node); err = parse_adc_sub_nodes(codec, spec, node, i);
if (err < 0) if (err < 0)
return err; return err;
else if (err > 0)
add_cap_src(spec, i);
} }
} }
......
...@@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); ...@@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
module_param_array(model, charp, NULL, 0444); module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model."); MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444); module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "Fix DMA pointer " MODULE_PARM_DESC(position_fix, "DMA pointer read method."
"(0 = auto, 1 = none, 2 = POSBUF)."); "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
module_param_array(bdl_pos_adj, int, NULL, 0644); module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444); module_param_array(probe_mask, int, NULL, 0444);
...@@ -305,6 +305,7 @@ enum { ...@@ -305,6 +305,7 @@ enum {
POS_FIX_AUTO, POS_FIX_AUTO,
POS_FIX_LPIB, POS_FIX_LPIB,
POS_FIX_POSBUF, POS_FIX_POSBUF,
POS_FIX_VIACOMBO,
}; };
/* Defines for ATI HD Audio support in SB450 south bridge */ /* Defines for ATI HD Audio support in SB450 south bridge */
...@@ -433,7 +434,6 @@ struct azx { ...@@ -433,7 +434,6 @@ struct azx {
unsigned int polling_mode :1; unsigned int polling_mode :1;
unsigned int msi :1; unsigned int msi :1;
unsigned int irq_pending_warned :1; unsigned int irq_pending_warned :1;
unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
unsigned int probing :1; /* codec probing phase */ unsigned int probing :1; /* codec probing phase */
/* for debugging */ /* for debugging */
...@@ -458,6 +458,7 @@ enum { ...@@ -458,6 +458,7 @@ enum {
AZX_DRIVER_ULI, AZX_DRIVER_ULI,
AZX_DRIVER_NVIDIA, AZX_DRIVER_NVIDIA,
AZX_DRIVER_TERA, AZX_DRIVER_TERA,
AZX_DRIVER_CTX,
AZX_DRIVER_GENERIC, AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */ AZX_NUM_DRIVERS, /* keep this as last entry */
}; };
...@@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = { ...@@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_ULI] = "HDA ULI M5461",
[AZX_DRIVER_NVIDIA] = "HDA NVidia", [AZX_DRIVER_NVIDIA] = "HDA NVidia",
[AZX_DRIVER_TERA] = "HDA Teradici", [AZX_DRIVER_TERA] = "HDA Teradici",
[AZX_DRIVER_CTX] = "HDA Creative",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic", [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
}; };
...@@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip) ...@@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
/* reset the rirb hw write pointer */ /* reset the rirb hw write pointer */
azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
/* set N=1, get RIRB response interrupt for new entry */ /* set N=1, get RIRB response interrupt for new entry */
azx_writew(chip, RINTCNT, 1); if (chip->driver_type == AZX_DRIVER_CTX)
azx_writew(chip, RINTCNT, 0xc0);
else
azx_writew(chip, RINTCNT, 1);
/* enable rirb dma and response irq */ /* enable rirb dma and response irq */
azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
spin_unlock_irq(&chip->reg_lock); spin_unlock_irq(&chip->reg_lock);
...@@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) ...@@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
/* clear rirb int */ /* clear rirb int */
status = azx_readb(chip, RIRBSTS); status = azx_readb(chip, RIRBSTS);
if (status & RIRB_INT_MASK) { if (status & RIRB_INT_MASK) {
if (status & RIRB_INT_RESPONSE) if (status & RIRB_INT_RESPONSE) {
if (chip->driver_type == AZX_DRIVER_CTX)
udelay(80);
azx_update_rirb(chip); azx_update_rirb(chip);
}
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
} }
...@@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) ...@@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
/* enable the position buffer */ /* enable the position buffer */
if (chip->position_fix[0] == POS_FIX_POSBUF || if (chip->position_fix[0] != POS_FIX_LPIB ||
chip->position_fix[0] == POS_FIX_AUTO || chip->position_fix[1] != POS_FIX_LPIB) {
chip->position_fix[1] == POS_FIX_POSBUF ||
chip->position_fix[1] == POS_FIX_AUTO ||
chip->via_dmapos_patch) {
if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
azx_writel(chip, DPLBASE, azx_writel(chip, DPLBASE,
(u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
...@@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) ...@@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
struct azx_dev *azx_dev = get_azx_dev(substream); struct azx_dev *azx_dev = get_azx_dev(substream);
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int bufsize, period_bytes, format_val; unsigned int bufsize, period_bytes, format_val, stream_tag;
int err; int err;
azx_stream_reset(chip, azx_dev); azx_stream_reset(chip, azx_dev);
...@@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) ...@@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
else else
azx_dev->fifo_size = 0; azx_dev->fifo_size = 0;
return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag, stream_tag = azx_dev->stream_tag;
/* CA-IBG chips need the playback stream starting from 1 */
if (chip->driver_type == AZX_DRIVER_CTX &&
stream_tag > chip->capture_streams)
stream_tag -= chip->capture_streams;
return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
azx_dev->format_val, substream); azx_dev->format_val, substream);
} }
...@@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip, ...@@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
struct azx_dev *azx_dev) struct azx_dev *azx_dev)
{ {
unsigned int pos; unsigned int pos;
int stream = azx_dev->substream->stream;
if (chip->via_dmapos_patch) switch (chip->position_fix[stream]) {
case POS_FIX_LPIB:
/* read LPIB */
pos = azx_sd_readl(azx_dev, SD_LPIB);
break;
case POS_FIX_VIACOMBO:
pos = azx_via_get_position(chip, azx_dev); pos = azx_via_get_position(chip, azx_dev);
else { break;
int stream = azx_dev->substream->stream; default:
if (chip->position_fix[stream] == POS_FIX_POSBUF || /* use the position buffer */
chip->position_fix[stream] == POS_FIX_AUTO) { pos = le32_to_cpu(*azx_dev->posbuf);
/* use the position buffer */
pos = le32_to_cpu(*azx_dev->posbuf);
} else {
/* read LPIB */
pos = azx_sd_readl(azx_dev, SD_LPIB);
}
} }
if (pos >= azx_dev->bufsize) if (pos >= azx_dev->bufsize)
pos = 0; pos = 0;
return pos; return pos;
...@@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix) ...@@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
switch (fix) { switch (fix) {
case POS_FIX_LPIB: case POS_FIX_LPIB:
case POS_FIX_POSBUF: case POS_FIX_POSBUF:
case POS_FIX_VIACOMBO:
return fix; return fix;
} }
/* Check VIA/ATI HD Audio Controller exist */
switch (chip->driver_type) {
case AZX_DRIVER_VIA:
case AZX_DRIVER_ATI:
chip->via_dmapos_patch = 1;
/* Use link position directly, avoid any transfer problem. */
return POS_FIX_LPIB;
}
chip->via_dmapos_patch = 0;
q = snd_pci_quirk_lookup(chip->pci, position_fix_list); q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
if (q) { if (q) {
printk(KERN_INFO printk(KERN_INFO
...@@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix) ...@@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
q->value, q->subvendor, q->subdevice); q->value, q->subvendor, q->subdevice);
return q->value; return q->value;
} }
/* Check VIA/ATI HD Audio Controller exist */
switch (chip->driver_type) {
case AZX_DRIVER_VIA:
case AZX_DRIVER_ATI:
/* Use link position directly, avoid any transfer problem. */
return POS_FIX_VIACOMBO;
}
return POS_FIX_AUTO; return POS_FIX_AUTO;
} }
...@@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci) ...@@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
/* PCI IDs */ /* PCI IDs */
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* ICH 6..10 */
{ PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
/* PCH */
{ PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
/* CPT */ /* CPT */
{ PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
/* PBG */ /* PBG */
{ PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH }, { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
/* SCH */ /* SCH */
{ PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
/* Generic Intel */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_ICH },
/* ATI SB 450/600 */ /* ATI SB 450/600 */
{ PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI }, { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
{ PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI }, { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
...@@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { ...@@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff, .class_mask = 0xffffff,
.driver_data = AZX_DRIVER_GENERIC }, .driver_data = AZX_DRIVER_CTX },
#else #else
/* this entry seems still valid -- i.e. without emu20kx chip */ /* this entry seems still valid -- i.e. without emu20kx chip */
{ PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
#endif #endif
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
......
...@@ -38,10 +38,11 @@ ...@@ -38,10 +38,11 @@
*/ */
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \ #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23)) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
#define HDA_AMP_VAL_MIN_MUTE (1<<29)
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0) HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
/* mono volume with index (index=0,1,...) (channel=1,2) */ /* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
.subdevice = HDA_SUBDEV_AMP_FLAG, \ .subdevice = HDA_SUBDEV_AMP_FLAG, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
...@@ -51,16 +52,20 @@ ...@@ -51,16 +52,20 @@
.get = snd_hda_mixer_amp_volume_get, \ .get = snd_hda_mixer_amp_volume_get, \
.put = snd_hda_mixer_amp_volume_put, \ .put = snd_hda_mixer_amp_volume_put, \
.tlv = { .c = snd_hda_mixer_amp_tlv }, \ .tlv = { .c = snd_hda_mixer_amp_tlv }, \
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
/* stereo volume with index */ /* stereo volume with index */
#define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
/* mono volume */ /* mono volume */
#define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \ #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction) HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
/* stereo volume */ /* stereo volume */
#define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \ #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction) HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
/* stereo volume with min=mute */
#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
HDA_AMP_VAL_MIN_MUTE)
/* mono mute switch with index (index=0,1,...) (channel=1,2) */ /* mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
...@@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); ...@@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
*/ */
#define HDA_MAX_NUM_INPUTS 16 #define HDA_MAX_NUM_INPUTS 16
struct hda_input_mux_item { struct hda_input_mux_item {
const char *label; char label[32];
unsigned int index; unsigned int index;
}; };
struct hda_input_mux { struct hda_input_mux {
...@@ -366,9 +371,7 @@ struct hda_bus_unsolicited { ...@@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
enum { enum {
AUTO_PIN_MIC, AUTO_PIN_MIC,
AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE_IN,
AUTO_PIN_LINE,
AUTO_PIN_FRONT_LINE,
AUTO_PIN_CD, AUTO_PIN_CD,
AUTO_PIN_AUX, AUTO_PIN_AUX,
AUTO_PIN_LAST AUTO_PIN_LAST
...@@ -380,9 +383,33 @@ enum { ...@@ -380,9 +383,33 @@ enum {
AUTO_PIN_HP_OUT AUTO_PIN_HP_OUT
}; };
extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
#define AUTO_CFG_MAX_OUTS 5 #define AUTO_CFG_MAX_OUTS 5
#define AUTO_CFG_MAX_INS 8
struct auto_pin_cfg_item {
hda_nid_t pin;
int type;
};
struct auto_pin_cfg;
const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
int check_location);
const char *hda_get_autocfg_input_label(struct hda_codec *codec,
const struct auto_pin_cfg *cfg,
int input);
int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
int index, int *type_index_ret);
enum {
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
};
int snd_hda_get_input_pin_attr(unsigned int def_conf);
struct auto_pin_cfg { struct auto_pin_cfg {
int line_outs; int line_outs;
...@@ -393,7 +420,8 @@ struct auto_pin_cfg { ...@@ -393,7 +420,8 @@ struct auto_pin_cfg {
int hp_outs; int hp_outs;
int line_out_type; /* AUTO_PIN_XXX_OUT */ int line_out_type; /* AUTO_PIN_XXX_OUT */
hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
hda_nid_t input_pins[AUTO_PIN_LAST]; int num_inputs;
struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
int dig_outs; int dig_outs;
hda_nid_t dig_out_pins[2]; hda_nid_t dig_out_pins[2];
hda_nid_t dig_in_pin; hda_nid_t dig_in_pin;
...@@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, ...@@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
/* /*
* CEA Short Audio Descriptor data * CEA Short Audio Descriptor data
......
...@@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec) ...@@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
spec->multiout.no_share_stream = 1; spec->multiout.no_share_stream = 1;
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
...@@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec) ...@@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops; codec->patch_ops = ad198x_patch_ops;
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
...@@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec) ...@@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
} }
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
...@@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, ...@@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
/* create input playback/capture controls for the given pin */ /* create input playback/capture controls for the given pin */
static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
const char *ctlname, int boost) const char *ctlname, int ctlidx, int boost)
{ {
char name[32]; char name[32];
int err, idx; int err, idx;
...@@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, ...@@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
} }
/* create playback/capture controls for input pins */ /* create playback/capture controls for input pins */
static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg) const struct auto_pin_cfg *cfg)
{ {
struct ad198x_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux; struct hda_input_mux *imux = &spec->private_imux;
int i, err; int i, err, type, type_idx;
for (i = 0; i < AUTO_PIN_LAST; i++) { for (i = 0; i < cfg->num_inputs; i++) {
err = new_analog_input(spec, cfg->input_pins[i], const char *label;
auto_pin_cfg_labels[i], type = cfg->inputs[i].type;
i <= AUTO_PIN_FRONT_MIC); label = hda_get_autocfg_input_label(codec, cfg, i);
snd_hda_add_imux_item(imux, label,
ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
&type_idx);
err = new_analog_input(spec, cfg->inputs[i].pin,
label, type_idx,
type == AUTO_PIN_MIC);
if (err < 0) if (err < 0)
return err; return err;
imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
imux->num_items++;
} }
imux->items[imux->num_items].label = "Mix"; snd_hda_add_imux_item(imux, "Mix", 9, NULL);
imux->items[imux->num_items].index = 9;
imux->num_items++;
if ((err = add_control(spec, AD_CTL_WIDGET_VOL, if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
"Analog Mix Playback Volume", "Analog Mix Playback Volume",
...@@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) ...@@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
static void ad1988_auto_init_analog_input(struct hda_codec *codec) static void ad1988_auto_init_analog_input(struct hda_codec *codec)
{ {
struct ad198x_spec *spec = codec->spec; struct ad198x_spec *spec = codec->spec;
const struct auto_pin_cfg *cfg = &spec->autocfg;
int i, idx; int i, idx;
for (i = 0; i < AUTO_PIN_LAST; i++) { for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t nid = spec->autocfg.input_pins[i]; hda_nid_t nid = cfg->inputs[i].pin;
if (! nid)
continue;
switch (nid) { switch (nid) {
case 0x15: /* port-C */ case 0x15: /* port-C */
snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
...@@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) ...@@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
break; break;
} }
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
if (nid != AD1988_PIN_CD_NID) if (nid != AD1988_PIN_CD_NID)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_MUTE); AMP_OUT_MUTE);
...@@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) ...@@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
"Speaker")) < 0 || "Speaker")) < 0 ||
(err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
"Headphone")) < 0 || "Headphone")) < 0 ||
(err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
return err; return err;
spec->multiout.max_channels = spec->multiout.num_dacs * 2; spec->multiout.max_channels = spec->multiout.num_dacs * 2;
...@@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec) ...@@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
spec->vmaster_nid = 0x04; spec->vmaster_nid = 0x04;
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
...@@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec) ...@@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
codec->patch_ops = ad198x_patch_ops; codec->patch_ops = ad198x_patch_ops;
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
...@@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec) ...@@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
} }
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
...@@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec) ...@@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
} }
codec->no_trigger_sense = 1; codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
return 0; return 0;
} }
......
/*
* Universal Interface for Intel High Definition Audio Codec
*
* HD audio interface patch for ATI HDMI codecs
*
* Copyright (c) 2006 ATI Technologies Inc.
*
*
* 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 <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
struct atihdmi_spec {
struct hda_multi_out multiout;
struct hda_pcm pcm_rec;
};
#define CVT_NID 0x02 /* audio converter */
#define PIN_NID 0x03 /* HDMI output pin */
static struct hda_verb atihdmi_basic_init[] = {
/* enable digital output on pin widget */
{ 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
{} /* terminator */
};
/*
* Controls
*/
static int atihdmi_build_controls(struct hda_codec *codec)
{
struct atihdmi_spec *spec = codec->spec;
int err;
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
if (err < 0)
return err;
return 0;
}
static int atihdmi_init(struct hda_codec *codec)
{
snd_hda_sequence_write(codec, atihdmi_basic_init);
/* SI codec requires to unmute the pin */
if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, PIN_NID, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
return 0;
}
/*
* Digital out
*/
static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct atihdmi_spec *spec = codec->spec;
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
}
static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct atihdmi_spec *spec = codec->spec;
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
}
static int atihdmi_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 atihdmi_spec *spec = codec->spec;
int chans = substream->runtime->channels;
int i, err;
err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
format, substream);
if (err < 0)
return err;
snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
chans - 1);
/* FIXME: XXX */
for (i = 0; i < chans; i++) {
snd_hda_codec_write(codec, CVT_NID, 0,
AC_VERB_SET_HDMI_CHAN_SLOT,
(i << 4) | i);
}
return 0;
}
static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.nid = CVT_NID, /* NID to query formats and rates and setup streams */
.ops = {
.open = atihdmi_dig_playback_pcm_open,
.close = atihdmi_dig_playback_pcm_close,
.prepare = atihdmi_dig_playback_pcm_prepare
},
};
static int atihdmi_build_pcms(struct hda_codec *codec)
{
struct atihdmi_spec *spec = codec->spec;
struct hda_pcm *info = &spec->pcm_rec;
unsigned int chans;
codec->num_pcms = 1;
codec->pcm_info = info;
info->name = "ATI HDMI";
info->pcm_type = HDA_PCM_TYPE_HDMI;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
/* FIXME: we must check ELD and change the PCM parameters dynamically
*/
chans = get_wcaps(codec, CVT_NID);
chans = get_wcaps_channels(chans);
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
return 0;
}
static void atihdmi_free(struct hda_codec *codec)
{
kfree(codec->spec);
}
static struct hda_codec_ops atihdmi_patch_ops = {
.build_controls = atihdmi_build_controls,
.build_pcms = atihdmi_build_pcms,
.init = atihdmi_init,
.free = atihdmi_free,
};
static int patch_atihdmi(struct hda_codec *codec)
{
struct atihdmi_spec *spec;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
spec->multiout.num_dacs = 0; /* no analog */
spec->multiout.max_channels = 2;
/* NID for copying analog to digital,
* seems to be unused in pure-digital
* case.
*/
spec->multiout.dig_out_nid = CVT_NID;
codec->patch_ops = atihdmi_patch_ops;
return 0;
}
/*
* patch entries
*/
static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi },
{} /* terminator */
};
MODULE_ALIAS("snd-hda-codec-id:1002793c");
MODULE_ALIAS("snd-hda-codec-id:10027919");
MODULE_ALIAS("snd-hda-codec-id:1002791a");
MODULE_ALIAS("snd-hda-codec-id:1002aa01");
MODULE_ALIAS("snd-hda-codec-id:10951390");
MODULE_ALIAS("snd-hda-codec-id:17e80047");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
static struct hda_codec_preset_list atihdmi_list = {
.preset = snd_hda_preset_atihdmi,
.owner = THIS_MODULE,
};
static int __init patch_atihdmi_init(void)
{
return snd_hda_add_codec_preset(&atihdmi_list);
}
static void __exit patch_atihdmi_exit(void)
{
snd_hda_delete_codec_preset(&atihdmi_list);
}
module_init(patch_atihdmi_init)
module_exit(patch_atihdmi_exit)
...@@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec) ...@@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
spec->dig_in = nid; spec->dig_in = nid;
continue; continue;
} }
for (j = 0; j < AUTO_PIN_LAST; j++) for (j = 0; j < cfg->num_inputs; j++)
if (cfg->input_pins[j] == pin) if (cfg->inputs[j].pin == pin)
break; break;
if (j >= AUTO_PIN_LAST) if (j >= cfg->num_inputs)
continue; continue;
spec->input_pins[n] = pin; spec->input_pins[n] = pin;
spec->input_labels[n] = auto_pin_cfg_labels[j]; spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
spec->adcs[n] = nid; spec->adcs[n] = nid;
n++; n++;
} }
...@@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec) ...@@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
if (cfg->dig_outs && if (cfg->dig_outs &&
snd_hda_get_connections(codec, cfg->dig_out_pins[0], snd_hda_get_connections(codec, cfg->dig_out_pins[0],
&spec->dig_out, 1) == 1) &spec->dig_out, 1) == 1)
spec->multiout.dig_out_nid = cfg->dig_out_pins[0]; spec->multiout.dig_out_nid = spec->dig_out;
} }
static int ca0110_parse_auto_config(struct hda_codec *codec) static int ca0110_parse_auto_config(struct hda_codec *codec)
......
...@@ -65,6 +65,7 @@ struct cs_spec { ...@@ -65,6 +65,7 @@ struct cs_spec {
/* available models */ /* available models */
enum { enum {
CS420X_MBP53,
CS420X_MBP55, CS420X_MBP55,
CS420X_IMAC27, CS420X_IMAC27,
CS420X_AUTO, CS420X_AUTO,
...@@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) ...@@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
{ {
struct cs_spec *spec = codec->spec; struct cs_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg; struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t pin = cfg->input_pins[idx]; hda_nid_t pin = cfg->inputs[idx].pin;
unsigned int val = snd_hda_query_pin_caps(codec, pin); unsigned int val = snd_hda_query_pin_caps(codec, pin);
if (!(val & AC_PINCAP_PRES_DETECT)) if (!(val & AC_PINCAP_PRES_DETECT))
return 0; return 0;
val = snd_hda_codec_get_pincfg(codec, pin); val = snd_hda_codec_get_pincfg(codec, pin);
return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
} }
static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
...@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec) ...@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
struct auto_pin_cfg *cfg = &spec->autocfg; struct auto_pin_cfg *cfg = &spec->autocfg;
int i; int i;
for (i = 0; i < AUTO_PIN_LAST; i++) { for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t pin = cfg->input_pins[i]; hda_nid_t pin = cfg->inputs[i].pin;
if (!pin)
continue;
spec->input_idx[spec->num_inputs] = i; spec->input_idx[spec->num_inputs] = i;
spec->capsrc_idx[i] = spec->num_inputs++; spec->capsrc_idx[i] = spec->num_inputs++;
spec->cur_input = i; spec->cur_input = i;
...@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec) ...@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
/* check whether the automatic mic switch is available */ /* check whether the automatic mic switch is available */
if (spec->num_inputs == 2 && if (spec->num_inputs == 2 &&
spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { cfg->inputs[0].type == AUTO_PIN_MIC &&
if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { cfg->inputs[1].type == AUTO_PIN_MIC) {
if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { if (is_ext_mic(codec, cfg->inputs[0].pin)) {
if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
spec->mic_detect = 1; spec->mic_detect = 1;
spec->automic_idx = AUTO_PIN_FRONT_MIC; spec->automic_idx = 0;
} }
} else { } else {
if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { if (is_ext_mic(codec, cfg->inputs[1].pin)) {
spec->mic_detect = 1; spec->mic_detect = 1;
spec->automic_idx = AUTO_PIN_MIC; spec->automic_idx = 1;
} }
} }
} }
...@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, ...@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
{ {
struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct cs_spec *spec = codec->spec; struct cs_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int idx; unsigned int idx;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
...@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, ...@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
if (uinfo->value.enumerated.item >= spec->num_inputs) if (uinfo->value.enumerated.item >= spec->num_inputs)
uinfo->value.enumerated.item = spec->num_inputs - 1; uinfo->value.enumerated.item = spec->num_inputs - 1;
idx = spec->input_idx[uinfo->value.enumerated.item]; idx = spec->input_idx[uinfo->value.enumerated.item];
strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]); strcpy(uinfo->value.enumerated.name,
hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
return 0; return 0;
} }
...@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, ...@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
return bind; return bind;
} }
/* add a (input-boost) volume control to the given input pin */
static int add_input_volume_control(struct hda_codec *codec,
struct auto_pin_cfg *cfg,
int item)
{
hda_nid_t pin = cfg->inputs[item].pin;
u32 caps;
const char *label;
struct snd_kcontrol *kctl;
if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
return 0;
caps = query_amp_caps(codec, pin, HDA_INPUT);
caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
if (caps <= 1)
return 0;
label = hda_get_autocfg_input_label(codec, cfg, item);
return add_volume(codec, label, 0,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
}
static int build_input(struct hda_codec *codec) static int build_input(struct hda_codec *codec)
{ {
struct cs_spec *spec = codec->spec; struct cs_spec *spec = codec->spec;
...@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec) ...@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
return err; return err;
} }
for (i = 0; i < spec->num_inputs; i++) {
err = add_input_volume_control(codec, &spec->autocfg, i);
if (err < 0)
return err;
}
return 0; return 0;
} }
...@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec) ...@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
AC_VERB_SET_PIN_WIDGET_CONTROL, AC_VERB_SET_PIN_WIDGET_CONTROL,
hp_present ? 0 : PIN_OUT); hp_present ? 0 : PIN_OUT);
} }
if (spec->board_config == CS420X_MBP55 || if (spec->board_config == CS420X_MBP53 ||
spec->board_config == CS420X_MBP55 ||
spec->board_config == CS420X_IMAC27) { spec->board_config == CS420X_IMAC27) {
unsigned int gpio = hp_present ? 0x02 : 0x08; unsigned int gpio = hp_present ? 0x02 : 0x08;
snd_hda_codec_write(codec, 0x01, 0, snd_hda_codec_write(codec, 0x01, 0,
...@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec) ...@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
hda_nid_t nid; hda_nid_t nid;
unsigned int present; unsigned int present;
nid = cfg->input_pins[spec->automic_idx]; nid = cfg->inputs[spec->automic_idx].pin;
present = snd_hda_jack_detect(codec, nid); present = snd_hda_jack_detect(codec, nid);
if (present) if (present)
change_cur_input(codec, spec->automic_idx, 0); change_cur_input(codec, spec->automic_idx, 0);
else { else
unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? change_cur_input(codec, !spec->automic_idx, 0);
AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
change_cur_input(codec, imic, 0);
}
} }
/* /*
...@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec) ...@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
unsigned int coef; unsigned int coef;
int i; int i;
for (i = 0; i < AUTO_PIN_LAST; i++) { for (i = 0; i < cfg->num_inputs; i++) {
unsigned int ctl; unsigned int ctl;
hda_nid_t pin = cfg->input_pins[i]; hda_nid_t pin = cfg->inputs[i].pin;
if (!pin || !spec->adc_nid[i]) if (!spec->adc_nid[i])
continue; continue;
/* set appropriate pin control and mute first */ /* set appropriate pin control and mute first */
ctl = PIN_IN; ctl = PIN_IN;
if (i <= AUTO_PIN_FRONT_MIC) { if (cfg->inputs[i].type == AUTO_PIN_MIC) {
unsigned int caps = snd_hda_query_pin_caps(codec, pin); unsigned int caps = snd_hda_query_pin_caps(codec, pin);
caps >>= AC_PINCAP_VREF_SHIFT; caps >>= AC_PINCAP_VREF_SHIFT;
if (caps & AC_PINCAP_VREF_80) if (caps & AC_PINCAP_VREF_80)
...@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec) ...@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
} }
static const char *cs420x_models[CS420X_MODELS] = { static const char *cs420x_models[CS420X_MODELS] = {
[CS420X_MBP53] = "mbp53",
[CS420X_MBP55] = "mbp55", [CS420X_MBP55] = "mbp55",
[CS420X_IMAC27] = "imac27", [CS420X_IMAC27] = "imac27",
[CS420X_AUTO] = "auto", [CS420X_AUTO] = "auto",
...@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = { ...@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
static struct snd_pci_quirk cs420x_cfg_tbl[] = { static struct snd_pci_quirk cs420x_cfg_tbl[] = {
SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27), SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
{} /* terminator */ {} /* terminator */
}; };
...@@ -1147,6 +1177,20 @@ struct cs_pincfg { ...@@ -1147,6 +1177,20 @@ struct cs_pincfg {
u32 val; u32 val;
}; };
static struct cs_pincfg mbp53_pincfgs[] = {
{ 0x09, 0x012b4050 },
{ 0x0a, 0x90100141 },
{ 0x0b, 0x90100140 },
{ 0x0c, 0x018b3020 },
{ 0x0d, 0x90a00110 },
{ 0x0e, 0x400000f0 },
{ 0x0f, 0x01cbe030 },
{ 0x10, 0x014be060 },
{ 0x12, 0x400000f0 },
{ 0x15, 0x400000f0 },
{} /* terminator */
};
static struct cs_pincfg mbp55_pincfgs[] = { static struct cs_pincfg mbp55_pincfgs[] = {
{ 0x09, 0x012b4030 }, { 0x09, 0x012b4030 },
{ 0x0a, 0x90100121 }, { 0x0a, 0x90100121 },
...@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = { ...@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
}; };
static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
[CS420X_MBP53] = mbp53_pincfgs,
[CS420X_MBP55] = mbp55_pincfgs, [CS420X_MBP55] = mbp55_pincfgs,
[CS420X_IMAC27] = imac27_pincfgs, [CS420X_IMAC27] = imac27_pincfgs,
}; };
...@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec) ...@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
switch (spec->board_config) { switch (spec->board_config) {
case CS420X_IMAC27: case CS420X_IMAC27:
case CS420X_MBP53:
case CS420X_MBP55: case CS420X_MBP55:
/* GPIO1 = headphones */ /* GPIO1 = headphones */
/* GPIO3 = speakers */ /* GPIO3 = speakers */
......
This diff is collapsed.
This diff is collapsed.
/*
*
* patch_intelhdmi.c - Patch for Intel HDMI codecs
*
* Copyright(c) 2008 Intel Corporation. All rights reserved.
*
* Authors:
* Jiang Zhe <zhe.jiang@intel.com>
* Wu Fengguang <wfg@linux.intel.com>
*
* Maintained by:
* Wu Fengguang <wfg@linux.intel.com>
*
* This program 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 program 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 <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
/*
* The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
* could support two independent pipes, each of them can be connected to one or
* more ports (DVI, HDMI or DisplayPort).
*
* The HDA correspondence of pipes/ports are converter/pin nodes.
*/
#define MAX_HDMI_CVTS 3
#define MAX_HDMI_PINS 3
#include "patch_hdmi.c"
static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
"INTEL HDMI 0",
"INTEL HDMI 1",
"INTEL HDMI 2",
};
/*
* HDMI callbacks
*/
static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
hdmi_set_channel_count(codec, hinfo->nid,
substream->runtime->channels);
hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
}
static struct hda_pcm_stream intel_hdmi_pcm_playback = {
.substreams = 1,
.channels_min = 2,
.ops = {
.open = hdmi_pcm_open,
.prepare = intel_hdmi_playback_pcm_prepare,
},
};
static int intel_hdmi_build_pcms(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
int i;
codec->num_pcms = spec->num_cvts;
codec->pcm_info = info;
for (i = 0; i < codec->num_pcms; i++, info++) {
unsigned int chans;
chans = get_wcaps(codec, spec->cvt[i]);
chans = get_wcaps_channels(chans);
info->name = intel_hdmi_pcm_names[i];
info->pcm_type = HDA_PCM_TYPE_HDMI;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
intel_hdmi_pcm_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
}
return 0;
}
static int intel_hdmi_build_controls(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
int err;
int i;
for (i = 0; i < codec->num_pcms; i++) {
err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
if (err < 0)
return err;
}
return 0;
}
static int intel_hdmi_init(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
int i;
for (i = 0; spec->pin[i]; i++) {
hdmi_enable_output(codec, spec->pin[i]);
snd_hda_codec_write(codec, spec->pin[i], 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | spec->pin[i]);
}
return 0;
}
static void intel_hdmi_free(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
int i;
for (i = 0; i < spec->num_pins; i++)
snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
kfree(spec);
}
static struct hda_codec_ops intel_hdmi_patch_ops = {
.init = intel_hdmi_init,
.free = intel_hdmi_free,
.build_pcms = intel_hdmi_build_pcms,
.build_controls = intel_hdmi_build_controls,
.unsol_event = hdmi_unsol_event,
};
static int patch_intel_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
int i;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
if (hdmi_parse_codec(codec) < 0) {
codec->spec = NULL;
kfree(spec);
return -EINVAL;
}
codec->patch_ops = intel_hdmi_patch_ops;
for (i = 0; i < spec->num_pins; i++)
snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
init_channel_allocations();
return 0;
}
static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_intel_hdmi },
{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_intel_hdmi },
{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_intel_hdmi },
{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi },
{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi },
{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi },
{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_intel_hdmi },
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
{} /* terminator */
};
MODULE_ALIAS("snd-hda-codec-id:808629fb");
MODULE_ALIAS("snd-hda-codec-id:80862801");
MODULE_ALIAS("snd-hda-codec-id:80862802");
MODULE_ALIAS("snd-hda-codec-id:80862803");
MODULE_ALIAS("snd-hda-codec-id:80862804");
MODULE_ALIAS("snd-hda-codec-id:80862805");
MODULE_ALIAS("snd-hda-codec-id:80860054");
MODULE_ALIAS("snd-hda-codec-id:10951392");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
static struct hda_codec_preset_list intel_list = {
.preset = snd_hda_preset_intelhdmi,
.owner = THIS_MODULE,
};
static int __init patch_intelhdmi_init(void)
{
return snd_hda_add_codec_preset(&intel_list);
}
static void __exit patch_intelhdmi_exit(void)
{
snd_hda_delete_codec_preset(&intel_list);
}
module_init(patch_intelhdmi_init)
module_exit(patch_intelhdmi_exit)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment