diff options
| author | Felix Kuehling <fkuehlin@ati.com> | 2006-05-17 11:22:21 +0200 | 
|---|---|---|
| committer | Jaroslav Kysela <perex@suse.cz> | 2006-06-22 21:33:41 +0200 | 
| commit | 778b6e1b2da260adf3d3254aaa35bffd1eb05b42 (patch) | |
| tree | e1c55390dd5fc4b791dc9c0962f1c2f721333075 | |
| parent | e2f872608af7f3c00beaa61ff6037e3cc5a66cf1 (diff) | |
| download | linux-778b6e1b2da260adf3d3254aaa35bffd1eb05b42.tar.bz2 | |
[ALSA] hda - Add support for the ATI RS600 HDMI audio device
Add support for the ATI RS600 HDMI audio device. It has a one-stream
pure digital stereo codec that isn't handled by the generic codec
support.
Signed-off-by: Felix Kuehling <fkuehlin@ati.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/hda/Makefile | 2 | ||||
| -rw-r--r-- | sound/pci/hda/hda_intel.c | 16 | ||||
| -rw-r--r-- | sound/pci/hda/hda_patch.h | 3 | ||||
| -rw-r--r-- | sound/pci/hda/patch_atihdmi.c | 165 | 
4 files changed, 185 insertions, 1 deletions
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index ddfb5ff7fb8f..dbacba6177db 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,5 +1,5 @@  snd-hda-intel-objs := hda_intel.o -snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o +snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o  ifdef CONFIG_PROC_FS  snd-hda-codec-objs += hda_proc.o  endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e821d65afa11..0154389bf95b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -82,6 +82,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"  			 "{Intel, ICH8},"  			 "{ATI, SB450},"  			 "{ATI, SB600}," +			 "{ATI, RS600},"  			 "{VIA, VT8251},"  			 "{VIA, VT8237A},"  			 "{SiS, SIS966}," @@ -167,6 +168,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };  #define ULI_PLAYBACK_INDEX	5  #define ULI_NUM_PLAYBACK	6 +/* ATI HDMI has 1 playback and 0 capture */ +#define ATIHDMI_CAPTURE_INDEX	0 +#define ATIHDMI_NUM_CAPTURE	0 +#define ATIHDMI_PLAYBACK_INDEX	0 +#define ATIHDMI_NUM_PLAYBACK	1 +  /* this number is statically defined for simplicity */  #define MAX_AZX_DEV		16 @@ -331,6 +338,7 @@ struct azx {  enum {  	AZX_DRIVER_ICH,  	AZX_DRIVER_ATI, +	AZX_DRIVER_ATIHDMI,  	AZX_DRIVER_VIA,  	AZX_DRIVER_SIS,  	AZX_DRIVER_ULI, @@ -340,6 +348,7 @@ enum {  static char *driver_short_names[] __devinitdata = {  	[AZX_DRIVER_ICH] = "HDA Intel",  	[AZX_DRIVER_ATI] = "HDA ATI SB", +	[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",  	[AZX_DRIVER_VIA] = "HDA VIA VT82xx",  	[AZX_DRIVER_SIS] = "HDA SIS966",  	[AZX_DRIVER_ULI] = "HDA ULI M5461", @@ -1495,6 +1504,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,  		chip->playback_index_offset = ULI_PLAYBACK_INDEX;  		chip->capture_index_offset = ULI_CAPTURE_INDEX;  		break; +	case AZX_DRIVER_ATIHDMI: +		chip->playback_streams = ATIHDMI_NUM_PLAYBACK; +		chip->capture_streams = ATIHDMI_NUM_CAPTURE; +		chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; +		chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; +		break;  	default:  		chip->playback_streams = ICH6_NUM_PLAYBACK;  		chip->capture_streams = ICH6_NUM_CAPTURE; @@ -1621,6 +1636,7 @@ static struct pci_device_id azx_ids[] __devinitdata = {  	{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */  	{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */  	{ 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ +	{ 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */  	{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */  	{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */  	{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index acaef3c811b8..0b668793face 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -12,6 +12,8 @@ extern struct hda_codec_preset snd_hda_preset_analog[];  extern struct hda_codec_preset snd_hda_preset_sigmatel[];  /* SiLabs 3054/3055 modem codecs */  extern struct hda_codec_preset snd_hda_preset_si3054[]; +/* ATI HDMI codecs */ +extern struct hda_codec_preset snd_hda_preset_atihdmi[];  static const struct hda_codec_preset *hda_preset_tables[] = {  	snd_hda_preset_realtek, @@ -19,5 +21,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = {  	snd_hda_preset_analog,  	snd_hda_preset_sigmatel,  	snd_hda_preset_si3054, +	snd_hda_preset_atihdmi,  	NULL  }; diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c new file mode 100644 index 000000000000..a27440ffd1c8 --- /dev/null +++ b/sound/pci/hda/patch_atihdmi.c @@ -0,0 +1,165 @@ +/* + * 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 <sound/driver.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/pci.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; +}; + +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); +	return 0; +} + +#ifdef CONFIG_PM +/* + * resume + */ +static int atihdmi_resume(struct hda_codec *codec) +{ +	atihdmi_init(codec); +	snd_hda_resume_spdif_out(codec); + +	return 0; +} +#endif + +/* + * 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 struct hda_pcm_stream atihdmi_pcm_digital_playback = { +	.substreams = 1, +	.channels_min = 2, +	.channels_max = 2, +	.nid = 0x2, /* NID to query formats and rates and setup streams */ +	.ops = { +		.open = atihdmi_dig_playback_pcm_open, +		.close = atihdmi_dig_playback_pcm_close +	}, +}; + +static int atihdmi_build_pcms(struct hda_codec *codec) +{ +	struct atihdmi_spec *spec = codec->spec; +	struct hda_pcm *info = &spec->pcm_rec; + +	codec->num_pcms = 1; +	codec->pcm_info = info; + +	info->name = "ATI HDMI"; +	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; + +	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, +#ifdef CONFIG_PM +	.resume = atihdmi_resume, +#endif +}; + +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; +	spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital, +					   * seems to be unused in pure-digital +					   * case. */ + +	codec->patch_ops = atihdmi_patch_ops; + +	return 0; +} + +/* + * patch entries + */ +struct hda_codec_preset snd_hda_preset_atihdmi[] = { +	{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, +	{} /* terminator */ +};  |