blob: 57042ef3a480cb68b332fbfdbf4b4fa5c2c2b4d0 [file] [log] [blame]
Jerome Anand5dab11d2017-01-25 04:27:52 +05301/*
2 * intel_hdmi_audio.c - Intel HDMI audio driver
3 *
4 * Copyright (C) 2016 Intel Corp
5 * Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
6 * Ramesh Babu K V <ramesh.babu@intel.com>
7 * Vaibhav Agarwal <vaibhav.agarwal@intel.com>
8 * Jerome Anand <jerome.anand@intel.com>
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21 * ALSA driver for Intel HDMI audio
22 */
23
Takashi Iwai03c34372017-02-02 16:19:03 +010024#include <linux/types.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053025#include <linux/platform_device.h>
26#include <linux/io.h>
27#include <linux/slab.h>
28#include <linux/module.h>
Takashi Iwaida864802017-01-31 13:52:22 +010029#include <linux/interrupt.h>
Takashi Iwai03c34372017-02-02 16:19:03 +010030#include <linux/pm_runtime.h>
Takashi Iwai412bbe7d52017-02-02 22:03:22 +010031#include <linux/dma-mapping.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053032#include <asm/cacheflush.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053033#include <sound/core.h>
Takashi Iwai03c34372017-02-02 16:19:03 +010034#include <sound/asoundef.h>
35#include <sound/pcm.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053036#include <sound/pcm_params.h>
37#include <sound/initval.h>
38#include <sound/control.h>
Takashi Iwai03c34372017-02-02 16:19:03 +010039#include <drm/drm_edid.h>
Takashi Iwaida864802017-01-31 13:52:22 +010040#include <drm/intel_lpe_audio.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053041#include "intel_hdmi_audio.h"
42
Jerome Anand5dab11d2017-01-25 04:27:52 +053043/*standard module options for ALSA. This module supports only one card*/
44static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
45static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
Jerome Anand5dab11d2017-01-25 04:27:52 +053046
47module_param_named(index, hdmi_card_index, int, 0444);
48MODULE_PARM_DESC(index,
49 "Index value for INTEL Intel HDMI Audio controller.");
50module_param_named(id, hdmi_card_id, charp, 0444);
51MODULE_PARM_DESC(id,
52 "ID string for INTEL Intel HDMI Audio controller.");
53
54/*
55 * ELD SA bits in the CEA Speaker Allocation data block
56 */
Takashi Iwai4a5ddb22017-02-01 16:45:38 +010057static const int eld_speaker_allocation_bits[] = {
Jerome Anand5dab11d2017-01-25 04:27:52 +053058 [0] = FL | FR,
59 [1] = LFE,
60 [2] = FC,
61 [3] = RL | RR,
62 [4] = RC,
63 [5] = FLC | FRC,
64 [6] = RLC | RRC,
65 /* the following are not defined in ELD yet */
66 [7] = 0,
67};
68
69/*
70 * This is an ordered list!
71 *
72 * The preceding ones have better chances to be selected by
73 * hdmi_channel_allocation().
74 */
75static struct cea_channel_speaker_allocation channel_allocations[] = {
76/* channel: 7 6 5 4 3 2 1 0 */
77{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
78 /* 2.1 */
79{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
80 /* Dolby Surround */
81{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
82 /* surround40 */
83{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
84 /* surround41 */
85{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
86 /* surround50 */
87{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
88 /* surround51 */
89{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
90 /* 6.1 */
91{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
92 /* surround71 */
93{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
94
95{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
96{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
97{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
98{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
99{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
100{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
101{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
102{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
103{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
104{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
105{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
106{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
107{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
108{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
109{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
110{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
111{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
112{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
113{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
114{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
115{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
116{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
117{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
118};
119
Takashi Iwai4a5ddb22017-02-01 16:45:38 +0100120static const struct channel_map_table map_tables[] = {
Jerome Anand5dab11d2017-01-25 04:27:52 +0530121 { SNDRV_CHMAP_FL, 0x00, FL },
122 { SNDRV_CHMAP_FR, 0x01, FR },
123 { SNDRV_CHMAP_RL, 0x04, RL },
124 { SNDRV_CHMAP_RR, 0x05, RR },
125 { SNDRV_CHMAP_LFE, 0x02, LFE },
126 { SNDRV_CHMAP_FC, 0x03, FC },
127 { SNDRV_CHMAP_RLC, 0x06, RLC },
128 { SNDRV_CHMAP_RRC, 0x07, RRC },
129 {} /* terminator */
130};
131
132/* hardware capability structure */
Takashi Iwaib5562902017-02-04 22:05:33 +0100133static const struct snd_pcm_hardware had_pcm_hardware = {
Jerome Anand5dab11d2017-01-25 04:27:52 +0530134 .info = (SNDRV_PCM_INFO_INTERLEAVED |
135 SNDRV_PCM_INFO_DOUBLE |
136 SNDRV_PCM_INFO_MMAP|
137 SNDRV_PCM_INFO_MMAP_VALID |
138 SNDRV_PCM_INFO_BATCH),
139 .formats = (SNDRV_PCM_FMTBIT_S24 |
140 SNDRV_PCM_FMTBIT_U24),
141 .rates = SNDRV_PCM_RATE_32000 |
142 SNDRV_PCM_RATE_44100 |
143 SNDRV_PCM_RATE_48000 |
144 SNDRV_PCM_RATE_88200 |
145 SNDRV_PCM_RATE_96000 |
146 SNDRV_PCM_RATE_176400 |
147 SNDRV_PCM_RATE_192000,
148 .rate_min = HAD_MIN_RATE,
149 .rate_max = HAD_MAX_RATE,
150 .channels_min = HAD_MIN_CHANNEL,
151 .channels_max = HAD_MAX_CHANNEL,
152 .buffer_bytes_max = HAD_MAX_BUFFER,
153 .period_bytes_min = HAD_MIN_PERIOD_BYTES,
154 .period_bytes_max = HAD_MAX_PERIOD_BYTES,
155 .periods_min = HAD_MIN_PERIODS,
156 .periods_max = HAD_MAX_PERIODS,
157 .fifo_size = HAD_FIFO_SIZE,
158};
159
Takashi Iwai313d9f22017-02-02 13:00:12 +0100160/* Get the active PCM substream;
161 * Call had_substream_put() for unreferecing.
162 * Don't call this inside had_spinlock, as it takes by itself
163 */
164static struct snd_pcm_substream *
165had_substream_get(struct snd_intelhad *intelhaddata)
166{
167 struct snd_pcm_substream *substream;
168 unsigned long flags;
169
170 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
171 substream = intelhaddata->stream_info.substream;
172 if (substream)
173 intelhaddata->stream_info.substream_refcount++;
174 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
175 return substream;
176}
177
178/* Unref the active PCM substream;
179 * Don't call this inside had_spinlock, as it takes by itself
180 */
181static void had_substream_put(struct snd_intelhad *intelhaddata)
182{
183 unsigned long flags;
184
185 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
186 intelhaddata->stream_info.substream_refcount--;
187 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
188}
189
Jerome Anand5dab11d2017-01-25 04:27:52 +0530190/* Register access functions */
Takashi Iwai83af57d2017-02-03 08:50:06 +0100191static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530192{
Takashi Iwaida864802017-01-31 13:52:22 +0100193 *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530194}
195
Takashi Iwai83af57d2017-02-03 08:50:06 +0100196static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530197{
Takashi Iwaida864802017-01-31 13:52:22 +0100198 iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530199}
200
Takashi Iwaida864802017-01-31 13:52:22 +0100201/*
Takashi Iwai313d9f22017-02-02 13:00:12 +0100202 * enable / disable audio configuration
203 *
Takashi Iwai83af57d2017-02-03 08:50:06 +0100204 * The normal read/modify should not directly be used on VLV2 for
Takashi Iwaida864802017-01-31 13:52:22 +0100205 * updating AUD_CONFIG register.
Jerome Anand5dab11d2017-01-25 04:27:52 +0530206 * This is because:
207 * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2
208 * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always
209 * clear bit6. AUD_CONFIG[6:4] represents the "channels" field of the
210 * register. This field should be 1xy binary for configuration with 6 or
211 * more channels. Read-modify of AUD_CONFIG (Eg. for enabling audio)
212 * causes the "channels" field to be updated as 0xy binary resulting in
213 * bad audio. The fix is to always write the AUD_CONFIG[6:4] with
214 * appropriate value when doing read-modify of AUD_CONFIG register.
Jerome Anand5dab11d2017-01-25 04:27:52 +0530215 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100216static void had_enable_audio(struct snd_pcm_substream *substream,
217 struct snd_intelhad *intelhaddata,
218 bool enable)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530219{
Takashi Iwai7ceba752017-02-02 15:58:35 +0100220 union aud_cfg cfg_val = {.regval = 0};
Takashi Iwai83af57d2017-02-03 08:50:06 +0100221 u8 channels;
222 u32 mask, val;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530223
224 /*
225 * If substream is NULL, there is no active stream.
226 * In this case just set channels to 2
227 */
Takashi Iwai313d9f22017-02-02 13:00:12 +0100228 channels = substream ? substream->runtime->channels : 2;
Takashi Iwai83af57d2017-02-03 08:50:06 +0100229 dev_dbg(intelhaddata->dev, "enable %d, ch=%d\n", enable, channels);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530230
Takashi Iwai83af57d2017-02-03 08:50:06 +0100231 cfg_val.regx.num_ch = channels - 2;
Takashi Iwai313d9f22017-02-02 13:00:12 +0100232 if (enable)
Takashi Iwai83af57d2017-02-03 08:50:06 +0100233 cfg_val.regx.aud_en = 1;
Takashi Iwai313d9f22017-02-02 13:00:12 +0100234 mask = AUD_CONFIG_CH_MASK | 1;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530235
Takashi Iwai83af57d2017-02-03 08:50:06 +0100236 had_read_register(intelhaddata, AUD_CONFIG, &val);
237 val &= ~mask;
238 val |= cfg_val.regval;
239 had_write_register(intelhaddata, AUD_CONFIG, val);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530240}
241
Takashi Iwai313d9f22017-02-02 13:00:12 +0100242/* enable / disable the audio interface */
Takashi Iwaib5562902017-02-04 22:05:33 +0100243static void had_enable_audio_int(struct snd_intelhad *ctx, bool enable)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530244{
Takashi Iwaida864802017-01-31 13:52:22 +0100245 u32 status_reg;
246
247 if (enable) {
Takashi Iwai83af57d2017-02-03 08:50:06 +0100248 had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
Takashi Iwaida864802017-01-31 13:52:22 +0100249 status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
Takashi Iwai83af57d2017-02-03 08:50:06 +0100250 had_write_register(ctx, AUD_HDMI_STATUS, status_reg);
251 had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
Takashi Iwaida864802017-01-31 13:52:22 +0100252 }
253}
254
Takashi Iwaif4566aa2017-02-04 21:39:56 +0100255/* Reset buffer pointers */
256static void had_reset_audio(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530257{
Takashi Iwaif4566aa2017-02-04 21:39:56 +0100258 had_write_register(intelhaddata, AUD_HDMI_STATUS, 1);
259 had_write_register(intelhaddata, AUD_HDMI_STATUS, 0);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530260}
261
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100262/*
Jerome Anand5dab11d2017-01-25 04:27:52 +0530263 * initialize audio channel status registers
264 * This function is called in the prepare callback
265 */
266static int had_prog_status_reg(struct snd_pcm_substream *substream,
267 struct snd_intelhad *intelhaddata)
268{
Takashi Iwai7ceba752017-02-02 15:58:35 +0100269 union aud_cfg cfg_val = {.regval = 0};
270 union aud_ch_status_0 ch_stat0 = {.regval = 0};
271 union aud_ch_status_1 ch_stat1 = {.regval = 0};
Jerome Anand5dab11d2017-01-25 04:27:52 +0530272 int format;
273
Takashi Iwai7ceba752017-02-02 15:58:35 +0100274 ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits &
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100275 IEC958_AES0_NONAUDIO) >> 1;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100276 ch_stat0.regx.clk_acc = (intelhaddata->aes_bits &
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100277 IEC958_AES3_CON_CLOCK) >> 4;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100278 cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530279
280 switch (substream->runtime->rate) {
281 case AUD_SAMPLE_RATE_32:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100282 ch_stat0.regx.samp_freq = CH_STATUS_MAP_32KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530283 break;
284
285 case AUD_SAMPLE_RATE_44_1:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100286 ch_stat0.regx.samp_freq = CH_STATUS_MAP_44KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530287 break;
288 case AUD_SAMPLE_RATE_48:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100289 ch_stat0.regx.samp_freq = CH_STATUS_MAP_48KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530290 break;
291 case AUD_SAMPLE_RATE_88_2:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100292 ch_stat0.regx.samp_freq = CH_STATUS_MAP_88KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530293 break;
294 case AUD_SAMPLE_RATE_96:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100295 ch_stat0.regx.samp_freq = CH_STATUS_MAP_96KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530296 break;
297 case AUD_SAMPLE_RATE_176_4:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100298 ch_stat0.regx.samp_freq = CH_STATUS_MAP_176KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530299 break;
300 case AUD_SAMPLE_RATE_192:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100301 ch_stat0.regx.samp_freq = CH_STATUS_MAP_192KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530302 break;
303
304 default:
305 /* control should never come here */
306 return -EINVAL;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530307 }
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100308
Takashi Iwai79dda752017-01-30 17:23:39 +0100309 had_write_register(intelhaddata,
Takashi Iwai7ceba752017-02-02 15:58:35 +0100310 AUD_CH_STATUS_0, ch_stat0.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530311
312 format = substream->runtime->format;
313
314 if (format == SNDRV_PCM_FORMAT_S16_LE) {
Takashi Iwai7ceba752017-02-02 15:58:35 +0100315 ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20;
316 ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530317 } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
Takashi Iwai7ceba752017-02-02 15:58:35 +0100318 ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24;
319 ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530320 } else {
Takashi Iwai7ceba752017-02-02 15:58:35 +0100321 ch_stat1.regx.max_wrd_len = 0;
322 ch_stat1.regx.wrd_len = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530323 }
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100324
Takashi Iwai79dda752017-01-30 17:23:39 +0100325 had_write_register(intelhaddata,
Takashi Iwai7ceba752017-02-02 15:58:35 +0100326 AUD_CH_STATUS_1, ch_stat1.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530327 return 0;
328}
329
Takashi Iwai76296ef2017-01-30 16:09:11 +0100330/*
Jerome Anand5dab11d2017-01-25 04:27:52 +0530331 * function to initialize audio
332 * registers and buffer confgiuration registers
333 * This function is called in the prepare callback
334 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100335static int had_init_audio_ctrl(struct snd_pcm_substream *substream,
336 struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530337{
Takashi Iwai7ceba752017-02-02 15:58:35 +0100338 union aud_cfg cfg_val = {.regval = 0};
339 union aud_buf_config buf_cfg = {.regval = 0};
Jerome Anand5dab11d2017-01-25 04:27:52 +0530340 u8 channels;
341
342 had_prog_status_reg(substream, intelhaddata);
343
Takashi Iwai7ceba752017-02-02 15:58:35 +0100344 buf_cfg.regx.audio_fifo_watermark = FIFO_THRESHOLD;
345 buf_cfg.regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD;
346 buf_cfg.regx.aud_delay = 0;
347 had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530348
349 channels = substream->runtime->channels;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100350 cfg_val.regx.num_ch = channels - 2;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530351 if (channels <= 2)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100352 cfg_val.regx.layout = LAYOUT0;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530353 else
Takashi Iwai7ceba752017-02-02 15:58:35 +0100354 cfg_val.regx.layout = LAYOUT1;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530355
Takashi Iwai7ceba752017-02-02 15:58:35 +0100356 cfg_val.regx.val_bit = 1;
Takashi Iwai83af57d2017-02-03 08:50:06 +0100357
358 /* fix up the DP bits */
359 if (intelhaddata->dp_output) {
360 cfg_val.regx.dp_modei = 1;
361 cfg_val.regx.set = 1;
362 }
363
Takashi Iwai7ceba752017-02-02 15:58:35 +0100364 had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530365 return 0;
366}
367
Jerome Anand5dab11d2017-01-25 04:27:52 +0530368/*
369 * Compute derived values in channel_allocations[].
370 */
371static void init_channel_allocations(void)
372{
373 int i, j;
374 struct cea_channel_speaker_allocation *p;
375
Jerome Anand5dab11d2017-01-25 04:27:52 +0530376 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
377 p = channel_allocations + i;
378 p->channels = 0;
379 p->spk_mask = 0;
380 for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
381 if (p->speakers[j]) {
382 p->channels++;
383 p->spk_mask |= p->speakers[j];
384 }
385 }
386}
387
388/*
389 * The transformation takes two steps:
390 *
391 * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
392 * spk_mask => (channel_allocations[]) => ai->CA
393 *
394 * TODO: it could select the wrong CA from multiple candidates.
395 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100396static int had_channel_allocation(struct snd_intelhad *intelhaddata,
397 int channels)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530398{
399 int i;
400 int ca = 0;
401 int spk_mask = 0;
402
403 /*
404 * CA defaults to 0 for basic stereo audio
405 */
406 if (channels <= 2)
407 return 0;
408
409 /*
410 * expand ELD's speaker allocation mask
411 *
412 * ELD tells the speaker mask in a compact(paired) form,
413 * expand ELD's notions to match the ones used by Audio InfoFrame.
414 */
415
416 for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100417 if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
Jerome Anand5dab11d2017-01-25 04:27:52 +0530418 spk_mask |= eld_speaker_allocation_bits[i];
419 }
420
421 /* search for the first working match in the CA table */
422 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
423 if (channels == channel_allocations[i].channels &&
424 (spk_mask & channel_allocations[i].spk_mask) ==
425 channel_allocations[i].spk_mask) {
426 ca = channel_allocations[i].ca_index;
427 break;
428 }
429 }
430
Takashi Iwaic75b0472017-01-31 15:49:15 +0100431 dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530432
433 return ca;
434}
435
436/* from speaker bit mask to ALSA API channel position */
437static int spk_to_chmap(int spk)
438{
Takashi Iwai4a5ddb22017-02-01 16:45:38 +0100439 const struct channel_map_table *t = map_tables;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530440
441 for (; t->map; t++) {
442 if (t->spk_mask == spk)
443 return t->map;
444 }
445 return 0;
446}
447
Takashi Iwai372d8552017-01-31 13:57:58 +0100448static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530449{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100450 int i, c;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530451 int spk_mask = 0;
452 struct snd_pcm_chmap_elem *chmap;
453 u8 eld_high, eld_high_mask = 0xF0;
454 u8 high_msb;
455
456 chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100457 if (!chmap) {
Jerome Anand5dab11d2017-01-25 04:27:52 +0530458 intelhaddata->chmap->chmap = NULL;
459 return;
460 }
461
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100462 dev_dbg(intelhaddata->dev, "eld speaker = %x\n",
463 intelhaddata->eld[DRM_ELD_SPEAKER]);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530464
465 /* WA: Fix the max channel supported to 8 */
466
467 /*
468 * Sink may support more than 8 channels, if eld_high has more than
469 * one bit set. SOC supports max 8 channels.
470 * Refer eld_speaker_allocation_bits, for sink speaker allocation
471 */
472
473 /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100474 eld_high = intelhaddata->eld[DRM_ELD_SPEAKER] & eld_high_mask;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530475 if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
476 /* eld_high & (eld_high-1): if more than 1 bit set */
477 /* 0x1F: 7 channels */
478 for (i = 1; i < 4; i++) {
479 high_msb = eld_high & (0x80 >> i);
480 if (high_msb) {
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100481 intelhaddata->eld[DRM_ELD_SPEAKER] &=
Jerome Anand5dab11d2017-01-25 04:27:52 +0530482 high_msb | 0xF;
483 break;
484 }
485 }
486 }
487
488 for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100489 if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
Jerome Anand5dab11d2017-01-25 04:27:52 +0530490 spk_mask |= eld_speaker_allocation_bits[i];
491 }
492
493 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
494 if (spk_mask == channel_allocations[i].spk_mask) {
495 for (c = 0; c < channel_allocations[i].channels; c++) {
496 chmap->map[c] = spk_to_chmap(
497 channel_allocations[i].speakers[
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100498 (MAX_SPEAKERS - 1) - c]);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530499 }
500 chmap->channels = channel_allocations[i].channels;
501 intelhaddata->chmap->chmap = chmap;
502 break;
503 }
504 }
505 if (i >= ARRAY_SIZE(channel_allocations)) {
506 intelhaddata->chmap->chmap = NULL;
507 kfree(chmap);
508 }
509}
510
511/*
512 * ALSA API channel-map control callbacks
513 */
514static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol,
515 struct snd_ctl_elem_info *uinfo)
516{
517 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
518 struct snd_intelhad *intelhaddata = info->private_data;
519
Takashi Iwai91b0cb02017-02-02 17:46:49 +0100520 if (!intelhaddata->connected)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530521 return -ENODEV;
522 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
523 uinfo->count = HAD_MAX_CHANNEL;
524 uinfo->value.integer.min = 0;
525 uinfo->value.integer.max = SNDRV_CHMAP_LAST;
526 return 0;
527}
528
529static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol,
530 struct snd_ctl_elem_value *ucontrol)
531{
532 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
533 struct snd_intelhad *intelhaddata = info->private_data;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100534 int i;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530535 const struct snd_pcm_chmap_elem *chmap;
536
Takashi Iwai91b0cb02017-02-02 17:46:49 +0100537 if (!intelhaddata->connected)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530538 return -ENODEV;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +0100539
540 mutex_lock(&intelhaddata->mutex);
541 if (!intelhaddata->chmap->chmap) {
542 mutex_unlock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530543 return -ENODATA;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +0100544 }
545
Jerome Anand5dab11d2017-01-25 04:27:52 +0530546 chmap = intelhaddata->chmap->chmap;
Takashi Iwaic75b0472017-01-31 15:49:15 +0100547 for (i = 0; i < chmap->channels; i++)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530548 ucontrol->value.integer.value[i] = chmap->map[i];
Takashi Iwai8f8d1d72017-02-01 17:24:02 +0100549 mutex_unlock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530550
551 return 0;
552}
553
554static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
555 struct snd_pcm *pcm)
556{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100557 int err;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530558
559 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
560 NULL, 0, (unsigned long)intelhaddata,
561 &intelhaddata->chmap);
562 if (err < 0)
563 return err;
564
565 intelhaddata->chmap->private_data = intelhaddata;
Takashi Iwaie9d65ab2017-01-31 16:11:27 +0100566 intelhaddata->chmap->kctl->info = had_chmap_ctl_info;
567 intelhaddata->chmap->kctl->get = had_chmap_ctl_get;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530568 intelhaddata->chmap->chmap = NULL;
569 return 0;
570}
571
Takashi Iwai76296ef2017-01-30 16:09:11 +0100572/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100573 * Initialize Data Island Packets registers
Jerome Anand5dab11d2017-01-25 04:27:52 +0530574 * This function is called in the prepare callback
575 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100576static void had_prog_dip(struct snd_pcm_substream *substream,
577 struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530578{
579 int i;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100580 union aud_ctrl_st ctrl_state = {.regval = 0};
581 union aud_info_frame2 frame2 = {.regval = 0};
582 union aud_info_frame3 frame3 = {.regval = 0};
Jerome Anand5dab11d2017-01-25 04:27:52 +0530583 u8 checksum = 0;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600584 u32 info_frame;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530585 int channels;
Takashi Iwai36ed3462017-02-02 17:06:38 +0100586 int ca;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530587
588 channels = substream->runtime->channels;
589
Takashi Iwai7ceba752017-02-02 15:58:35 +0100590 had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530591
Takashi Iwaib5562902017-02-04 22:05:33 +0100592 ca = had_channel_allocation(intelhaddata, channels);
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600593 if (intelhaddata->dp_output) {
594 info_frame = DP_INFO_FRAME_WORD1;
Takashi Iwai36ed3462017-02-02 17:06:38 +0100595 frame2.regval = (substream->runtime->channels - 1) | (ca << 24);
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600596 } else {
597 info_frame = HDMI_INFO_FRAME_WORD1;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100598 frame2.regx.chnl_cnt = substream->runtime->channels - 1;
Takashi Iwai36ed3462017-02-02 17:06:38 +0100599 frame3.regx.chnl_alloc = ca;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530600
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100601 /* Calculte the byte wide checksum for all valid DIP words */
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600602 for (i = 0; i < BYTES_PER_WORD; i++)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100603 checksum += (info_frame >> (i * 8)) & 0xff;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600604 for (i = 0; i < BYTES_PER_WORD; i++)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100605 checksum += (frame2.regval >> (i * 8)) & 0xff;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600606 for (i = 0; i < BYTES_PER_WORD; i++)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100607 checksum += (frame3.regval >> (i * 8)) & 0xff;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530608
Takashi Iwai7ceba752017-02-02 15:58:35 +0100609 frame2.regx.chksum = -(checksum);
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600610 }
Jerome Anand5dab11d2017-01-25 04:27:52 +0530611
Takashi Iwai4151ee82017-01-31 18:14:15 +0100612 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame);
Takashi Iwai7ceba752017-02-02 15:58:35 +0100613 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.regval);
614 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530615
616 /* program remaining DIP words with zero */
617 for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
Takashi Iwai4151ee82017-01-31 18:14:15 +0100618 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530619
Takashi Iwai7ceba752017-02-02 15:58:35 +0100620 ctrl_state.regx.dip_freq = 1;
621 ctrl_state.regx.dip_en_sta = 1;
622 had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530623}
624
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100625/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100626 * Programs buffer address and length registers
Jerome Anand5dab11d2017-01-25 04:27:52 +0530627 * This function programs ring buffer address and length into registers.
628 */
Takashi Iwai313d9f22017-02-02 13:00:12 +0100629static int snd_intelhad_prog_buffer(struct snd_pcm_substream *substream,
630 struct snd_intelhad *intelhaddata,
631 int start, int end)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530632{
633 u32 ring_buf_addr, ring_buf_size, period_bytes;
634 u8 i, num_periods;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530635
636 ring_buf_addr = substream->runtime->dma_addr;
637 ring_buf_size = snd_pcm_lib_buffer_bytes(substream);
638 intelhaddata->stream_info.ring_buf_size = ring_buf_size;
639 period_bytes = frames_to_bytes(substream->runtime,
640 substream->runtime->period_size);
641 num_periods = substream->runtime->periods;
642
643 /*
644 * buffer addr should be 64 byte aligned, period bytes
645 * will be used to calculate addr offset
646 */
647 period_bytes &= ~0x3F;
648
649 /* Hardware supports MAX_PERIODS buffers */
650 if (end >= HAD_MAX_PERIODS)
651 return -EINVAL;
652
653 for (i = start; i <= end; i++) {
654 /* Program the buf registers with addr and len */
655 intelhaddata->buf_info[i].buf_addr = ring_buf_addr +
656 (i * period_bytes);
657 if (i < num_periods-1)
658 intelhaddata->buf_info[i].buf_size = period_bytes;
659 else
660 intelhaddata->buf_info[i].buf_size = ring_buf_size -
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100661 (i * period_bytes);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530662
Takashi Iwai79dda752017-01-30 17:23:39 +0100663 had_write_register(intelhaddata,
664 AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH),
Jerome Anand5dab11d2017-01-25 04:27:52 +0530665 intelhaddata->buf_info[i].buf_addr |
666 BIT(0) | BIT(1));
Takashi Iwai79dda752017-01-30 17:23:39 +0100667 had_write_register(intelhaddata,
668 AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
Jerome Anand5dab11d2017-01-25 04:27:52 +0530669 period_bytes);
670 intelhaddata->buf_info[i].is_valid = true;
671 }
Takashi Iwaic75b0472017-01-31 15:49:15 +0100672 dev_dbg(intelhaddata->dev, "%s:buf[%d-%d] addr=%#x and size=%d\n",
673 __func__, start, end,
674 intelhaddata->buf_info[start].buf_addr,
675 intelhaddata->buf_info[start].buf_size);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530676 intelhaddata->valid_buf_cnt = num_periods;
677 return 0;
678}
679
Takashi Iwai372d8552017-01-31 13:57:58 +0100680static int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530681{
682 int i, retval = 0;
683 u32 len[4];
684
685 for (i = 0; i < 4 ; i++) {
Takashi Iwai79dda752017-01-30 17:23:39 +0100686 had_read_register(intelhaddata,
687 AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
688 &len[i]);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530689 if (!len[i])
690 retval++;
691 }
692 if (retval != 1) {
693 for (i = 0; i < 4 ; i++)
Takashi Iwaic75b0472017-01-31 15:49:15 +0100694 dev_dbg(intelhaddata->dev, "buf[%d] size=%d\n",
695 i, len[i]);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530696 }
697
698 return retval;
699}
700
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600701static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate)
702{
703 u32 maud_val;
704
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100705 /* Select maud according to DP 1.2 spec */
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600706 if (link_rate == DP_2_7_GHZ) {
707 switch (aud_samp_freq) {
708 case AUD_SAMPLE_RATE_32:
709 maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL;
710 break;
711
712 case AUD_SAMPLE_RATE_44_1:
713 maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL;
714 break;
715
716 case AUD_SAMPLE_RATE_48:
717 maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL;
718 break;
719
720 case AUD_SAMPLE_RATE_88_2:
721 maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL;
722 break;
723
724 case AUD_SAMPLE_RATE_96:
725 maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL;
726 break;
727
728 case AUD_SAMPLE_RATE_176_4:
729 maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL;
730 break;
731
732 case HAD_MAX_RATE:
733 maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL;
734 break;
735
736 default:
737 maud_val = -EINVAL;
738 break;
739 }
740 } else if (link_rate == DP_1_62_GHZ) {
741 switch (aud_samp_freq) {
742 case AUD_SAMPLE_RATE_32:
743 maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL;
744 break;
745
746 case AUD_SAMPLE_RATE_44_1:
747 maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL;
748 break;
749
750 case AUD_SAMPLE_RATE_48:
751 maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL;
752 break;
753
754 case AUD_SAMPLE_RATE_88_2:
755 maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL;
756 break;
757
758 case AUD_SAMPLE_RATE_96:
759 maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL;
760 break;
761
762 case AUD_SAMPLE_RATE_176_4:
763 maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL;
764 break;
765
766 case HAD_MAX_RATE:
767 maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL;
768 break;
769
770 default:
771 maud_val = -EINVAL;
772 break;
773 }
774 } else
775 maud_val = -EINVAL;
776
777 return maud_val;
778}
779
Takashi Iwai76296ef2017-01-30 16:09:11 +0100780/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100781 * Program HDMI audio CTS value
Jerome Anand5dab11d2017-01-25 04:27:52 +0530782 *
783 * @aud_samp_freq: sampling frequency of audio data
784 * @tmds: sampling frequency of the display data
Takashi Iwaib5562902017-02-04 22:05:33 +0100785 * @link_rate: DP link rate
Jerome Anand5dab11d2017-01-25 04:27:52 +0530786 * @n_param: N value, depends on aud_samp_freq
Takashi Iwaib5562902017-02-04 22:05:33 +0100787 * @intelhaddata: substream private data
Jerome Anand5dab11d2017-01-25 04:27:52 +0530788 *
789 * Program CTS register based on the audio and display sampling frequency
790 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100791static void had_prog_cts(u32 aud_samp_freq, u32 tmds, u32 link_rate,
792 u32 n_param, struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530793{
794 u32 cts_val;
795 u64 dividend, divisor;
796
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600797 if (intelhaddata->dp_output) {
798 /* Substitute cts_val with Maud according to DP 1.2 spec*/
799 cts_val = had_calculate_maud_value(aud_samp_freq, link_rate);
800 } else {
801 /* Calculate CTS according to HDMI 1.3a spec*/
802 dividend = (u64)tmds * n_param*1000;
803 divisor = 128 * aud_samp_freq;
804 cts_val = div64_u64(dividend, divisor);
805 }
Takashi Iwaic75b0472017-01-31 15:49:15 +0100806 dev_dbg(intelhaddata->dev, "TMDS value=%d, N value=%d, CTS Value=%d\n",
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600807 tmds, n_param, cts_val);
Takashi Iwai79dda752017-01-30 17:23:39 +0100808 had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val));
Jerome Anand5dab11d2017-01-25 04:27:52 +0530809}
810
811static int had_calculate_n_value(u32 aud_samp_freq)
812{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100813 int n_val;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530814
815 /* Select N according to HDMI 1.3a spec*/
816 switch (aud_samp_freq) {
817 case AUD_SAMPLE_RATE_32:
818 n_val = 4096;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100819 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530820
821 case AUD_SAMPLE_RATE_44_1:
822 n_val = 6272;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100823 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530824
825 case AUD_SAMPLE_RATE_48:
826 n_val = 6144;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100827 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530828
829 case AUD_SAMPLE_RATE_88_2:
830 n_val = 12544;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100831 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530832
833 case AUD_SAMPLE_RATE_96:
834 n_val = 12288;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100835 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530836
837 case AUD_SAMPLE_RATE_176_4:
838 n_val = 25088;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100839 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530840
841 case HAD_MAX_RATE:
842 n_val = 24576;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100843 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530844
845 default:
846 n_val = -EINVAL;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100847 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530848 }
849 return n_val;
850}
851
Takashi Iwai76296ef2017-01-30 16:09:11 +0100852/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100853 * Program HDMI audio N value
Jerome Anand5dab11d2017-01-25 04:27:52 +0530854 *
855 * @aud_samp_freq: sampling frequency of audio data
856 * @n_param: N value, depends on aud_samp_freq
Takashi Iwaib5562902017-02-04 22:05:33 +0100857 * @intelhaddata: substream private data
Jerome Anand5dab11d2017-01-25 04:27:52 +0530858 *
859 * This function is called in the prepare callback.
860 * It programs based on the audio and display sampling frequency
861 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100862static int had_prog_n(u32 aud_samp_freq, u32 *n_param,
863 struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530864{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100865 int n_val;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530866
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600867 if (intelhaddata->dp_output) {
868 /*
869 * According to DP specs, Maud and Naud values hold
870 * a relationship, which is stated as:
871 * Maud/Naud = 512 * fs / f_LS_Clk
872 * where, fs is the sampling frequency of the audio stream
873 * and Naud is 32768 for Async clock.
874 */
875
876 n_val = DP_NAUD_VAL;
877 } else
878 n_val = had_calculate_n_value(aud_samp_freq);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530879
880 if (n_val < 0)
881 return n_val;
882
Takashi Iwai79dda752017-01-30 17:23:39 +0100883 had_write_register(intelhaddata, AUD_N_ENABLE, (BIT(24) | n_val));
Jerome Anand5dab11d2017-01-25 04:27:52 +0530884 *n_param = n_val;
885 return 0;
886}
887
Takashi Iwai03c34372017-02-02 16:19:03 +0100888#define MAX_CNT 0xFF
889
Takashi Iwai372d8552017-01-31 13:57:58 +0100890static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530891{
Takashi Iwai79f439e2017-01-31 16:46:44 +0100892 u32 hdmi_status = 0, i = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530893
894 /* Handle Underrun interrupt within Audio Unit */
Takashi Iwai79dda752017-01-30 17:23:39 +0100895 had_write_register(intelhaddata, AUD_CONFIG, 0);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530896 /* Reset buffer pointers */
Takashi Iwaif4566aa2017-02-04 21:39:56 +0100897 had_reset_audio(intelhaddata);
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100898 /*
Jerome Anand5dab11d2017-01-25 04:27:52 +0530899 * The interrupt status 'sticky' bits might not be cleared by
900 * setting '1' to that bit once...
901 */
902 do { /* clear bit30, 31 AUD_HDMI_STATUS */
Takashi Iwai4151ee82017-01-31 18:14:15 +0100903 had_read_register(intelhaddata, AUD_HDMI_STATUS,
Takashi Iwai79dda752017-01-30 17:23:39 +0100904 &hdmi_status);
Takashi Iwaic75b0472017-01-31 15:49:15 +0100905 dev_dbg(intelhaddata->dev, "HDMI status =0x%x\n", hdmi_status);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530906 if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
907 i++;
Takashi Iwai79dda752017-01-30 17:23:39 +0100908 had_write_register(intelhaddata,
Takashi Iwai4151ee82017-01-31 18:14:15 +0100909 AUD_HDMI_STATUS, hdmi_status);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530910 } else
911 break;
912 } while (i < MAX_CNT);
913 if (i >= MAX_CNT)
Takashi Iwaic75b0472017-01-31 15:49:15 +0100914 dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n");
Jerome Anand5dab11d2017-01-25 04:27:52 +0530915}
916
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100917/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100918 * ALSA PCM open callback
Jerome Anand5dab11d2017-01-25 04:27:52 +0530919 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100920static int had_pcm_open(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530921{
922 struct snd_intelhad *intelhaddata;
923 struct snd_pcm_runtime *runtime;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530924 int retval;
925
Jerome Anand5dab11d2017-01-25 04:27:52 +0530926 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530927 runtime = substream->runtime;
928
Takashi Iwai182cdf22017-02-02 14:43:39 +0100929 pm_runtime_get_sync(intelhaddata->dev);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530930
Takashi Iwai91b0cb02017-02-02 17:46:49 +0100931 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +0100932 dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n",
933 __func__);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530934 retval = -ENODEV;
Takashi Iwaifa5dfe62017-02-01 22:03:26 +0100935 goto error;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530936 }
937
938 /* set the runtime hw parameter with local snd_pcm_hardware struct */
Takashi Iwaib5562902017-02-04 22:05:33 +0100939 runtime->hw = had_pcm_hardware;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530940
Jerome Anand5dab11d2017-01-25 04:27:52 +0530941 retval = snd_pcm_hw_constraint_integer(runtime,
942 SNDRV_PCM_HW_PARAM_PERIODS);
943 if (retval < 0)
Takashi Iwaifa5dfe62017-02-01 22:03:26 +0100944 goto error;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530945
946 /* Make sure, that the period size is always aligned
947 * 64byte boundary
948 */
949 retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
950 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
Takashi Iwai73997b02017-02-02 17:38:50 +0100951 if (retval < 0)
Takashi Iwaifa5dfe62017-02-01 22:03:26 +0100952 goto error;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530953
Takashi Iwai73997b02017-02-02 17:38:50 +0100954 /* expose PCM substream */
Takashi Iwai313d9f22017-02-02 13:00:12 +0100955 spin_lock_irq(&intelhaddata->had_spinlock);
956 intelhaddata->stream_info.substream = substream;
957 intelhaddata->stream_info.substream_refcount++;
958 spin_unlock_irq(&intelhaddata->had_spinlock);
959
Takashi Iwai73997b02017-02-02 17:38:50 +0100960 /* these are cleared in prepare callback, but just to be sure */
961 intelhaddata->curr_buf = 0;
962 intelhaddata->underrun_count = 0;
963 intelhaddata->stream_info.buffer_rendered = 0;
964
Jerome Anand5dab11d2017-01-25 04:27:52 +0530965 return retval;
Takashi Iwaifa5dfe62017-02-01 22:03:26 +0100966 error:
Jerome Anand5dab11d2017-01-25 04:27:52 +0530967 pm_runtime_put(intelhaddata->dev);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530968 return retval;
969}
970
Takashi Iwaidf76df12017-01-31 16:04:10 +0100971/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100972 * ALSA PCM close callback
Jerome Anand5dab11d2017-01-25 04:27:52 +0530973 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100974static int had_pcm_close(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530975{
976 struct snd_intelhad *intelhaddata;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530977
Jerome Anand5dab11d2017-01-25 04:27:52 +0530978 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530979
Takashi Iwai73997b02017-02-02 17:38:50 +0100980 /* unreference and sync with the pending PCM accesses */
Takashi Iwai313d9f22017-02-02 13:00:12 +0100981 spin_lock_irq(&intelhaddata->had_spinlock);
982 intelhaddata->stream_info.substream = NULL;
983 intelhaddata->stream_info.substream_refcount--;
984 while (intelhaddata->stream_info.substream_refcount > 0) {
985 spin_unlock_irq(&intelhaddata->had_spinlock);
986 cpu_relax();
987 spin_lock_irq(&intelhaddata->had_spinlock);
988 }
989 spin_unlock_irq(&intelhaddata->had_spinlock);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530990
Jerome Anand5dab11d2017-01-25 04:27:52 +0530991 pm_runtime_put(intelhaddata->dev);
992 return 0;
993}
994
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100995/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100996 * ALSA PCM hw_params callback
Jerome Anand5dab11d2017-01-25 04:27:52 +0530997 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100998static int had_pcm_hw_params(struct snd_pcm_substream *substream,
999 struct snd_pcm_hw_params *hw_params)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301000{
Takashi Iwaic75b0472017-01-31 15:49:15 +01001001 struct snd_intelhad *intelhaddata;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301002 unsigned long addr;
1003 int pages, buf_size, retval;
1004
Takashi Iwaic75b0472017-01-31 15:49:15 +01001005 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301006 buf_size = params_buffer_bytes(hw_params);
1007 retval = snd_pcm_lib_malloc_pages(substream, buf_size);
1008 if (retval < 0)
1009 return retval;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001010 dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n",
1011 __func__, buf_size);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301012 /* mark the pages as uncached region */
1013 addr = (unsigned long) substream->runtime->dma_area;
1014 pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
1015 retval = set_memory_uc(addr, pages);
1016 if (retval) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001017 dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n",
1018 retval);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301019 return retval;
1020 }
1021 memset(substream->runtime->dma_area, 0, buf_size);
1022
1023 return retval;
1024}
1025
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001026/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001027 * ALSA PCM hw_free callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301028 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001029static int had_pcm_hw_free(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301030{
1031 unsigned long addr;
1032 u32 pages;
1033
Jerome Anand5dab11d2017-01-25 04:27:52 +05301034 /* mark back the pages as cached/writeback region before the free */
1035 if (substream->runtime->dma_area != NULL) {
1036 addr = (unsigned long) substream->runtime->dma_area;
1037 pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
1038 PAGE_SIZE;
1039 set_memory_wb(addr, pages);
1040 return snd_pcm_lib_free_pages(substream);
1041 }
1042 return 0;
1043}
1044
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001045/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001046 * ALSA PCM trigger callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301047 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001048static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301049{
Takashi Iwaida864802017-01-31 13:52:22 +01001050 int retval = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301051 struct snd_intelhad *intelhaddata;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301052
Jerome Anand5dab11d2017-01-25 04:27:52 +05301053 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301054
1055 switch (cmd) {
1056 case SNDRV_PCM_TRIGGER_START:
Takashi Iwai182cdf22017-02-02 14:43:39 +01001057 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1058 case SNDRV_PCM_TRIGGER_RESUME:
Jerome Anand5dab11d2017-01-25 04:27:52 +05301059 /* Disable local INTRs till register prgmng is done */
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001060 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001061 dev_dbg(intelhaddata->dev,
1062 "_START: HDMI cable plugged-out\n");
Jerome Anand5dab11d2017-01-25 04:27:52 +05301063 retval = -ENODEV;
1064 break;
1065 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301066
Takashi Iwaif69bd102017-02-02 14:57:22 +01001067 intelhaddata->stream_info.running = true;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301068
1069 /* Enable Audio */
Takashi Iwaib5562902017-02-04 22:05:33 +01001070 had_enable_audio_int(intelhaddata, true);
1071 had_enable_audio(substream, intelhaddata, true);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301072 break;
1073
1074 case SNDRV_PCM_TRIGGER_STOP:
Takashi Iwai182cdf22017-02-02 14:43:39 +01001075 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1076 case SNDRV_PCM_TRIGGER_SUSPEND:
Takashi Iwaibcce7752017-02-01 17:18:20 +01001077 spin_lock(&intelhaddata->had_spinlock);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301078
Takashi Iwaic75b0472017-01-31 15:49:15 +01001079 /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */
Jerome Anand5dab11d2017-01-25 04:27:52 +05301080
Takashi Iwaif69bd102017-02-02 14:57:22 +01001081 intelhaddata->stream_info.running = false;
Takashi Iwaibcce7752017-02-01 17:18:20 +01001082 spin_unlock(&intelhaddata->had_spinlock);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301083 /* Disable Audio */
Takashi Iwaib5562902017-02-04 22:05:33 +01001084 had_enable_audio_int(intelhaddata, false);
1085 had_enable_audio(substream, intelhaddata, false);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301086 /* Reset buffer pointers */
Takashi Iwaif4566aa2017-02-04 21:39:56 +01001087 had_reset_audio(intelhaddata);
Takashi Iwaib5562902017-02-04 22:05:33 +01001088 had_enable_audio_int(intelhaddata, false);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301089 break;
1090
1091 default:
1092 retval = -EINVAL;
1093 }
1094 return retval;
1095}
1096
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001097/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001098 * ALSA PCM prepare callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301099 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001100static int had_pcm_prepare(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301101{
1102 int retval;
1103 u32 disp_samp_freq, n_param;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001104 u32 link_rate = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301105 struct snd_intelhad *intelhaddata;
1106 struct snd_pcm_runtime *runtime;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301107
Jerome Anand5dab11d2017-01-25 04:27:52 +05301108 intelhaddata = snd_pcm_substream_chip(substream);
1109 runtime = substream->runtime;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301110
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001111 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001112 dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n",
1113 __func__);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301114 retval = -ENODEV;
1115 goto prep_end;
1116 }
1117
Takashi Iwaic75b0472017-01-31 15:49:15 +01001118 dev_dbg(intelhaddata->dev, "period_size=%d\n",
Jerome Anand5dab11d2017-01-25 04:27:52 +05301119 (int)frames_to_bytes(runtime, runtime->period_size));
Takashi Iwaic75b0472017-01-31 15:49:15 +01001120 dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods);
1121 dev_dbg(intelhaddata->dev, "buffer_size=%d\n",
1122 (int)snd_pcm_lib_buffer_bytes(substream));
1123 dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate);
1124 dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301125
Takashi Iwai73997b02017-02-02 17:38:50 +01001126 intelhaddata->curr_buf = 0;
1127 intelhaddata->underrun_count = 0;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001128 intelhaddata->stream_info.buffer_rendered = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301129
1130 /* Get N value in KHz */
Takashi Iwaida864802017-01-31 13:52:22 +01001131 disp_samp_freq = intelhaddata->tmds_clock_speed;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301132
Takashi Iwaib5562902017-02-04 22:05:33 +01001133 retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301134 if (retval) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001135 dev_err(intelhaddata->dev,
1136 "programming N value failed %#x\n", retval);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301137 goto prep_end;
1138 }
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001139
1140 if (intelhaddata->dp_output)
Takashi Iwaida864802017-01-31 13:52:22 +01001141 link_rate = intelhaddata->link_rate;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001142
Takashi Iwaib5562902017-02-04 22:05:33 +01001143 had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
1144 n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301145
Takashi Iwaib5562902017-02-04 22:05:33 +01001146 had_prog_dip(substream, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301147
Takashi Iwaib5562902017-02-04 22:05:33 +01001148 retval = had_init_audio_ctrl(substream, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301149
1150 /* Prog buffer address */
Takashi Iwai313d9f22017-02-02 13:00:12 +01001151 retval = snd_intelhad_prog_buffer(substream, intelhaddata,
Jerome Anand5dab11d2017-01-25 04:27:52 +05301152 HAD_BUF_TYPE_A, HAD_BUF_TYPE_D);
1153
1154 /*
1155 * Program channel mapping in following order:
1156 * FL, FR, C, LFE, RL, RR
1157 */
1158
Takashi Iwai79dda752017-01-30 17:23:39 +01001159 had_write_register(intelhaddata, AUD_BUF_CH_SWAP, SWAP_LFE_CENTER);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301160
1161prep_end:
1162 return retval;
1163}
1164
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001165/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001166 * ALSA PCM pointer callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301167 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001168static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301169{
1170 struct snd_intelhad *intelhaddata;
1171 u32 bytes_rendered = 0;
1172 u32 t;
1173 int buf_id;
1174
Jerome Anand5dab11d2017-01-25 04:27:52 +05301175 intelhaddata = snd_pcm_substream_chip(substream);
1176
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001177 if (!intelhaddata->connected)
Takashi Iwai79f439e2017-01-31 16:46:44 +01001178 return SNDRV_PCM_POS_XRUN;
1179
Jerome Anand5dab11d2017-01-25 04:27:52 +05301180 /* Use a hw register to calculate sub-period position reports.
1181 * This makes PulseAudio happier.
1182 */
1183
1184 buf_id = intelhaddata->curr_buf % 4;
Takashi Iwai79dda752017-01-30 17:23:39 +01001185 had_read_register(intelhaddata,
1186 AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t);
Jerome Anand232892f2017-01-25 04:27:53 +05301187
1188 if ((t == 0) || (t == ((u32)-1L))) {
Takashi Iwai6ddb3ab2017-01-30 18:17:44 +01001189 intelhaddata->underrun_count++;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001190 dev_dbg(intelhaddata->dev,
1191 "discovered buffer done for buf %d, count = %d\n",
Takashi Iwai6ddb3ab2017-01-30 18:17:44 +01001192 buf_id, intelhaddata->underrun_count);
Jerome Anand232892f2017-01-25 04:27:53 +05301193
Takashi Iwai6ddb3ab2017-01-30 18:17:44 +01001194 if (intelhaddata->underrun_count > (HAD_MIN_PERIODS/2)) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001195 dev_dbg(intelhaddata->dev,
1196 "assume audio_codec_reset, underrun = %d - do xrun\n",
Takashi Iwai6ddb3ab2017-01-30 18:17:44 +01001197 intelhaddata->underrun_count);
Jerome Anand232892f2017-01-25 04:27:53 +05301198 return SNDRV_PCM_POS_XRUN;
1199 }
1200 } else {
1201 /* Reset Counter */
Takashi Iwai6ddb3ab2017-01-30 18:17:44 +01001202 intelhaddata->underrun_count = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301203 }
Jerome Anand232892f2017-01-25 04:27:53 +05301204
Jerome Anand5dab11d2017-01-25 04:27:52 +05301205 t = intelhaddata->buf_info[buf_id].buf_size - t;
1206
1207 if (intelhaddata->stream_info.buffer_rendered)
1208 div_u64_rem(intelhaddata->stream_info.buffer_rendered,
1209 intelhaddata->stream_info.ring_buf_size,
1210 &(bytes_rendered));
1211
Takashi Iwai7d9e7982017-02-01 22:25:58 +01001212 return bytes_to_frames(substream->runtime, bytes_rendered + t);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301213}
1214
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001215/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001216 * ALSA PCM mmap callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301217 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001218static int had_pcm_mmap(struct snd_pcm_substream *substream,
1219 struct vm_area_struct *vma)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301220{
Jerome Anand5dab11d2017-01-25 04:27:52 +05301221 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
1222 return remap_pfn_range(vma, vma->vm_start,
1223 substream->dma_buffer.addr >> PAGE_SHIFT,
1224 vma->vm_end - vma->vm_start, vma->vm_page_prot);
1225}
1226
Takashi Iwai73997b02017-02-02 17:38:50 +01001227/*
1228 * ALSA PCM ops
1229 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001230static const struct snd_pcm_ops had_pcm_ops = {
1231 .open = had_pcm_open,
1232 .close = had_pcm_close,
Takashi Iwai73997b02017-02-02 17:38:50 +01001233 .ioctl = snd_pcm_lib_ioctl,
Takashi Iwaib5562902017-02-04 22:05:33 +01001234 .hw_params = had_pcm_hw_params,
1235 .hw_free = had_pcm_hw_free,
1236 .prepare = had_pcm_prepare,
1237 .trigger = had_pcm_trigger,
1238 .pointer = had_pcm_pointer,
1239 .mmap = had_pcm_mmap,
Takashi Iwai73997b02017-02-02 17:38:50 +01001240};
1241
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001242/* process mode change of the running stream; called in mutex */
Takashi Iwaib5562902017-02-04 22:05:33 +01001243static int had_process_mode_change(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301244{
Takashi Iwaida864802017-01-31 13:52:22 +01001245 struct snd_pcm_substream *substream;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301246 int retval = 0;
1247 u32 disp_samp_freq, n_param;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001248 u32 link_rate = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301249
Takashi Iwai313d9f22017-02-02 13:00:12 +01001250 substream = had_substream_get(intelhaddata);
1251 if (!substream)
Takashi Iwaida864802017-01-31 13:52:22 +01001252 return 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301253
1254 /* Disable Audio */
Takashi Iwaib5562902017-02-04 22:05:33 +01001255 had_enable_audio(substream, intelhaddata, false);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301256
1257 /* Update CTS value */
Takashi Iwaida864802017-01-31 13:52:22 +01001258 disp_samp_freq = intelhaddata->tmds_clock_speed;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301259
Takashi Iwaib5562902017-02-04 22:05:33 +01001260 retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301261 if (retval) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001262 dev_err(intelhaddata->dev,
1263 "programming N value failed %#x\n", retval);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301264 goto out;
1265 }
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001266
1267 if (intelhaddata->dp_output)
Takashi Iwaida864802017-01-31 13:52:22 +01001268 link_rate = intelhaddata->link_rate;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001269
Takashi Iwaib5562902017-02-04 22:05:33 +01001270 had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
1271 n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301272
1273 /* Enable Audio */
Takashi Iwaib5562902017-02-04 22:05:33 +01001274 had_enable_audio(substream, intelhaddata, true);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301275
1276out:
Takashi Iwai313d9f22017-02-02 13:00:12 +01001277 had_substream_put(intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301278 return retval;
1279}
1280
Takashi Iwai372d8552017-01-31 13:57:58 +01001281static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata,
1282 enum intel_had_aud_buf_type buf_id)
1283{
1284 int i, intr_count = 0;
1285 enum intel_had_aud_buf_type buff_done;
1286 u32 buf_size, buf_addr;
Takashi Iwai372d8552017-01-31 13:57:58 +01001287
1288 buff_done = buf_id;
1289
1290 intr_count = snd_intelhad_read_len(intelhaddata);
1291 if (intr_count > 1) {
1292 /* In case of active playback */
Takashi Iwaic75b0472017-01-31 15:49:15 +01001293 dev_err(intelhaddata->dev,
1294 "Driver detected %d missed buffer done interrupt(s)\n",
1295 (intr_count - 1));
Takashi Iwai372d8552017-01-31 13:57:58 +01001296 if (intr_count > 3)
1297 return intr_count;
1298
1299 buf_id += (intr_count - 1);
1300 /* Reprogram registers*/
1301 for (i = buff_done; i < buf_id; i++) {
1302 int j = i % 4;
1303
1304 buf_size = intelhaddata->buf_info[j].buf_size;
1305 buf_addr = intelhaddata->buf_info[j].buf_addr;
1306 had_write_register(intelhaddata,
1307 AUD_BUF_A_LENGTH +
1308 (j * HAD_REG_WIDTH), buf_size);
1309 had_write_register(intelhaddata,
1310 AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH),
1311 (buf_addr | BIT(0) | BIT(1)));
1312 }
1313 buf_id = buf_id % 4;
Takashi Iwai372d8552017-01-31 13:57:58 +01001314 intelhaddata->buff_done = buf_id;
Takashi Iwai372d8552017-01-31 13:57:58 +01001315 }
1316
1317 return intr_count;
1318}
1319
Takashi Iwaibcce7752017-02-01 17:18:20 +01001320/* called from irq handler */
Takashi Iwai372d8552017-01-31 13:57:58 +01001321static int had_process_buffer_done(struct snd_intelhad *intelhaddata)
1322{
1323 u32 len = 1;
1324 enum intel_had_aud_buf_type buf_id;
1325 enum intel_had_aud_buf_type buff_done;
1326 struct pcm_stream_info *stream;
Takashi Iwai313d9f22017-02-02 13:00:12 +01001327 struct snd_pcm_substream *substream;
Takashi Iwai372d8552017-01-31 13:57:58 +01001328 u32 buf_size;
Takashi Iwai372d8552017-01-31 13:57:58 +01001329 int intr_count;
Takashi Iwaibcce7752017-02-01 17:18:20 +01001330 unsigned long flags;
Takashi Iwai372d8552017-01-31 13:57:58 +01001331
Takashi Iwai372d8552017-01-31 13:57:58 +01001332 stream = &intelhaddata->stream_info;
1333 intr_count = 1;
1334
Takashi Iwaibcce7752017-02-01 17:18:20 +01001335 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001336 if (!intelhaddata->connected) {
Takashi Iwaibcce7752017-02-01 17:18:20 +01001337 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
Takashi Iwaic75b0472017-01-31 15:49:15 +01001338 dev_dbg(intelhaddata->dev,
1339 "%s:Device already disconnected\n", __func__);
Takashi Iwai372d8552017-01-31 13:57:58 +01001340 return 0;
1341 }
1342 buf_id = intelhaddata->curr_buf;
1343 intelhaddata->buff_done = buf_id;
1344 buff_done = intelhaddata->buff_done;
1345 buf_size = intelhaddata->buf_info[buf_id].buf_size;
Takashi Iwai372d8552017-01-31 13:57:58 +01001346
Takashi Iwai372d8552017-01-31 13:57:58 +01001347 /* Every debug statement has an implication
1348 * of ~5msec. Thus, avoid having >3 debug statements
1349 * for each buffer_done handling.
1350 */
1351
1352 /* Check for any intr_miss in case of active playback */
Takashi Iwaif69bd102017-02-02 14:57:22 +01001353 if (stream->running) {
Takashi Iwai372d8552017-01-31 13:57:58 +01001354 intr_count = had_chk_intrmiss(intelhaddata, buf_id);
1355 if (!intr_count || (intr_count > 3)) {
Takashi Iwaibcce7752017-02-01 17:18:20 +01001356 spin_unlock_irqrestore(&intelhaddata->had_spinlock,
1357 flags);
Takashi Iwaic75b0472017-01-31 15:49:15 +01001358 dev_err(intelhaddata->dev,
1359 "HAD SW state in non-recoverable mode\n");
Takashi Iwai372d8552017-01-31 13:57:58 +01001360 return 0;
1361 }
1362 buf_id += (intr_count - 1);
1363 buf_id = buf_id % 4;
Takashi Iwai372d8552017-01-31 13:57:58 +01001364 }
1365
1366 intelhaddata->buf_info[buf_id].is_valid = true;
1367 if (intelhaddata->valid_buf_cnt-1 == buf_id) {
Takashi Iwaif69bd102017-02-02 14:57:22 +01001368 if (stream->running)
Takashi Iwai372d8552017-01-31 13:57:58 +01001369 intelhaddata->curr_buf = HAD_BUF_TYPE_A;
1370 } else
1371 intelhaddata->curr_buf = buf_id + 1;
1372
Takashi Iwaibcce7752017-02-01 17:18:20 +01001373 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
Takashi Iwai372d8552017-01-31 13:57:58 +01001374
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001375 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001376 dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n");
Takashi Iwai372d8552017-01-31 13:57:58 +01001377 return 0;
1378 }
1379
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001380 /* Reprogram the registers with addr and length */
Takashi Iwai372d8552017-01-31 13:57:58 +01001381 had_write_register(intelhaddata,
1382 AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH),
1383 buf_size);
1384 had_write_register(intelhaddata,
1385 AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH),
1386 intelhaddata->buf_info[buf_id].buf_addr |
1387 BIT(0) | BIT(1));
1388
1389 had_read_register(intelhaddata,
1390 AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH),
1391 &len);
Takashi Iwaic75b0472017-01-31 15:49:15 +01001392 dev_dbg(intelhaddata->dev, "%s:Enabled buf[%d]\n", __func__, buf_id);
Takashi Iwai372d8552017-01-31 13:57:58 +01001393
1394 /* In case of actual data,
1395 * report buffer_done to above ALSA layer
1396 */
Takashi Iwai313d9f22017-02-02 13:00:12 +01001397 substream = had_substream_get(intelhaddata);
1398 if (substream) {
1399 buf_size = intelhaddata->buf_info[buf_id].buf_size;
Takashi Iwai372d8552017-01-31 13:57:58 +01001400 intelhaddata->stream_info.buffer_rendered +=
1401 (intr_count * buf_size);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001402 snd_pcm_period_elapsed(substream);
1403 had_substream_put(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001404 }
1405
1406 return 0;
1407}
1408
Takashi Iwaibcce7752017-02-01 17:18:20 +01001409/* called from irq handler */
Takashi Iwai372d8552017-01-31 13:57:58 +01001410static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
1411{
1412 enum intel_had_aud_buf_type buf_id;
1413 struct pcm_stream_info *stream;
Takashi Iwai313d9f22017-02-02 13:00:12 +01001414 struct snd_pcm_substream *substream;
Takashi Iwaibcce7752017-02-01 17:18:20 +01001415 unsigned long flags;
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001416 int connected;
Takashi Iwai372d8552017-01-31 13:57:58 +01001417
Takashi Iwai372d8552017-01-31 13:57:58 +01001418 stream = &intelhaddata->stream_info;
1419
Takashi Iwaibcce7752017-02-01 17:18:20 +01001420 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
Takashi Iwai372d8552017-01-31 13:57:58 +01001421 buf_id = intelhaddata->curr_buf;
Takashi Iwai372d8552017-01-31 13:57:58 +01001422 intelhaddata->buff_done = buf_id;
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001423 connected = intelhaddata->connected;
Takashi Iwaif69bd102017-02-02 14:57:22 +01001424 if (stream->running)
Takashi Iwai372d8552017-01-31 13:57:58 +01001425 intelhaddata->curr_buf = HAD_BUF_TYPE_A;
1426
Takashi Iwaibcce7752017-02-01 17:18:20 +01001427 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
Takashi Iwai372d8552017-01-31 13:57:58 +01001428
Takashi Iwaif69bd102017-02-02 14:57:22 +01001429 dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_running=%d\n",
1430 __func__, buf_id, stream->running);
Takashi Iwai372d8552017-01-31 13:57:58 +01001431
1432 snd_intelhad_handle_underrun(intelhaddata);
1433
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001434 if (!connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001435 dev_dbg(intelhaddata->dev,
1436 "%s:Device already disconnected\n", __func__);
Takashi Iwai372d8552017-01-31 13:57:58 +01001437 return 0;
1438 }
1439
Takashi Iwaif69bd102017-02-02 14:57:22 +01001440 /* Report UNDERRUN error to above layers */
1441 substream = had_substream_get(intelhaddata);
1442 if (substream) {
1443 snd_pcm_stop_xrun(substream);
1444 had_substream_put(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001445 }
1446
1447 return 0;
1448}
1449
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001450/* process hot plug, called from wq with mutex locked */
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001451static void had_process_hot_plug(struct snd_intelhad *intelhaddata)
Takashi Iwai372d8552017-01-31 13:57:58 +01001452{
1453 enum intel_had_aud_buf_type buf_id;
1454 struct snd_pcm_substream *substream;
Takashi Iwai372d8552017-01-31 13:57:58 +01001455
Takashi Iwaibcce7752017-02-01 17:18:20 +01001456 spin_lock_irq(&intelhaddata->had_spinlock);
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001457 if (intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001458 dev_dbg(intelhaddata->dev, "Device already connected\n");
Takashi Iwaibcce7752017-02-01 17:18:20 +01001459 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001460 return;
Takashi Iwai372d8552017-01-31 13:57:58 +01001461 }
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001462
Takashi Iwai372d8552017-01-31 13:57:58 +01001463 buf_id = intelhaddata->curr_buf;
1464 intelhaddata->buff_done = buf_id;
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001465 intelhaddata->connected = true;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001466 dev_dbg(intelhaddata->dev,
1467 "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
Takashi Iwai372d8552017-01-31 13:57:58 +01001468 __func__, __LINE__);
Takashi Iwaibcce7752017-02-01 17:18:20 +01001469 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai372d8552017-01-31 13:57:58 +01001470
Takashi Iwaic75b0472017-01-31 15:49:15 +01001471 dev_dbg(intelhaddata->dev, "Processing HOT_PLUG, buf_id = %d\n",
1472 buf_id);
Takashi Iwai372d8552017-01-31 13:57:58 +01001473
1474 /* Safety check */
Takashi Iwai313d9f22017-02-02 13:00:12 +01001475 substream = had_substream_get(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001476 if (substream) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001477 dev_dbg(intelhaddata->dev,
1478 "Force to stop the active stream by disconnection\n");
Takashi Iwai372d8552017-01-31 13:57:58 +01001479 /* Set runtime->state to hw_params done */
1480 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001481 had_substream_put(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001482 }
1483
1484 had_build_channel_allocation_map(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001485}
1486
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001487/* process hot unplug, called from wq with mutex locked */
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001488static void had_process_hot_unplug(struct snd_intelhad *intelhaddata)
Takashi Iwai372d8552017-01-31 13:57:58 +01001489{
1490 enum intel_had_aud_buf_type buf_id;
Takashi Iwai313d9f22017-02-02 13:00:12 +01001491 struct snd_pcm_substream *substream;
Takashi Iwai372d8552017-01-31 13:57:58 +01001492
Takashi Iwai372d8552017-01-31 13:57:58 +01001493 buf_id = intelhaddata->curr_buf;
1494
Takashi Iwai313d9f22017-02-02 13:00:12 +01001495 substream = had_substream_get(intelhaddata);
1496
Takashi Iwaibcce7752017-02-01 17:18:20 +01001497 spin_lock_irq(&intelhaddata->had_spinlock);
Takashi Iwai372d8552017-01-31 13:57:58 +01001498
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001499 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001500 dev_dbg(intelhaddata->dev, "Device already disconnected\n");
Takashi Iwaibcce7752017-02-01 17:18:20 +01001501 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001502 goto out;
Takashi Iwai372d8552017-01-31 13:57:58 +01001503
Takashi Iwai372d8552017-01-31 13:57:58 +01001504 }
1505
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001506 /* Disable Audio */
Takashi Iwaib5562902017-02-04 22:05:33 +01001507 had_enable_audio_int(intelhaddata, false);
1508 had_enable_audio(substream, intelhaddata, false);
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001509
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001510 intelhaddata->connected = false;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001511 dev_dbg(intelhaddata->dev,
1512 "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n",
Takashi Iwai372d8552017-01-31 13:57:58 +01001513 __func__, __LINE__);
Takashi Iwaibcce7752017-02-01 17:18:20 +01001514 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001515
1516 /* Report to above ALSA layer */
1517 if (substream)
1518 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
1519
1520 out:
1521 if (substream)
1522 had_substream_put(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001523 kfree(intelhaddata->chmap->chmap);
1524 intelhaddata->chmap->chmap = NULL;
Takashi Iwai372d8552017-01-31 13:57:58 +01001525}
1526
Takashi Iwai73997b02017-02-02 17:38:50 +01001527/*
1528 * ALSA iec958 and ELD controls
1529 */
Jerome Anand5dab11d2017-01-25 04:27:52 +05301530
Jerome Anand5dab11d2017-01-25 04:27:52 +05301531static int had_iec958_info(struct snd_kcontrol *kcontrol,
1532 struct snd_ctl_elem_info *uinfo)
1533{
1534 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1535 uinfo->count = 1;
1536 return 0;
1537}
1538
1539static int had_iec958_get(struct snd_kcontrol *kcontrol,
1540 struct snd_ctl_elem_value *ucontrol)
1541{
1542 struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
1543
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001544 mutex_lock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301545 ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff;
1546 ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff;
1547 ucontrol->value.iec958.status[2] =
1548 (intelhaddata->aes_bits >> 16) & 0xff;
1549 ucontrol->value.iec958.status[3] =
1550 (intelhaddata->aes_bits >> 24) & 0xff;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001551 mutex_unlock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301552 return 0;
1553}
Takashi Iwai372d8552017-01-31 13:57:58 +01001554
Jerome Anand5dab11d2017-01-25 04:27:52 +05301555static int had_iec958_mask_get(struct snd_kcontrol *kcontrol,
1556 struct snd_ctl_elem_value *ucontrol)
1557{
1558 ucontrol->value.iec958.status[0] = 0xff;
1559 ucontrol->value.iec958.status[1] = 0xff;
1560 ucontrol->value.iec958.status[2] = 0xff;
1561 ucontrol->value.iec958.status[3] = 0xff;
1562 return 0;
1563}
Takashi Iwai372d8552017-01-31 13:57:58 +01001564
Jerome Anand5dab11d2017-01-25 04:27:52 +05301565static int had_iec958_put(struct snd_kcontrol *kcontrol,
1566 struct snd_ctl_elem_value *ucontrol)
1567{
1568 unsigned int val;
1569 struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001570 int changed = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301571
Jerome Anand5dab11d2017-01-25 04:27:52 +05301572 val = (ucontrol->value.iec958.status[0] << 0) |
1573 (ucontrol->value.iec958.status[1] << 8) |
1574 (ucontrol->value.iec958.status[2] << 16) |
1575 (ucontrol->value.iec958.status[3] << 24);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001576 mutex_lock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301577 if (intelhaddata->aes_bits != val) {
1578 intelhaddata->aes_bits = val;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001579 changed = 1;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301580 }
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001581 mutex_unlock(&intelhaddata->mutex);
1582 return changed;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301583}
1584
Takashi Iwai4aedb942017-02-02 16:38:39 +01001585static int had_ctl_eld_info(struct snd_kcontrol *kcontrol,
1586 struct snd_ctl_elem_info *uinfo)
1587{
1588 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1589 uinfo->count = HDMI_MAX_ELD_BYTES;
1590 return 0;
1591}
1592
1593static int had_ctl_eld_get(struct snd_kcontrol *kcontrol,
1594 struct snd_ctl_elem_value *ucontrol)
1595{
1596 struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
1597
1598 mutex_lock(&intelhaddata->mutex);
1599 memcpy(ucontrol->value.bytes.data, intelhaddata->eld,
1600 HDMI_MAX_ELD_BYTES);
1601 mutex_unlock(&intelhaddata->mutex);
1602 return 0;
1603}
1604
Takashi Iwai73997b02017-02-02 17:38:50 +01001605static const struct snd_kcontrol_new had_controls[] = {
Takashi Iwai4aedb942017-02-02 16:38:39 +01001606 {
1607 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1608 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1609 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
1610 .info = had_iec958_info, /* shared */
1611 .get = had_iec958_mask_get,
1612 },
1613 {
1614 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1615 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
1616 .info = had_iec958_info,
1617 .get = had_iec958_get,
1618 .put = had_iec958_put,
1619 },
1620 {
1621 .access = (SNDRV_CTL_ELEM_ACCESS_READ |
1622 SNDRV_CTL_ELEM_ACCESS_VOLATILE),
1623 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1624 .name = "ELD",
1625 .info = had_ctl_eld_info,
1626 .get = had_ctl_eld_get,
1627 },
Jerome Anand5dab11d2017-01-25 04:27:52 +05301628};
1629
Takashi Iwai73997b02017-02-02 17:38:50 +01001630/*
1631 * audio interrupt handler
1632 */
Takashi Iwaida864802017-01-31 13:52:22 +01001633static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
1634{
1635 struct snd_intelhad *ctx = dev_id;
1636 u32 audio_stat, audio_reg;
1637
Takashi Iwai4151ee82017-01-31 18:14:15 +01001638 audio_reg = AUD_HDMI_STATUS;
Takashi Iwai83af57d2017-02-03 08:50:06 +01001639 had_read_register(ctx, audio_reg, &audio_stat);
Takashi Iwaida864802017-01-31 13:52:22 +01001640
1641 if (audio_stat & HDMI_AUDIO_UNDERRUN) {
Takashi Iwai83af57d2017-02-03 08:50:06 +01001642 had_write_register(ctx, audio_reg, HDMI_AUDIO_UNDERRUN);
Takashi Iwaida864802017-01-31 13:52:22 +01001643 had_process_buffer_underrun(ctx);
1644 }
1645
1646 if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
Takashi Iwai83af57d2017-02-03 08:50:06 +01001647 had_write_register(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE);
Takashi Iwaida864802017-01-31 13:52:22 +01001648 had_process_buffer_done(ctx);
1649 }
1650
1651 return IRQ_HANDLED;
1652}
1653
Takashi Iwai73997b02017-02-02 17:38:50 +01001654/*
1655 * monitor plug/unplug notification from i915; just kick off the work
1656 */
Takashi Iwaida864802017-01-31 13:52:22 +01001657static void notify_audio_lpe(struct platform_device *pdev)
1658{
1659 struct snd_intelhad *ctx = platform_get_drvdata(pdev);
Takashi Iwaida864802017-01-31 13:52:22 +01001660
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001661 schedule_work(&ctx->hdmi_audio_wq);
1662}
Takashi Iwaida864802017-01-31 13:52:22 +01001663
Takashi Iwai73997b02017-02-02 17:38:50 +01001664/* the work to handle monitor hot plug/unplug */
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001665static void had_audio_wq(struct work_struct *work)
1666{
1667 struct snd_intelhad *ctx =
1668 container_of(work, struct snd_intelhad, hdmi_audio_wq);
1669 struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data;
1670
Takashi Iwai182cdf22017-02-02 14:43:39 +01001671 pm_runtime_get_sync(ctx->dev);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001672 mutex_lock(&ctx->mutex);
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001673 if (!pdata->hdmi_connected) {
1674 dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
Takashi Iwaida864802017-01-31 13:52:22 +01001675 __func__);
Takashi Iwai4aedb942017-02-02 16:38:39 +01001676 memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001677 had_process_hot_unplug(ctx);
Takashi Iwaida864802017-01-31 13:52:22 +01001678 } else {
1679 struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
1680
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001681 dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
1682 __func__, eld->port_id, pdata->tmds_clock_speed);
1683
Takashi Iwaida864802017-01-31 13:52:22 +01001684 switch (eld->pipe_id) {
1685 case 0:
1686 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
1687 break;
1688 case 1:
1689 ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
1690 break;
1691 case 2:
1692 ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
1693 break;
1694 default:
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001695 dev_dbg(ctx->dev, "Invalid pipe %d\n",
Takashi Iwaida864802017-01-31 13:52:22 +01001696 eld->pipe_id);
1697 break;
1698 }
1699
Takashi Iwaidf0435d2017-02-02 15:37:11 +01001700 memcpy(ctx->eld, eld->eld_data, sizeof(ctx->eld));
Takashi Iwaida864802017-01-31 13:52:22 +01001701
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001702 ctx->dp_output = pdata->dp_output;
1703 ctx->tmds_clock_speed = pdata->tmds_clock_speed;
1704 ctx->link_rate = pdata->link_rate;
1705
Takashi Iwaida864802017-01-31 13:52:22 +01001706 had_process_hot_plug(ctx);
1707
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001708 /* Process mode change if stream is active */
Takashi Iwaib5562902017-02-04 22:05:33 +01001709 had_process_mode_change(ctx);
Takashi Iwaida864802017-01-31 13:52:22 +01001710 }
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001711 mutex_unlock(&ctx->mutex);
Takashi Iwai182cdf22017-02-02 14:43:39 +01001712 pm_runtime_put(ctx->dev);
1713}
1714
1715/*
1716 * PM callbacks
1717 */
1718
1719static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
1720{
1721 struct snd_intelhad *ctx = dev_get_drvdata(dev);
1722 struct snd_pcm_substream *substream;
1723
1724 substream = had_substream_get(ctx);
1725 if (substream) {
1726 snd_pcm_suspend(substream);
1727 had_substream_put(ctx);
1728 }
1729
1730 return 0;
1731}
1732
1733static int hdmi_lpe_audio_suspend(struct device *dev)
1734{
1735 struct snd_intelhad *ctx = dev_get_drvdata(dev);
1736 int err;
1737
1738 err = hdmi_lpe_audio_runtime_suspend(dev);
1739 if (!err)
1740 snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D3hot);
1741 return err;
1742}
1743
1744static int hdmi_lpe_audio_resume(struct device *dev)
1745{
1746 struct snd_intelhad *ctx = dev_get_drvdata(dev);
1747
1748 snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D0);
1749 return 0;
Takashi Iwaida864802017-01-31 13:52:22 +01001750}
1751
1752/* release resources */
1753static void hdmi_lpe_audio_free(struct snd_card *card)
1754{
1755 struct snd_intelhad *ctx = card->private_data;
1756
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001757 cancel_work_sync(&ctx->hdmi_audio_wq);
1758
Takashi Iwaida864802017-01-31 13:52:22 +01001759 if (ctx->mmio_start)
1760 iounmap(ctx->mmio_start);
1761 if (ctx->irq >= 0)
1762 free_irq(ctx->irq, ctx);
1763}
1764
1765/*
1766 * hdmi_lpe_audio_probe - start bridge with i915
1767 *
1768 * This function is called when the i915 driver creates the
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001769 * hdmi-lpe-audio platform device.
Takashi Iwaida864802017-01-31 13:52:22 +01001770 */
1771static int hdmi_lpe_audio_probe(struct platform_device *pdev)
1772{
1773 struct snd_card *card;
1774 struct snd_intelhad *ctx;
1775 struct snd_pcm *pcm;
1776 struct intel_hdmi_lpe_audio_pdata *pdata;
1777 int irq;
1778 struct resource *res_mmio;
Takashi Iwai4aedb942017-02-02 16:38:39 +01001779 int i, ret;
Takashi Iwaida864802017-01-31 13:52:22 +01001780
Takashi Iwaida864802017-01-31 13:52:22 +01001781 pdata = pdev->dev.platform_data;
1782 if (!pdata) {
1783 dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__);
1784 return -EINVAL;
1785 }
1786
1787 /* get resources */
1788 irq = platform_get_irq(pdev, 0);
1789 if (irq < 0) {
1790 dev_err(&pdev->dev, "Could not get irq resource\n");
1791 return -ENODEV;
1792 }
1793
1794 res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1795 if (!res_mmio) {
1796 dev_err(&pdev->dev, "Could not get IO_MEM resources\n");
1797 return -ENXIO;
1798 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301799
Takashi Iwai5647aec2017-01-31 08:14:34 +01001800 /* create a card instance with ALSA framework */
Takashi Iwaida864802017-01-31 13:52:22 +01001801 ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id,
1802 THIS_MODULE, sizeof(*ctx), &card);
1803 if (ret)
1804 return ret;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301805
Takashi Iwaida864802017-01-31 13:52:22 +01001806 ctx = card->private_data;
1807 spin_lock_init(&ctx->had_spinlock);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001808 mutex_init(&ctx->mutex);
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001809 ctx->connected = false;
Takashi Iwaida864802017-01-31 13:52:22 +01001810 ctx->dev = &pdev->dev;
1811 ctx->card = card;
Takashi Iwaida864802017-01-31 13:52:22 +01001812 ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
1813 strcpy(card->driver, INTEL_HAD);
1814 strcpy(card->shortname, INTEL_HAD);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301815
Takashi Iwaida864802017-01-31 13:52:22 +01001816 ctx->irq = -1;
1817 ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001818 INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301819
Takashi Iwaida864802017-01-31 13:52:22 +01001820 card->private_free = hdmi_lpe_audio_free;
1821
1822 /* assume pipe A as default */
1823 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
1824
1825 platform_set_drvdata(pdev, ctx);
1826
1827 dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
1828 __func__, (unsigned int)res_mmio->start,
1829 (unsigned int)res_mmio->end);
1830
1831 ctx->mmio_start = ioremap_nocache(res_mmio->start,
1832 (size_t)(resource_size(res_mmio)));
1833 if (!ctx->mmio_start) {
1834 dev_err(&pdev->dev, "Could not get ioremap\n");
1835 ret = -EACCES;
1836 goto err;
1837 }
1838
1839 /* setup interrupt handler */
1840 ret = request_irq(irq, display_pipe_interrupt_handler, 0,
1841 pdev->name, ctx);
1842 if (ret < 0) {
1843 dev_err(&pdev->dev, "request_irq failed\n");
1844 goto err;
1845 }
1846
1847 ctx->irq = irq;
1848
1849 ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
1850 MAX_CAP_STREAMS, &pcm);
1851 if (ret)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301852 goto err;
1853
1854 /* setup private data which can be retrieved when required */
Takashi Iwaida864802017-01-31 13:52:22 +01001855 pcm->private_data = ctx;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301856 pcm->info_flags = 0;
1857 strncpy(pcm->name, card->shortname, strlen(card->shortname));
Takashi Iwaida864802017-01-31 13:52:22 +01001858 /* setup the ops for playabck */
Takashi Iwaib5562902017-02-04 22:05:33 +01001859 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops);
Takashi Iwai412bbe7d52017-02-02 22:03:22 +01001860
1861 /* only 32bit addressable */
1862 dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
1863 dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
1864
Jerome Anand5dab11d2017-01-25 04:27:52 +05301865 /* allocate dma pages for ALSA stream operations
1866 * memory allocated is based on size, not max value
1867 * thus using same argument for max & size
1868 */
Takashi Iwaida864802017-01-31 13:52:22 +01001869 snd_pcm_lib_preallocate_pages_for_all(pcm,
Jerome Anand5dab11d2017-01-25 04:27:52 +05301870 SNDRV_DMA_TYPE_DEV, NULL,
1871 HAD_MAX_BUFFER, HAD_MAX_BUFFER);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301872
Takashi Iwai4aedb942017-02-02 16:38:39 +01001873 /* create controls */
1874 for (i = 0; i < ARRAY_SIZE(had_controls); i++) {
1875 ret = snd_ctl_add(card, snd_ctl_new1(&had_controls[i], ctx));
1876 if (ret < 0)
1877 goto err;
1878 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301879
1880 init_channel_allocations();
1881
1882 /* Register channel map controls */
Takashi Iwaida864802017-01-31 13:52:22 +01001883 ret = had_register_chmap_ctls(ctx, pcm);
1884 if (ret < 0)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301885 goto err;
1886
Takashi Iwaida864802017-01-31 13:52:22 +01001887 ret = snd_card_register(card);
1888 if (ret)
Takashi Iwai36ec0d92017-01-31 08:47:05 +01001889 goto err;
1890
Takashi Iwaibcce7752017-02-01 17:18:20 +01001891 spin_lock_irq(&pdata->lpe_audio_slock);
Takashi Iwaida864802017-01-31 13:52:22 +01001892 pdata->notify_audio_lpe = notify_audio_lpe;
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001893 pdata->notify_pending = false;
Takashi Iwaibcce7752017-02-01 17:18:20 +01001894 spin_unlock_irq(&pdata->lpe_audio_slock);
Takashi Iwaida864802017-01-31 13:52:22 +01001895
1896 pm_runtime_set_active(&pdev->dev);
1897 pm_runtime_enable(&pdev->dev);
1898
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001899 dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
Takashi Iwaida864802017-01-31 13:52:22 +01001900 schedule_work(&ctx->hdmi_audio_wq);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301901
Takashi Iwai79dda752017-01-30 17:23:39 +01001902 return 0;
Takashi Iwai5647aec2017-01-31 08:14:34 +01001903
Jerome Anand5dab11d2017-01-25 04:27:52 +05301904err:
1905 snd_card_free(card);
Takashi Iwaida864802017-01-31 13:52:22 +01001906 return ret;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301907}
1908
Takashi Iwai79dda752017-01-30 17:23:39 +01001909/*
Takashi Iwaida864802017-01-31 13:52:22 +01001910 * hdmi_lpe_audio_remove - stop bridge with i915
Jerome Anand5dab11d2017-01-25 04:27:52 +05301911 *
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001912 * This function is called when the platform device is destroyed.
Jerome Anand5dab11d2017-01-25 04:27:52 +05301913 */
Takashi Iwaida864802017-01-31 13:52:22 +01001914static int hdmi_lpe_audio_remove(struct platform_device *pdev)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301915{
Takashi Iwaida864802017-01-31 13:52:22 +01001916 struct snd_intelhad *ctx = platform_get_drvdata(pdev);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301917
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001918 if (ctx->connected)
Takashi Iwaib5562902017-02-04 22:05:33 +01001919 had_enable_audio_int(ctx, false);
Takashi Iwaida864802017-01-31 13:52:22 +01001920 snd_card_free(ctx->card);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301921 return 0;
1922}
1923
Takashi Iwai182cdf22017-02-02 14:43:39 +01001924static const struct dev_pm_ops hdmi_lpe_audio_pm = {
1925 SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
1926 SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend, NULL, NULL)
1927};
1928
Takashi Iwaida864802017-01-31 13:52:22 +01001929static struct platform_driver hdmi_lpe_audio_driver = {
1930 .driver = {
1931 .name = "hdmi-lpe-audio",
Takashi Iwai182cdf22017-02-02 14:43:39 +01001932 .pm = &hdmi_lpe_audio_pm,
Takashi Iwaida864802017-01-31 13:52:22 +01001933 },
1934 .probe = hdmi_lpe_audio_probe,
1935 .remove = hdmi_lpe_audio_remove,
Takashi Iwaida864802017-01-31 13:52:22 +01001936};
1937
1938module_platform_driver(hdmi_lpe_audio_driver);
1939MODULE_ALIAS("platform:hdmi_lpe_audio");
1940
Jerome Anand5dab11d2017-01-25 04:27:52 +05301941MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
1942MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
1943MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
1944MODULE_AUTHOR("Jerome Anand <jerome.anand@intel.com>");
1945MODULE_DESCRIPTION("Intel HDMI Audio driver");
1946MODULE_LICENSE("GPL v2");
1947MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");