blob: c02e6d3a6314c54b6172a563fc884b007f9c22c2 [file] [log] [blame]
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +05301/*
2 * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms
3 *
4 * Copyright (C) 2014-2015 Intel Corp
5 * Author: Samreen Nilofer <samreen.nilofer@intel.com>
6 * Subhransu S. Prusty <subhransu.s.prusty@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program 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; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <linux/init.h>
21#include <linux/delay.h>
22#include <linux/module.h>
23#include <linux/pm_runtime.h>
Subhransu S. Prustya657f1d2015-11-10 18:42:09 +053024#include <linux/hdmi.h>
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +053025#include <sound/pcm_params.h>
26#include <sound/soc.h>
27#include <sound/hdaudio_ext.h>
28#include "../../hda/local.h"
29
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +053030#define AMP_OUT_MUTE 0xb080
31#define AMP_OUT_UNMUTE 0xb000
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +053032#define PIN_OUT (AC_PINCTL_OUT_EN)
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +053033
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +053034#define HDA_MAX_CONNECTIONS 32
35
36struct hdac_hdmi_cvt_params {
37 unsigned int channels_min;
38 unsigned int channels_max;
39 u32 rates;
40 u64 formats;
41 unsigned int maxbps;
42};
43
44struct hdac_hdmi_cvt {
45 hda_nid_t nid;
46 struct hdac_hdmi_cvt_params params;
47};
48
49struct hdac_hdmi_pin {
50 hda_nid_t nid;
51 int num_mux_nids;
52 hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
53};
54
55struct hdac_hdmi_dai_pin_map {
56 int dai_id;
57 struct hdac_hdmi_pin pin;
58 struct hdac_hdmi_cvt cvt;
59};
60
61struct hdac_hdmi_priv {
62 hda_nid_t pin_nid[3];
63 hda_nid_t cvt_nid[3];
64 struct hdac_hdmi_dai_pin_map dai_map[3];
65};
66
Subhransu S. Prustye342ac02015-11-10 18:42:07 +053067static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
68{
69 struct hdac_device *hdac = container_of(dev, struct hdac_device, dev);
70
71 return container_of(hdac, struct hdac_ext_device, hdac);
72}
73
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +053074static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
75 hda_nid_t cvt_nid, hda_nid_t pin_nid,
76 u32 stream_tag, int format)
77{
78 unsigned int val;
79
80 dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
81 cvt_nid, pin_nid, stream_tag, format);
82
83 val = (stream_tag << 4);
84
85 snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
86 AC_VERB_SET_CHANNEL_STREAMID, val);
87 snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
88 AC_VERB_SET_STREAM_FORMAT, format);
89
90 return 0;
91}
92
Subhransu S. Prustya657f1d2015-11-10 18:42:09 +053093static void
94hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
95 int packet_index, int byte_index)
96{
97 int val;
98
99 val = (packet_index << 5) | (byte_index & 0x1f);
100
101 snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
102 AC_VERB_SET_HDMI_DIP_INDEX, val);
103}
104
105static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
106 hda_nid_t cvt_nid, hda_nid_t pin_nid)
107{
108 uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
109 struct hdmi_audio_infoframe frame;
110 u8 *dip = (u8 *)&frame;
111 int ret;
112 int i;
113
114 hdmi_audio_infoframe_init(&frame);
115
116 /* Default stereo for now */
117 frame.channels = 2;
118
119 /* setup channel count */
120 snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
121 AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
122
123 ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
124 if (ret < 0)
125 return ret;
126
127 /* stop infoframe transmission */
128 hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
129 snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
130 AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
131
132
133 /* Fill infoframe. Index auto-incremented */
134 hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
135 for (i = 0; i < sizeof(frame); i++)
136 snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
137 AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
138
139 /* Start infoframe */
140 hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
141 snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
142 AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
143
144 return 0;
145}
146
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +0530147static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
148 struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
149{
150 /* Power up pin widget */
151 if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin.nid, pwr_state))
152 snd_hdac_codec_write(&edev->hdac, dai_map->pin.nid, 0,
153 AC_VERB_SET_POWER_STATE, pwr_state);
154
155 /* Power up converter */
156 if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt.nid, pwr_state))
157 snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
158 AC_VERB_SET_POWER_STATE, pwr_state);
159}
160
161static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
162 struct snd_soc_dai *dai)
163{
164 struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
165 struct hdac_hdmi_priv *hdmi = hdac->private_data;
166 struct hdac_hdmi_dai_pin_map *dai_map;
167 struct hdac_ext_dma_params *dd;
Subhransu S. Prustya657f1d2015-11-10 18:42:09 +0530168 int ret;
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +0530169
170 if (dai->id > 0) {
171 dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
172 return -ENODEV;
173 }
174
175 dai_map = &hdmi->dai_map[dai->id];
176
177 dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
178 dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
179 dd->stream_tag, dd->format);
180
Subhransu S. Prustya657f1d2015-11-10 18:42:09 +0530181 ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid,
182 dai_map->pin.nid);
183 if (ret < 0)
184 return ret;
185
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +0530186 return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid,
187 dd->stream_tag, dd->format);
188}
189
190static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
191 struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
192{
193 struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
194 struct hdac_ext_dma_params *dd;
195
196 if (dai->id > 0) {
197 dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
198 return -ENODEV;
199 }
200
201 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
202 dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
203 params_channels(hparams), params_format(hparams),
204 24, 0);
205
206 snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
207
208 return 0;
209}
210
211static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
212 struct snd_soc_dai *dai)
213{
214 struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
215 struct hdac_ext_dma_params *dd;
216 struct hdac_hdmi_priv *hdmi = edev->private_data;
217 struct hdac_hdmi_dai_pin_map *dai_map;
218
219 dai_map = &hdmi->dai_map[dai->id];
220
221 snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
222 AC_VERB_SET_CHANNEL_STREAMID, 0);
223 snd_hdac_codec_write(&edev->hdac, dai_map->cvt.nid, 0,
224 AC_VERB_SET_STREAM_FORMAT, 0);
225
226 dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
227 snd_soc_dai_set_dma_data(dai, substream, NULL);
228
229 kfree(dd);
230
231 return 0;
232}
233
234static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
235 struct snd_soc_dai *dai)
236{
237 struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
238 struct hdac_hdmi_priv *hdmi = hdac->private_data;
239 struct hdac_hdmi_dai_pin_map *dai_map;
240 int val;
241
242 if (dai->id > 0) {
243 dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
244 return -ENODEV;
245 }
246
247 dai_map = &hdmi->dai_map[dai->id];
248
249 val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin.nid, 0,
250 AC_VERB_GET_PIN_SENSE, 0);
251 dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
252
253 if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
254 dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
255 return -ENODEV;
256 }
257
258 hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
259
260 snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0,
261 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
262
263 snd_pcm_hw_constraint_step(substream->runtime, 0,
264 SNDRV_PCM_HW_PARAM_CHANNELS, 2);
265
266 return 0;
267}
268
269static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
270 struct snd_soc_dai *dai)
271{
272 struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
273 struct hdac_hdmi_priv *hdmi = hdac->private_data;
274 struct hdac_hdmi_dai_pin_map *dai_map;
275
276 dai_map = &hdmi->dai_map[dai->id];
277
278 hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
279
280 snd_hdac_codec_write(&hdac->hdac, dai_map->pin.nid, 0,
281 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
282}
283
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530284static int
285hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
286{
287 int err;
288
289 /* Only stereo supported as of now */
290 cvt->params.channels_min = cvt->params.channels_max = 2;
291
292 err = snd_hdac_query_supported_pcm(hdac, cvt->nid,
293 &cvt->params.rates,
294 &cvt->params.formats,
295 &cvt->params.maxbps);
296 if (err < 0)
297 dev_err(&hdac->dev,
298 "Failed to query pcm params for nid %d: %d\n",
299 cvt->nid, err);
300
301 return err;
302}
303
304static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
305 struct hdac_hdmi_pin *pin)
306{
307 if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
308 dev_warn(&hdac->hdac.dev,
309 "HDMI: pin %d wcaps %#x does not support connection list\n",
310 pin->nid, get_wcaps(&hdac->hdac, pin->nid));
311 return -EINVAL;
312 }
313
314 pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
315 pin->mux_nids, HDA_MAX_CONNECTIONS);
316 if (pin->num_mux_nids == 0) {
317 dev_err(&hdac->hdac.dev, "No connections found\n");
318 return -ENODEV;
319 }
320
321 return pin->num_mux_nids;
322}
323
324static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
325 enum snd_soc_dapm_type id,
326 const char *wname, const char *stream)
327{
328 w->id = id;
329 w->name = wname;
330 w->sname = stream;
331 w->reg = SND_SOC_NOPM;
332 w->shift = 0;
333 w->kcontrol_news = NULL;
334 w->num_kcontrols = 0;
335 w->priv = NULL;
336}
337
338static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
339 const char *sink, const char *control, const char *src)
340{
341 route->sink = sink;
342 route->source = src;
343 route->control = control;
344 route->connected = NULL;
345}
346
347static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
348 struct hdac_hdmi_dai_pin_map *dai_map)
349{
350 struct snd_soc_dapm_route route[1];
351 struct snd_soc_dapm_widget widgets[2] = { {0} };
352
353 memset(&route, 0, sizeof(route));
354
355 hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
356 "hif1 Output", NULL);
357 hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
358 "Coverter 1", "hif1");
359
360 hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
361
362 snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
363 snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
364}
365
366static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev,
367 struct hdac_hdmi_dai_pin_map *dai_map,
368 hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id)
369{
370 int ret;
371
372 dai_map->dai_id = dai_id;
373 dai_map->pin.nid = pin_nid;
374
375 ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin);
376 if (ret < 0) {
377 dev_err(&edev->hdac.dev,
378 "Error querying connection list: %d\n", ret);
379 return ret;
380 }
381
382 dai_map->cvt.nid = cvt_nid;
383
384 /* Enable out path for this pin widget */
385 snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
386 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
387
388 /* Enable transmission */
389 snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
390 AC_VERB_SET_DIGI_CONVERT_1, 1);
391
392 /* Category Code (CC) to zero */
393 snd_hdac_codec_write(&edev->hdac, cvt_nid, 0,
394 AC_VERB_SET_DIGI_CONVERT_2, 0);
395
396 snd_hdac_codec_write(&edev->hdac, pin_nid, 0,
397 AC_VERB_SET_CONNECT_SEL, 0);
398
399 return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt);
400}
401
402/*
403 * Parse all nodes and store the cvt/pin nids in array
404 * Add one time initialization for pin and cvt widgets
405 */
406static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
407{
408 hda_nid_t nid;
409 int i;
410 struct hdac_device *hdac = &edev->hdac;
411 struct hdac_hdmi_priv *hdmi = edev->private_data;
412 int cvt_nid = 0, pin_nid = 0;
413
414 hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
415 if (!nid || hdac->num_nodes < 0) {
416 dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
417 return -EINVAL;
418 }
419
420 hdac->start_nid = nid;
421
422 for (i = 0; i < hdac->num_nodes; i++, nid++) {
423 unsigned int caps;
424 unsigned int type;
425
426 caps = get_wcaps(hdac, nid);
427 type = get_wcaps_type(caps);
428
429 if (!(caps & AC_WCAP_DIGITAL))
430 continue;
431
432 switch (type) {
433
434 case AC_WID_AUD_OUT:
435 hdmi->cvt_nid[cvt_nid] = nid;
436 cvt_nid++;
437 break;
438
439 case AC_WID_PIN:
440 hdmi->pin_nid[pin_nid] = nid;
441 pin_nid++;
442 break;
443 }
444 }
445
446 hdac->end_nid = nid;
447
448 if (!pin_nid || !cvt_nid)
449 return -EIO;
450
451 /*
452 * Currently on board only 1 pin and 1 converter is enabled for
453 * simplification, more will be added eventually
454 * So using fixed map for dai_id:pin:cvt
455 */
456 return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0],
457 hdmi->cvt_nid[0], 0);
458}
459
460static int hdmi_codec_probe(struct snd_soc_codec *codec)
461{
462 struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
463 struct hdac_hdmi_priv *hdmi = edev->private_data;
464 struct snd_soc_dapm_context *dapm =
465 snd_soc_component_get_dapm(&codec->component);
466
467 edev->scodec = codec;
468
469 create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
470
471 /* Imp: Store the card pointer in hda_codec */
472 edev->card = dapm->card->snd_card;
473
Subhransu S. Prustye342ac02015-11-10 18:42:07 +0530474 /*
475 * hdac_device core already sets the state to active and calls
476 * get_noresume. So enable runtime and set the device to suspend.
477 */
478 pm_runtime_enable(&edev->hdac.dev);
479 pm_runtime_put(&edev->hdac.dev);
480 pm_runtime_suspend(&edev->hdac.dev);
481
482 return 0;
483}
484
485static int hdmi_codec_remove(struct snd_soc_codec *codec)
486{
487 struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
488
489 pm_runtime_disable(&edev->hdac.dev);
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530490 return 0;
491}
492
493static struct snd_soc_codec_driver hdmi_hda_codec = {
494 .probe = hdmi_codec_probe,
Subhransu S. Prustye342ac02015-11-10 18:42:07 +0530495 .remove = hdmi_codec_remove,
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530496 .idle_bias_off = true,
497};
498
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +0530499static struct snd_soc_dai_ops hdmi_dai_ops = {
500 .startup = hdac_hdmi_pcm_open,
501 .shutdown = hdac_hdmi_pcm_close,
502 .hw_params = hdac_hdmi_set_hw_params,
503 .prepare = hdac_hdmi_playback_prepare,
504 .hw_free = hdac_hdmi_playback_cleanup,
505};
506
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530507static struct snd_soc_dai_driver hdmi_dais[] = {
508 { .name = "intel-hdmi-hif1",
509 .playback = {
510 .stream_name = "hif1",
511 .channels_min = 2,
512 .channels_max = 2,
513 .rates = SNDRV_PCM_RATE_32000 |
514 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
515 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
516 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
517 .formats = SNDRV_PCM_FMTBIT_S16_LE |
518 SNDRV_PCM_FMTBIT_S20_3LE |
519 SNDRV_PCM_FMTBIT_S24_LE |
520 SNDRV_PCM_FMTBIT_S32_LE,
521
522 },
Subhransu S. Prustyb0362ad2015-11-10 18:42:08 +0530523 .ops = &hdmi_dai_ops,
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530524 },
525};
526
527static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
528{
529 struct hdac_device *codec = &edev->hdac;
530 struct hdac_hdmi_priv *hdmi_priv;
531 int ret = 0;
532
533 hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
534 if (hdmi_priv == NULL)
535 return -ENOMEM;
536
537 edev->private_data = hdmi_priv;
538
539 dev_set_drvdata(&codec->dev, edev);
540
541 ret = hdac_hdmi_parse_and_map_nid(edev);
542 if (ret < 0)
543 return ret;
544
545 /* ASoC specific initialization */
546 return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
547 hdmi_dais, ARRAY_SIZE(hdmi_dais));
548}
549
550static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
551{
552 snd_soc_unregister_codec(&edev->hdac.dev);
553
554 return 0;
555}
556
Subhransu S. Prustye342ac02015-11-10 18:42:07 +0530557#ifdef CONFIG_PM
558static int hdac_hdmi_runtime_suspend(struct device *dev)
559{
560 struct hdac_ext_device *edev = to_hda_ext_device(dev);
561 struct hdac_device *hdac = &edev->hdac;
562
563 dev_dbg(dev, "Enter: %s\n", __func__);
564
565 /* Power down afg */
566 if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
567 snd_hdac_codec_write(hdac, hdac->afg, 0,
568 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
569
570 return 0;
571}
572
573static int hdac_hdmi_runtime_resume(struct device *dev)
574{
575 struct hdac_ext_device *edev = to_hda_ext_device(dev);
576 struct hdac_device *hdac = &edev->hdac;
577
578 dev_dbg(dev, "Enter: %s\n", __func__);
579
580 /* Power up afg */
581 if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
582 snd_hdac_codec_write(hdac, hdac->afg, 0,
583 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
584
585 return 0;
586}
587#else
588#define hdac_hdmi_runtime_suspend NULL
589#define hdac_hdmi_runtime_resume NULL
590#endif
591
592static const struct dev_pm_ops hdac_hdmi_pm = {
593 SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
594};
595
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530596static const struct hda_device_id hdmi_list[] = {
597 HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
598 {}
599};
600
601MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
602
603static struct hdac_ext_driver hdmi_driver = {
604 . hdac = {
605 .driver = {
606 .name = "HDMI HDA Codec",
Subhransu S. Prustye342ac02015-11-10 18:42:07 +0530607 .pm = &hdac_hdmi_pm,
Subhransu S. Prusty18382ea2015-11-10 18:42:06 +0530608 },
609 .id_table = hdmi_list,
610 },
611 .probe = hdac_hdmi_dev_probe,
612 .remove = hdac_hdmi_dev_remove,
613};
614
615static int __init hdmi_init(void)
616{
617 return snd_hda_ext_driver_register(&hdmi_driver);
618}
619
620static void __exit hdmi_exit(void)
621{
622 snd_hda_ext_driver_unregister(&hdmi_driver);
623}
624
625module_init(hdmi_init);
626module_exit(hdmi_exit);
627
628MODULE_LICENSE("GPL v2");
629MODULE_DESCRIPTION("HDMI HD codec");
630MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>");
631MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");