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