Commit 778b6e1b2da260adf3d3254aaa35bffd1eb05b42

Authored by Felix Kuehling
Committed by Jaroslav Kysela
1 parent e2f872608a

[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 +};