Commit 778b6e1b2da260adf3d3254aaa35bffd1eb05b42
Committed by
Jaroslav Kysela
1 parent
e2f872608a
Exists in
master
and in
7 other branches
[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>
Showing 4 changed files with 185 additions and 1 deletions Side-by-side Diff
sound/pci/hda/Makefile
| 1 | 1 | snd-hda-intel-objs := hda_intel.o |
| 2 | -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 | |
| 2 | +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 | |
| 3 | 3 | ifdef CONFIG_PROC_FS |
| 4 | 4 | snd-hda-codec-objs += hda_proc.o |
| 5 | 5 | endif |
sound/pci/hda/hda_intel.c
| ... | ... | @@ -82,6 +82,7 @@ |
| 82 | 82 | "{Intel, ICH8}," |
| 83 | 83 | "{ATI, SB450}," |
| 84 | 84 | "{ATI, SB600}," |
| 85 | + "{ATI, RS600}," | |
| 85 | 86 | "{VIA, VT8251}," |
| 86 | 87 | "{VIA, VT8237A}," |
| 87 | 88 | "{SiS, SIS966}," |
| ... | ... | @@ -167,6 +168,12 @@ |
| 167 | 168 | #define ULI_PLAYBACK_INDEX 5 |
| 168 | 169 | #define ULI_NUM_PLAYBACK 6 |
| 169 | 170 | |
| 171 | +/* ATI HDMI has 1 playback and 0 capture */ | |
| 172 | +#define ATIHDMI_CAPTURE_INDEX 0 | |
| 173 | +#define ATIHDMI_NUM_CAPTURE 0 | |
| 174 | +#define ATIHDMI_PLAYBACK_INDEX 0 | |
| 175 | +#define ATIHDMI_NUM_PLAYBACK 1 | |
| 176 | + | |
| 170 | 177 | /* this number is statically defined for simplicity */ |
| 171 | 178 | #define MAX_AZX_DEV 16 |
| 172 | 179 | |
| ... | ... | @@ -331,6 +338,7 @@ |
| 331 | 338 | enum { |
| 332 | 339 | AZX_DRIVER_ICH, |
| 333 | 340 | AZX_DRIVER_ATI, |
| 341 | + AZX_DRIVER_ATIHDMI, | |
| 334 | 342 | AZX_DRIVER_VIA, |
| 335 | 343 | AZX_DRIVER_SIS, |
| 336 | 344 | AZX_DRIVER_ULI, |
| ... | ... | @@ -340,6 +348,7 @@ |
| 340 | 348 | static char *driver_short_names[] __devinitdata = { |
| 341 | 349 | [AZX_DRIVER_ICH] = "HDA Intel", |
| 342 | 350 | [AZX_DRIVER_ATI] = "HDA ATI SB", |
| 351 | + [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", | |
| 343 | 352 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", |
| 344 | 353 | [AZX_DRIVER_SIS] = "HDA SIS966", |
| 345 | 354 | [AZX_DRIVER_ULI] = "HDA ULI M5461", |
| ... | ... | @@ -1495,6 +1504,12 @@ |
| 1495 | 1504 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; |
| 1496 | 1505 | chip->capture_index_offset = ULI_CAPTURE_INDEX; |
| 1497 | 1506 | break; |
| 1507 | + case AZX_DRIVER_ATIHDMI: | |
| 1508 | + chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | |
| 1509 | + chip->capture_streams = ATIHDMI_NUM_CAPTURE; | |
| 1510 | + chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; | |
| 1511 | + chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; | |
| 1512 | + break; | |
| 1498 | 1513 | default: |
| 1499 | 1514 | chip->playback_streams = ICH6_NUM_PLAYBACK; |
| 1500 | 1515 | chip->capture_streams = ICH6_NUM_CAPTURE; |
| ... | ... | @@ -1621,6 +1636,7 @@ |
| 1621 | 1636 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ |
| 1622 | 1637 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ |
| 1623 | 1638 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ |
| 1639 | + { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ | |
| 1624 | 1640 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ |
| 1625 | 1641 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ |
| 1626 | 1642 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ |
sound/pci/hda/hda_patch.h
| ... | ... | @@ -12,6 +12,8 @@ |
| 12 | 12 | extern struct hda_codec_preset snd_hda_preset_sigmatel[]; |
| 13 | 13 | /* SiLabs 3054/3055 modem codecs */ |
| 14 | 14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; |
| 15 | +/* ATI HDMI codecs */ | |
| 16 | +extern struct hda_codec_preset snd_hda_preset_atihdmi[]; | |
| 15 | 17 | |
| 16 | 18 | static const struct hda_codec_preset *hda_preset_tables[] = { |
| 17 | 19 | snd_hda_preset_realtek, |
| ... | ... | @@ -19,6 +21,7 @@ |
| 19 | 21 | snd_hda_preset_analog, |
| 20 | 22 | snd_hda_preset_sigmatel, |
| 21 | 23 | snd_hda_preset_si3054, |
| 24 | + snd_hda_preset_atihdmi, | |
| 22 | 25 | NULL |
| 23 | 26 | }; |
sound/pci/hda/patch_atihdmi.c
| 1 | +/* | |
| 2 | + * Universal Interface for Intel High Definition Audio Codec | |
| 3 | + * | |
| 4 | + * HD audio interface patch for ATI HDMI codecs | |
| 5 | + * | |
| 6 | + * Copyright (c) 2006 ATI Technologies Inc. | |
| 7 | + * | |
| 8 | + * | |
| 9 | + * This driver is free software; you can redistribute it and/or modify | |
| 10 | + * it under the terms of the GNU General Public License as published by | |
| 11 | + * the Free Software Foundation; either version 2 of the License, or | |
| 12 | + * (at your option) any later version. | |
| 13 | + * | |
| 14 | + * This driver is distributed in the hope that it will be useful, | |
| 15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | + * GNU General Public License for more details. | |
| 18 | + * | |
| 19 | + * You should have received a copy of the GNU General Public License | |
| 20 | + * along with this program; if not, write to the Free Software | |
| 21 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 22 | + */ | |
| 23 | + | |
| 24 | +#include <sound/driver.h> | |
| 25 | +#include <linux/init.h> | |
| 26 | +#include <linux/delay.h> | |
| 27 | +#include <linux/slab.h> | |
| 28 | +#include <linux/pci.h> | |
| 29 | +#include <sound/core.h> | |
| 30 | +#include "hda_codec.h" | |
| 31 | +#include "hda_local.h" | |
| 32 | + | |
| 33 | +struct atihdmi_spec { | |
| 34 | + struct hda_multi_out multiout; | |
| 35 | + | |
| 36 | + struct hda_pcm pcm_rec; | |
| 37 | +}; | |
| 38 | + | |
| 39 | +static struct hda_verb atihdmi_basic_init[] = { | |
| 40 | + /* enable digital output on pin widget */ | |
| 41 | + { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | |
| 42 | + {} /* terminator */ | |
| 43 | +}; | |
| 44 | + | |
| 45 | +/* | |
| 46 | + * Controls | |
| 47 | + */ | |
| 48 | +static int atihdmi_build_controls(struct hda_codec *codec) | |
| 49 | +{ | |
| 50 | + struct atihdmi_spec *spec = codec->spec; | |
| 51 | + int err; | |
| 52 | + | |
| 53 | + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | |
| 54 | + if (err < 0) | |
| 55 | + return err; | |
| 56 | + | |
| 57 | + return 0; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static int atihdmi_init(struct hda_codec *codec) | |
| 61 | +{ | |
| 62 | + snd_hda_sequence_write(codec, atihdmi_basic_init); | |
| 63 | + return 0; | |
| 64 | +} | |
| 65 | + | |
| 66 | +#ifdef CONFIG_PM | |
| 67 | +/* | |
| 68 | + * resume | |
| 69 | + */ | |
| 70 | +static int atihdmi_resume(struct hda_codec *codec) | |
| 71 | +{ | |
| 72 | + atihdmi_init(codec); | |
| 73 | + snd_hda_resume_spdif_out(codec); | |
| 74 | + | |
| 75 | + return 0; | |
| 76 | +} | |
| 77 | +#endif | |
| 78 | + | |
| 79 | +/* | |
| 80 | + * Digital out | |
| 81 | + */ | |
| 82 | +static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | |
| 83 | + struct hda_codec *codec, | |
| 84 | + struct snd_pcm_substream *substream) | |
| 85 | +{ | |
| 86 | + struct atihdmi_spec *spec = codec->spec; | |
| 87 | + return snd_hda_multi_out_dig_open(codec, &spec->multiout); | |
| 88 | +} | |
| 89 | + | |
| 90 | +static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | |
| 91 | + struct hda_codec *codec, | |
| 92 | + struct snd_pcm_substream *substream) | |
| 93 | +{ | |
| 94 | + struct atihdmi_spec *spec = codec->spec; | |
| 95 | + return snd_hda_multi_out_dig_close(codec, &spec->multiout); | |
| 96 | +} | |
| 97 | + | |
| 98 | +static struct hda_pcm_stream atihdmi_pcm_digital_playback = { | |
| 99 | + .substreams = 1, | |
| 100 | + .channels_min = 2, | |
| 101 | + .channels_max = 2, | |
| 102 | + .nid = 0x2, /* NID to query formats and rates and setup streams */ | |
| 103 | + .ops = { | |
| 104 | + .open = atihdmi_dig_playback_pcm_open, | |
| 105 | + .close = atihdmi_dig_playback_pcm_close | |
| 106 | + }, | |
| 107 | +}; | |
| 108 | + | |
| 109 | +static int atihdmi_build_pcms(struct hda_codec *codec) | |
| 110 | +{ | |
| 111 | + struct atihdmi_spec *spec = codec->spec; | |
| 112 | + struct hda_pcm *info = &spec->pcm_rec; | |
| 113 | + | |
| 114 | + codec->num_pcms = 1; | |
| 115 | + codec->pcm_info = info; | |
| 116 | + | |
| 117 | + info->name = "ATI HDMI"; | |
| 118 | + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; | |
| 119 | + | |
| 120 | + return 0; | |
| 121 | +} | |
| 122 | + | |
| 123 | +static void atihdmi_free(struct hda_codec *codec) | |
| 124 | +{ | |
| 125 | + kfree(codec->spec); | |
| 126 | +} | |
| 127 | + | |
| 128 | +static struct hda_codec_ops atihdmi_patch_ops = { | |
| 129 | + .build_controls = atihdmi_build_controls, | |
| 130 | + .build_pcms = atihdmi_build_pcms, | |
| 131 | + .init = atihdmi_init, | |
| 132 | + .free = atihdmi_free, | |
| 133 | +#ifdef CONFIG_PM | |
| 134 | + .resume = atihdmi_resume, | |
| 135 | +#endif | |
| 136 | +}; | |
| 137 | + | |
| 138 | +static int patch_atihdmi(struct hda_codec *codec) | |
| 139 | +{ | |
| 140 | + struct atihdmi_spec *spec; | |
| 141 | + | |
| 142 | + spec = kzalloc(sizeof(*spec), GFP_KERNEL); | |
| 143 | + if (spec == NULL) | |
| 144 | + return -ENOMEM; | |
| 145 | + | |
| 146 | + codec->spec = spec; | |
| 147 | + | |
| 148 | + spec->multiout.num_dacs = 0; /* no analog */ | |
| 149 | + spec->multiout.max_channels = 2; | |
| 150 | + spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital, | |
| 151 | + * seems to be unused in pure-digital | |
| 152 | + * case. */ | |
| 153 | + | |
| 154 | + codec->patch_ops = atihdmi_patch_ops; | |
| 155 | + | |
| 156 | + return 0; | |
| 157 | +} | |
| 158 | + | |
| 159 | +/* | |
| 160 | + * patch entries | |
| 161 | + */ | |
| 162 | +struct hda_codec_preset snd_hda_preset_atihdmi[] = { | |
| 163 | + { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | |
| 164 | + {} /* terminator */ | |
| 165 | +}; |