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 <sound/core.h> 29#include "hda_codec.h" 30#include "hda_local.h" 31 32struct atihdmi_spec { 33 struct hda_multi_out multiout; 34 35 struct hda_pcm pcm_rec; 36}; 37 38static struct hda_verb atihdmi_basic_init[] = { 39 /* enable digital output on pin widget */ 40 { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 41 {} /* terminator */ 42}; 43 44/* 45 * Controls 46 */ 47static int atihdmi_build_controls(struct hda_codec *codec) 48{ 49 struct atihdmi_spec *spec = codec->spec; 50 int err; 51 52 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 53 if (err < 0) 54 return err; 55 56 return 0; 57} 58 59static int atihdmi_init(struct hda_codec *codec) 60{ 61 snd_hda_sequence_write(codec, atihdmi_basic_init); 62 return 0; 63} 64 65#ifdef CONFIG_PM 66/* 67 * resume 68 */ 69static int atihdmi_resume(struct hda_codec *codec) 70{ 71 atihdmi_init(codec); 72 snd_hda_resume_spdif_out(codec); 73 74 return 0; 75} 76#endif 77 78/* 79 * Digital out 80 */ 81static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 82 struct hda_codec *codec, 83 struct snd_pcm_substream *substream) 84{ 85 struct atihdmi_spec *spec = codec->spec; 86 return snd_hda_multi_out_dig_open(codec, &spec->multiout); 87} 88 89static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 90 struct hda_codec *codec, 91 struct snd_pcm_substream *substream) 92{ 93 struct atihdmi_spec *spec = codec->spec; 94 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 95} 96 97static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 98 struct hda_codec *codec, 99 unsigned int stream_tag, 100 unsigned int format, 101 struct snd_pcm_substream *substream) 102{ 103 struct atihdmi_spec *spec = codec->spec; 104 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, 105 format, substream); 106} 107 108static struct hda_pcm_stream atihdmi_pcm_digital_playback = { 109 .substreams = 1, 110 .channels_min = 2, 111 .channels_max = 2, 112 .nid = 0x2, /* NID to query formats and rates and setup streams */ 113 .ops = { 114 .open = atihdmi_dig_playback_pcm_open, 115 .close = atihdmi_dig_playback_pcm_close, 116 .prepare = atihdmi_dig_playback_pcm_prepare 117 }, 118}; 119 120static int atihdmi_build_pcms(struct hda_codec *codec) 121{ 122 struct atihdmi_spec *spec = codec->spec; 123 struct hda_pcm *info = &spec->pcm_rec; 124 125 codec->num_pcms = 1; 126 codec->pcm_info = info; 127 128 info->name = "ATI HDMI"; 129 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; 130 131 return 0; 132} 133 134static void atihdmi_free(struct hda_codec *codec) 135{ 136 kfree(codec->spec); 137} 138 139static struct hda_codec_ops atihdmi_patch_ops = { 140 .build_controls = atihdmi_build_controls, 141 .build_pcms = atihdmi_build_pcms, 142 .init = atihdmi_init, 143 .free = atihdmi_free, 144#ifdef CONFIG_PM 145 .resume = atihdmi_resume, 146#endif 147}; 148 149static int patch_atihdmi(struct hda_codec *codec) 150{ 151 struct atihdmi_spec *spec; 152 153 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 154 if (spec == NULL) 155 return -ENOMEM; 156 157 codec->spec = spec; 158 159 spec->multiout.num_dacs = 0; /* no analog */ 160 spec->multiout.max_channels = 2; 161 spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital, 162 * seems to be unused in pure-digital 163 * case. */ 164 165 codec->patch_ops = atihdmi_patch_ops; 166 167 return 0; 168} 169 170/* 171 * patch entries 172 */ 173struct hda_codec_preset snd_hda_preset_atihdmi[] = { 174 { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, 175 { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, 176 { .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi }, 177 {} /* terminator */ 178}; 179