blob: b84f7d92ed246511495b403010e0d78aca7133f2 [file] [log] [blame]
Jerome Anand287599c2017-01-25 04:27:51 +05301/*
2 * intel_hdmi_lpe_audio.c - Intel HDMI LPE audio driver for Atom platforms
3 *
4 * Copyright (C) 2016 Intel Corp
5 * Authors:
6 * Jerome Anand <jerome.anand@intel.com>
7 * Aravind Siddappaji <aravindx.siddappaji@intel.com>
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21
22#include <linux/platform_device.h>
23#include <linux/irqreturn.h>
24#include <linux/interrupt.h>
25#include <linux/io.h>
26#include <linux/slab.h>
27#include <linux/module.h>
28#include <linux/pci.h>
29#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/pcm_params.h>
32#include <sound/initval.h>
33#include <sound/control.h>
34#include <sound/initval.h>
35#include <drm/intel_lpe_audio.h>
36#include "intel_hdmi_lpe_audio.h"
Jerome Anand5dab11d2017-01-25 04:27:52 +053037#include "intel_hdmi_audio.h"
Jerome Anand287599c2017-01-25 04:27:51 +053038
Jerome Anand287599c2017-01-25 04:27:51 +053039struct hdmi_lpe_audio_ctx {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010040 struct platform_device *pdev;
Jerome Anand287599c2017-01-25 04:27:51 +053041 int irq;
42 void __iomem *mmio_start;
Takashi Iwai79dda752017-01-30 17:23:39 +010043 struct snd_intelhad *had;
Jerome Anand287599c2017-01-25 04:27:51 +053044 int tmds_clock_speed;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -060045 bool dp_output;
46 int link_rate;
Jerome Anand287599c2017-01-25 04:27:51 +053047 unsigned int had_config_offset;
48 int hdmi_audio_interrupt_mask;
49 struct work_struct hdmi_audio_wq;
Takashi Iwai055610b2017-01-30 18:11:13 +010050 int state; /* connection state */
Takashi Iwai7f2e9ab2017-01-30 18:15:40 +010051 union otm_hdmi_eld_t eld; /* ELD copy */
Jerome Anand287599c2017-01-25 04:27:51 +053052};
53
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010054static void mid_hdmi_audio_signal_event(struct platform_device *pdev,
55 enum had_event_type event)
Jerome Anand287599c2017-01-25 04:27:51 +053056{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010057 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +053058
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010059 dev_dbg(&pdev->dev, "%s: Enter\n", __func__);
Jerome Anand287599c2017-01-25 04:27:51 +053060
61 /* The handler is protected in the respective
62 * event handlers to avoid races
63 */
Takashi Iwai437af8f2017-01-30 17:38:00 +010064 had_event_handler(event, ctx->had);
Jerome Anand287599c2017-01-25 04:27:51 +053065}
66
Takashi Iwaif23df802017-01-30 16:29:39 +010067/*
Jerome Anand287599c2017-01-25 04:27:51 +053068 * used to write into display controller HDMI audio registers.
69 */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010070int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val)
Jerome Anand287599c2017-01-25 04:27:51 +053071{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010072 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +053073
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010074 dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val);
Jerome Anand287599c2017-01-25 04:27:51 +053075
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -060076 if (ctx->dp_output) {
Takashi Iwaif23df802017-01-30 16:29:39 +010077 if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT))
78 val |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -060079 }
Takashi Iwaif23df802017-01-30 16:29:39 +010080 iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
Jerome Anand287599c2017-01-25 04:27:51 +053081
82 return 0;
83}
84
Takashi Iwaif23df802017-01-30 16:29:39 +010085/*
Jerome Anand287599c2017-01-25 04:27:51 +053086 * used to get the register value read from
87 * display controller HDMI audio registers.
88 */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010089int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val)
Jerome Anand287599c2017-01-25 04:27:51 +053090{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010091 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +053092
Takashi Iwaif23df802017-01-30 16:29:39 +010093 *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
Takashi Iwaibf8b24f2017-01-30 18:09:01 +010094 dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val);
Jerome Anand287599c2017-01-25 04:27:51 +053095 return 0;
96}
97
Takashi Iwaif23df802017-01-30 16:29:39 +010098/*
Jerome Anand287599c2017-01-25 04:27:51 +053099 * used to update the masked bits in display controller HDMI
100 * audio registers.
101 */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100102int mid_hdmi_audio_rmw(struct platform_device *pdev,
103 u32 reg, u32 val, u32 mask)
Jerome Anand287599c2017-01-25 04:27:51 +0530104{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100105 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +0530106 u32 val_tmp = 0;
107
Takashi Iwaif23df802017-01-30 16:29:39 +0100108 val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
109 val_tmp &= ~mask;
110 val_tmp |= (val & mask);
Jerome Anand287599c2017-01-25 04:27:51 +0530111
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600112 if (ctx->dp_output) {
Takashi Iwaif23df802017-01-30 16:29:39 +0100113 if (reg == AUD_CONFIG && (val_tmp & AUD_CONFIG_VALID_BIT))
114 val_tmp |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600115 }
116
Takashi Iwaif23df802017-01-30 16:29:39 +0100117 iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg);
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100118 dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__,
Jerome Anand287599c2017-01-25 04:27:51 +0530119 reg, val_tmp);
120
121 return 0;
122}
123
Takashi Iwai9eca88c2017-01-30 16:37:06 +0100124/*
Jerome Anand287599c2017-01-25 04:27:51 +0530125 * used to return the HDMI audio capabilities.
126 * e.g. resolution, frame rate.
127 */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100128int mid_hdmi_audio_get_caps(struct platform_device *pdev,
129 enum had_caps_list get_element,
Takashi Iwai9eca88c2017-01-30 16:37:06 +0100130 void *capabilities)
Jerome Anand287599c2017-01-25 04:27:51 +0530131{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100132 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +0530133 int ret = 0;
134
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100135 dev_dbg(&pdev->dev, "%s: Enter\n", __func__);
Jerome Anand287599c2017-01-25 04:27:51 +0530136
137 switch (get_element) {
138 case HAD_GET_ELD:
Takashi Iwai7f2e9ab2017-01-30 18:15:40 +0100139 memcpy(capabilities, &ctx->eld, sizeof(ctx->eld));
140 print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE,
141 (u8 *)&ctx->eld, sizeof(ctx->eld));
Jerome Anand287599c2017-01-25 04:27:51 +0530142 break;
143 case HAD_GET_DISPLAY_RATE:
144 /* ToDo: Verify if sampling freq logic is correct */
145 *(u32 *)capabilities = ctx->tmds_clock_speed;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100146 dev_dbg(&pdev->dev, "%s: tmds_clock_speed = 0x%x\n",
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600147 __func__, ctx->tmds_clock_speed);
148 break;
149 case HAD_GET_LINK_RATE:
150 /* ToDo: Verify if sampling freq logic is correct */
151 *(u32 *)capabilities = ctx->link_rate;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100152 dev_dbg(&pdev->dev, "%s: link rate = 0x%x\n",
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600153 __func__, ctx->link_rate);
154 break;
155 case HAD_GET_DP_OUTPUT:
156 *(u32 *)capabilities = ctx->dp_output;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100157 dev_dbg(&pdev->dev, "%s: dp_output = %d\n",
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600158 __func__, ctx->dp_output);
Jerome Anand287599c2017-01-25 04:27:51 +0530159 break;
160 default:
161 break;
162 }
163
164 return ret;
165}
166
Takashi Iwai9eca88c2017-01-30 16:37:06 +0100167/*
Jerome Anand287599c2017-01-25 04:27:51 +0530168 * used to set the HDMI audio capabilities.
169 * e.g. Audio INT.
170 */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100171int mid_hdmi_audio_set_caps(struct platform_device *pdev,
172 enum had_caps_list set_element,
Takashi Iwai9eca88c2017-01-30 16:37:06 +0100173 void *capabilties)
Jerome Anand287599c2017-01-25 04:27:51 +0530174{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100175 dev_dbg(&pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element);
Jerome Anand287599c2017-01-25 04:27:51 +0530176
177 switch (set_element) {
178 case HAD_SET_ENABLE_AUDIO_INT:
179 {
180 u32 status_reg;
181
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100182 mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2,
183 &status_reg);
Jerome Anand287599c2017-01-25 04:27:51 +0530184 status_reg |=
185 HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100186 mid_hdmi_audio_write(pdev, AUD_HDMI_STATUS_v2,
187 status_reg);
188 mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2,
189 &status_reg);
Jerome Anand287599c2017-01-25 04:27:51 +0530190 }
191 break;
192 default:
193 break;
194 }
195
196 return 0;
197}
198
Jerome Anand287599c2017-01-25 04:27:51 +0530199static void _had_wq(struct work_struct *work)
200{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100201 struct hdmi_lpe_audio_ctx *ctx =
202 container_of(work, struct hdmi_lpe_audio_ctx, hdmi_audio_wq);
203
204 mid_hdmi_audio_signal_event(ctx->pdev, HAD_EVENT_HOT_PLUG);
Jerome Anand287599c2017-01-25 04:27:51 +0530205}
206
Jerome Anand287599c2017-01-25 04:27:51 +0530207static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
208{
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100209 struct platform_device *pdev = dev_id;
Jerome Anand287599c2017-01-25 04:27:51 +0530210 u32 audio_stat, audio_reg;
Jerome Anand287599c2017-01-25 04:27:51 +0530211 struct hdmi_lpe_audio_ctx *ctx;
212
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100213 dev_dbg(&pdev->dev, "%s: Enter\n", __func__);
Jerome Anand287599c2017-01-25 04:27:51 +0530214
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100215 ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +0530216
Takashi Iwaif23df802017-01-30 16:29:39 +0100217 audio_reg = AUD_HDMI_STATUS_v2;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100218 mid_hdmi_audio_read(pdev, audio_reg, &audio_stat);
Jerome Anand287599c2017-01-25 04:27:51 +0530219
220 if (audio_stat & HDMI_AUDIO_UNDERRUN) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100221 mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_UNDERRUN);
222 mid_hdmi_audio_signal_event(pdev,
Jerome Anand287599c2017-01-25 04:27:51 +0530223 HAD_EVENT_AUDIO_BUFFER_UNDERRUN);
224 }
225
226 if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100227 mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_BUFFER_DONE);
228 mid_hdmi_audio_signal_event(pdev,
Jerome Anand287599c2017-01-25 04:27:51 +0530229 HAD_EVENT_AUDIO_BUFFER_DONE);
230 }
231
232 return IRQ_HANDLED;
233}
234
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100235static void notify_audio_lpe(struct platform_device *pdev)
Jerome Anand287599c2017-01-25 04:27:51 +0530236{
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100237 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
238 struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data;
Jerome Anand287599c2017-01-25 04:27:51 +0530239
240 if (pdata->hdmi_connected != true) {
241
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100242 dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
Jerome Anand287599c2017-01-25 04:27:51 +0530243 __func__);
244
Takashi Iwai055610b2017-01-30 18:11:13 +0100245 if (ctx->state == hdmi_connector_status_connected) {
Jerome Anand287599c2017-01-25 04:27:51 +0530246
Takashi Iwai055610b2017-01-30 18:11:13 +0100247 ctx->state = hdmi_connector_status_disconnected;
Jerome Anand287599c2017-01-25 04:27:51 +0530248
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100249 mid_hdmi_audio_signal_event(pdev,
Jerome Anand287599c2017-01-25 04:27:51 +0530250 HAD_EVENT_HOT_UNPLUG);
251 } else
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100252 dev_dbg(&pdev->dev, "%s: Already Unplugged!\n",
Jerome Anand287599c2017-01-25 04:27:51 +0530253 __func__);
254
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100255 } else {
256 struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
Jerome Anand287599c2017-01-25 04:27:51 +0530257
Pierre-Louis Bossart0843e042017-01-31 14:16:53 -0600258 switch (eld->pipe_id) {
259 case 0:
260 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
261 break;
262 case 1:
263 ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
264 break;
265 case 2:
266 ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
267 break;
268 default:
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100269 dev_dbg(&pdev->dev, "Invalid pipe %d\n",
Pierre-Louis Bossart0843e042017-01-31 14:16:53 -0600270 eld->pipe_id);
271 break;
272 }
273
Takashi Iwai7f2e9ab2017-01-30 18:15:40 +0100274 memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld));
Jerome Anand287599c2017-01-25 04:27:51 +0530275
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100276 mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG);
Jerome Anand287599c2017-01-25 04:27:51 +0530277
Takashi Iwai055610b2017-01-30 18:11:13 +0100278 ctx->state = hdmi_connector_status_connected;
Jerome Anand287599c2017-01-25 04:27:51 +0530279
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100280 dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
Jerome Anand287599c2017-01-25 04:27:51 +0530281 __func__, eld->port_id, pdata->tmds_clock_speed);
282
283 if (pdata->tmds_clock_speed) {
284 ctx->tmds_clock_speed = pdata->tmds_clock_speed;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600285 ctx->dp_output = pdata->dp_output;
286 ctx->link_rate = pdata->link_rate;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100287 mid_hdmi_audio_signal_event(pdev,
288 HAD_EVENT_MODE_CHANGING);
Jerome Anand287599c2017-01-25 04:27:51 +0530289 }
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100290 }
Jerome Anand287599c2017-01-25 04:27:51 +0530291}
292
293/**
294 * hdmi_lpe_audio_probe - start bridge with i915
295 *
Jerome Anand5dab11d2017-01-25 04:27:52 +0530296 * This function is called when the i915 driver creates the
297 * hdmi-lpe-audio platform device. Card creation is deferred until a
298 * hot plug event is received
Jerome Anand287599c2017-01-25 04:27:51 +0530299 */
300static int hdmi_lpe_audio_probe(struct platform_device *pdev)
301{
302 struct hdmi_lpe_audio_ctx *ctx;
303 struct intel_hdmi_lpe_audio_pdata *pdata;
304 int irq;
305 struct resource *res_mmio;
306 void __iomem *mmio_start;
307 int ret = 0;
308 unsigned long flag_irq;
Jerome Anand287599c2017-01-25 04:27:51 +0530309
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100310 dev_dbg(&pdev->dev, "Enter %s\n", __func__);
Takashi Iwaidae15a92017-01-31 08:02:16 +0100311 dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask);
Jerome Anand287599c2017-01-25 04:27:51 +0530312
Jerome Anand287599c2017-01-25 04:27:51 +0530313 /* get resources */
314 irq = platform_get_irq(pdev, 0);
315 if (irq < 0) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100316 dev_err(&pdev->dev, "Could not get irq resource\n");
Jerome Anand287599c2017-01-25 04:27:51 +0530317 return -ENODEV;
318 }
319
320 res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
321 if (!res_mmio) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100322 dev_err(&pdev->dev, "Could not get IO_MEM resources\n");
Jerome Anand287599c2017-01-25 04:27:51 +0530323 return -ENXIO;
324 }
325
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100326 dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
Jerome Anand287599c2017-01-25 04:27:51 +0530327 __func__, (unsigned int)res_mmio->start,
328 (unsigned int)res_mmio->end);
329
330 mmio_start = ioremap_nocache(res_mmio->start,
kbuild test robotf0fd4122017-01-24 23:41:46 +0800331 (size_t)(resource_size(res_mmio)));
Jerome Anand287599c2017-01-25 04:27:51 +0530332 if (!mmio_start) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100333 dev_err(&pdev->dev, "Could not get ioremap\n");
Jerome Anand287599c2017-01-25 04:27:51 +0530334 return -EACCES;
335 }
336
Jerome Anand287599c2017-01-25 04:27:51 +0530337 /* alloc and save context */
338 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
339 if (ctx == NULL) {
Takashi Iwai45459d12017-01-31 08:29:56 +0100340 ret = -ENOMEM;
341 goto error_ctx;
Jerome Anand287599c2017-01-25 04:27:51 +0530342 }
343
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100344 ctx->pdev = pdev;
Jerome Anand287599c2017-01-25 04:27:51 +0530345 ctx->irq = irq;
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100346 dev_dbg(&pdev->dev, "hdmi lpe audio: irq num = %d\n", irq);
Jerome Anand287599c2017-01-25 04:27:51 +0530347 ctx->mmio_start = mmio_start;
348 ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
Takashi Iwai79dda752017-01-30 17:23:39 +0100349 INIT_WORK(&ctx->hdmi_audio_wq, _had_wq);
Takashi Iwai055610b2017-01-30 18:11:13 +0100350 ctx->state = hdmi_connector_status_disconnected;
Jerome Anand287599c2017-01-25 04:27:51 +0530351
Pierre-Louis Bossart0843e042017-01-31 14:16:53 -0600352 /* assume pipe A as default */
353 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
Jerome Anand287599c2017-01-25 04:27:51 +0530354
355 pdata = pdev->dev.platform_data;
356
357 if (pdata == NULL) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100358 dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__);
Takashi Iwai45459d12017-01-31 08:29:56 +0100359 ret = -ENOMEM;
Takashi Iwai033e9252017-01-30 17:40:04 +0100360 goto error_irq;
Jerome Anand287599c2017-01-25 04:27:51 +0530361 }
362
363 platform_set_drvdata(pdev, ctx);
364
Takashi Iwai033e9252017-01-30 17:40:04 +0100365 /* setup interrupt handler */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100366 ret = request_irq(irq, display_pipe_interrupt_handler, 0,
367 pdev->name, pdev);
368
Takashi Iwai033e9252017-01-30 17:40:04 +0100369 if (ret < 0) {
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100370 dev_err(&pdev->dev, "request_irq failed\n");
Takashi Iwai033e9252017-01-30 17:40:04 +0100371 goto error_irq;
372 }
373
Takashi Iwai79dda752017-01-30 17:23:39 +0100374 ret = hdmi_audio_probe(pdev, &ctx->had);
Takashi Iwai45459d12017-01-31 08:29:56 +0100375 if (ret < 0)
376 goto error_probe;
377
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100378 dev_dbg(&pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n");
Jerome Anand287599c2017-01-25 04:27:51 +0530379
Takashi Iwai79dda752017-01-30 17:23:39 +0100380 /* The Audio driver is loading now and we need to notify
381 * it if there is an HDMI device attached
382 */
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100383 dev_dbg(&pdev->dev, "%s: Scheduling HDMI audio work queue\n",
Takashi Iwai79dda752017-01-30 17:23:39 +0100384 __func__);
385 schedule_work(&ctx->hdmi_audio_wq);
386
Jerome Anand287599c2017-01-25 04:27:51 +0530387 spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq);
388 pdata->notify_audio_lpe = notify_audio_lpe;
Jerome Anand287599c2017-01-25 04:27:51 +0530389 if (pdata->notify_pending) {
390
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100391 dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
Takashi Iwaib1c01f42017-01-30 17:56:39 +0100392 notify_audio_lpe(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +0530393 pdata->notify_pending = false;
394 }
395 spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq);
396
397 return ret;
Takashi Iwai45459d12017-01-31 08:29:56 +0100398
399 error_probe:
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100400 free_irq(irq, pdev);
Takashi Iwai45459d12017-01-31 08:29:56 +0100401 error_irq:
Takashi Iwai033e9252017-01-30 17:40:04 +0100402 kfree(ctx);
403 error_ctx:
Takashi Iwai45459d12017-01-31 08:29:56 +0100404 iounmap(mmio_start);
405 return ret;
Jerome Anand287599c2017-01-25 04:27:51 +0530406}
407
408/**
409 * hdmi_lpe_audio_remove - stop bridge with i915
410 *
411 * This function is called when the platform device is destroyed. The sound
412 * card should have been removed on hot plug event.
413 */
414static int hdmi_lpe_audio_remove(struct platform_device *pdev)
415{
Takashi Iwai79dda752017-01-30 17:23:39 +0100416 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
Jerome Anand287599c2017-01-25 04:27:51 +0530417
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100418 dev_dbg(&pdev->dev, "Enter %s\n", __func__);
Jerome Anand287599c2017-01-25 04:27:51 +0530419
Takashi Iwai79dda752017-01-30 17:23:39 +0100420 hdmi_audio_remove(ctx->had);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530421
Takashi Iwai79dda752017-01-30 17:23:39 +0100422 /* release resources */
Jerome Anand287599c2017-01-25 04:27:51 +0530423 iounmap(ctx->mmio_start);
Takashi Iwaibf8b24f2017-01-30 18:09:01 +0100424 free_irq(ctx->irq, pdev);
Jerome Anand287599c2017-01-25 04:27:51 +0530425 kfree(ctx);
426 return 0;
427}
428
Takashi Iwai6f9ecc72017-01-30 16:52:06 +0100429static int hdmi_lpe_audio_suspend(struct platform_device *pdev,
430 pm_message_t state)
Jerome Anand287599c2017-01-25 04:27:51 +0530431{
Takashi Iwai6f9ecc72017-01-30 16:52:06 +0100432 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
433
Takashi Iwai055610b2017-01-30 18:11:13 +0100434 dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state);
Takashi Iwai6f9ecc72017-01-30 16:52:06 +0100435 /* HDMI is not connected, assuming audio device is suspended already */
Takashi Iwai055610b2017-01-30 18:11:13 +0100436 if (ctx->state != hdmi_connector_status_disconnected)
Takashi Iwai79dda752017-01-30 17:23:39 +0100437 hdmi_audio_suspend(ctx->had);
Jerome Anand287599c2017-01-25 04:27:51 +0530438 return 0;
439}
440
Takashi Iwai6f9ecc72017-01-30 16:52:06 +0100441static int hdmi_lpe_audio_resume(struct platform_device *pdev)
Jerome Anand287599c2017-01-25 04:27:51 +0530442{
Takashi Iwai6f9ecc72017-01-30 16:52:06 +0100443 struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
444
Takashi Iwai055610b2017-01-30 18:11:13 +0100445 dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state);
Takashi Iwai6f9ecc72017-01-30 16:52:06 +0100446 /* HDMI is not connected, there is no need to resume audio device */
Takashi Iwai055610b2017-01-30 18:11:13 +0100447 if (ctx->state != hdmi_connector_status_disconnected)
Takashi Iwai79dda752017-01-30 17:23:39 +0100448 hdmi_audio_resume(ctx->had);
Jerome Anand287599c2017-01-25 04:27:51 +0530449 return 0;
450}
451
452static struct platform_driver hdmi_lpe_audio_driver = {
453 .driver = {
454 .name = "hdmi-lpe-audio",
455 },
456 .probe = hdmi_lpe_audio_probe,
457 .remove = hdmi_lpe_audio_remove,
458 .suspend = hdmi_lpe_audio_suspend,
459 .resume = hdmi_lpe_audio_resume
460};
461
462module_platform_driver(hdmi_lpe_audio_driver);
463MODULE_LICENSE("GPL v2");
464MODULE_ALIAS("platform:hdmi_lpe_audio");