Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 
0007 #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
0008 
0009 #include <linux/of_platform.h>
0010 
0011 #include <drm/display/drm_dp_helper.h>
0012 #include <drm/drm_edid.h>
0013 
0014 #include "dp_catalog.h"
0015 #include "dp_audio.h"
0016 #include "dp_panel.h"
0017 #include "dp_display.h"
0018 
0019 #define HEADER_BYTE_2_BIT    0
0020 #define PARITY_BYTE_2_BIT    8
0021 #define HEADER_BYTE_1_BIT   16
0022 #define PARITY_BYTE_1_BIT   24
0023 #define HEADER_BYTE_3_BIT   16
0024 #define PARITY_BYTE_3_BIT   24
0025 
0026 struct dp_audio_private {
0027     struct platform_device *audio_pdev;
0028     struct platform_device *pdev;
0029     struct drm_device *drm_dev;
0030     struct dp_catalog *catalog;
0031     struct dp_panel *panel;
0032 
0033     bool engine_on;
0034     u32 channels;
0035 
0036     struct dp_audio dp_audio;
0037 };
0038 
0039 static u8 dp_audio_get_g0_value(u8 data)
0040 {
0041     u8 c[4];
0042     u8 g[4];
0043     u8 ret_data = 0;
0044     u8 i;
0045 
0046     for (i = 0; i < 4; i++)
0047         c[i] = (data >> i) & 0x01;
0048 
0049     g[0] = c[3];
0050     g[1] = c[0] ^ c[3];
0051     g[2] = c[1];
0052     g[3] = c[2];
0053 
0054     for (i = 0; i < 4; i++)
0055         ret_data = ((g[i] & 0x01) << i) | ret_data;
0056 
0057     return ret_data;
0058 }
0059 
0060 static u8 dp_audio_get_g1_value(u8 data)
0061 {
0062     u8 c[4];
0063     u8 g[4];
0064     u8 ret_data = 0;
0065     u8 i;
0066 
0067     for (i = 0; i < 4; i++)
0068         c[i] = (data >> i) & 0x01;
0069 
0070     g[0] = c[0] ^ c[3];
0071     g[1] = c[0] ^ c[1] ^ c[3];
0072     g[2] = c[1] ^ c[2];
0073     g[3] = c[2] ^ c[3];
0074 
0075     for (i = 0; i < 4; i++)
0076         ret_data = ((g[i] & 0x01) << i) | ret_data;
0077 
0078     return ret_data;
0079 }
0080 
0081 static u8 dp_audio_calculate_parity(u32 data)
0082 {
0083     u8 x0 = 0;
0084     u8 x1 = 0;
0085     u8 ci = 0;
0086     u8 iData = 0;
0087     u8 i = 0;
0088     u8 parity_byte;
0089     u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
0090 
0091     for (i = 0; i < num_byte; i++) {
0092         iData = (data >> i*4) & 0xF;
0093 
0094         ci = iData ^ x1;
0095         x1 = x0 ^ dp_audio_get_g1_value(ci);
0096         x0 = dp_audio_get_g0_value(ci);
0097     }
0098 
0099     parity_byte = x1 | (x0 << 4);
0100 
0101     return parity_byte;
0102 }
0103 
0104 static u32 dp_audio_get_header(struct dp_catalog *catalog,
0105         enum dp_catalog_audio_sdp_type sdp,
0106         enum dp_catalog_audio_header_type header)
0107 {
0108     catalog->sdp_type = sdp;
0109     catalog->sdp_header = header;
0110     dp_catalog_audio_get_header(catalog);
0111 
0112     return catalog->audio_data;
0113 }
0114 
0115 static void dp_audio_set_header(struct dp_catalog *catalog,
0116         u32 data,
0117         enum dp_catalog_audio_sdp_type sdp,
0118         enum dp_catalog_audio_header_type header)
0119 {
0120     catalog->sdp_type = sdp;
0121     catalog->sdp_header = header;
0122     catalog->audio_data = data;
0123     dp_catalog_audio_set_header(catalog);
0124 }
0125 
0126 static void dp_audio_stream_sdp(struct dp_audio_private *audio)
0127 {
0128     struct dp_catalog *catalog = audio->catalog;
0129     u32 value, new_value;
0130     u8 parity_byte;
0131 
0132     /* Config header and parity byte 1 */
0133     value = dp_audio_get_header(catalog,
0134             DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
0135 
0136     new_value = 0x02;
0137     parity_byte = dp_audio_calculate_parity(new_value);
0138     value |= ((new_value << HEADER_BYTE_1_BIT)
0139             | (parity_byte << PARITY_BYTE_1_BIT));
0140     drm_dbg_dp(audio->drm_dev,
0141             "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
0142             value, parity_byte);
0143     dp_audio_set_header(catalog, value,
0144         DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
0145 
0146     /* Config header and parity byte 2 */
0147     value = dp_audio_get_header(catalog,
0148             DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
0149     new_value = value;
0150     parity_byte = dp_audio_calculate_parity(new_value);
0151     value |= ((new_value << HEADER_BYTE_2_BIT)
0152             | (parity_byte << PARITY_BYTE_2_BIT));
0153     drm_dbg_dp(audio->drm_dev,
0154             "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
0155             value, parity_byte);
0156 
0157     dp_audio_set_header(catalog, value,
0158         DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
0159 
0160     /* Config header and parity byte 3 */
0161     value = dp_audio_get_header(catalog,
0162             DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
0163 
0164     new_value = audio->channels - 1;
0165     parity_byte = dp_audio_calculate_parity(new_value);
0166     value |= ((new_value << HEADER_BYTE_3_BIT)
0167             | (parity_byte << PARITY_BYTE_3_BIT));
0168     drm_dbg_dp(audio->drm_dev,
0169             "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
0170         value, parity_byte);
0171 
0172     dp_audio_set_header(catalog, value,
0173         DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
0174 }
0175 
0176 static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
0177 {
0178     struct dp_catalog *catalog = audio->catalog;
0179     u32 value, new_value;
0180     u8 parity_byte;
0181 
0182     /* Config header and parity byte 1 */
0183     value = dp_audio_get_header(catalog,
0184             DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
0185 
0186     new_value = 0x1;
0187     parity_byte = dp_audio_calculate_parity(new_value);
0188     value |= ((new_value << HEADER_BYTE_1_BIT)
0189             | (parity_byte << PARITY_BYTE_1_BIT));
0190     drm_dbg_dp(audio->drm_dev,
0191             "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
0192             value, parity_byte);
0193     dp_audio_set_header(catalog, value,
0194         DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
0195 
0196     /* Config header and parity byte 2 */
0197     value = dp_audio_get_header(catalog,
0198             DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
0199 
0200     new_value = 0x17;
0201     parity_byte = dp_audio_calculate_parity(new_value);
0202     value |= ((new_value << HEADER_BYTE_2_BIT)
0203             | (parity_byte << PARITY_BYTE_2_BIT));
0204     drm_dbg_dp(audio->drm_dev,
0205             "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
0206             value, parity_byte);
0207     dp_audio_set_header(catalog, value,
0208         DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
0209 
0210     /* Config header and parity byte 3 */
0211     value = dp_audio_get_header(catalog,
0212             DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
0213 
0214     new_value = (0x0 | (0x11 << 2));
0215     parity_byte = dp_audio_calculate_parity(new_value);
0216     value |= ((new_value << HEADER_BYTE_3_BIT)
0217             | (parity_byte << PARITY_BYTE_3_BIT));
0218     drm_dbg_dp(audio->drm_dev,
0219             "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
0220             value, parity_byte);
0221     dp_audio_set_header(catalog, value,
0222         DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
0223 }
0224 
0225 static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
0226 {
0227     struct dp_catalog *catalog = audio->catalog;
0228     u32 value, new_value;
0229     u8 parity_byte;
0230 
0231     /* Config header and parity byte 1 */
0232     value = dp_audio_get_header(catalog,
0233             DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
0234 
0235     new_value = 0x84;
0236     parity_byte = dp_audio_calculate_parity(new_value);
0237     value |= ((new_value << HEADER_BYTE_1_BIT)
0238             | (parity_byte << PARITY_BYTE_1_BIT));
0239     drm_dbg_dp(audio->drm_dev,
0240             "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
0241             value, parity_byte);
0242     dp_audio_set_header(catalog, value,
0243         DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
0244 
0245     /* Config header and parity byte 2 */
0246     value = dp_audio_get_header(catalog,
0247             DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
0248 
0249     new_value = 0x1b;
0250     parity_byte = dp_audio_calculate_parity(new_value);
0251     value |= ((new_value << HEADER_BYTE_2_BIT)
0252             | (parity_byte << PARITY_BYTE_2_BIT));
0253     drm_dbg_dp(audio->drm_dev,
0254             "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
0255             value, parity_byte);
0256     dp_audio_set_header(catalog, value,
0257         DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
0258 
0259     /* Config header and parity byte 3 */
0260     value = dp_audio_get_header(catalog,
0261             DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
0262 
0263     new_value = (0x0 | (0x11 << 2));
0264     parity_byte = dp_audio_calculate_parity(new_value);
0265     value |= ((new_value << HEADER_BYTE_3_BIT)
0266             | (parity_byte << PARITY_BYTE_3_BIT));
0267     drm_dbg_dp(audio->drm_dev,
0268             "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
0269             new_value, parity_byte);
0270     dp_audio_set_header(catalog, value,
0271         DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
0272 }
0273 
0274 static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
0275 {
0276     struct dp_catalog *catalog = audio->catalog;
0277     u32 value, new_value;
0278     u8 parity_byte;
0279 
0280     /* Config header and parity byte 1 */
0281     value = dp_audio_get_header(catalog,
0282             DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
0283 
0284     new_value = 0x05;
0285     parity_byte = dp_audio_calculate_parity(new_value);
0286     value |= ((new_value << HEADER_BYTE_1_BIT)
0287             | (parity_byte << PARITY_BYTE_1_BIT));
0288     drm_dbg_dp(audio->drm_dev,
0289             "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
0290             value, parity_byte);
0291     dp_audio_set_header(catalog, value,
0292         DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
0293 
0294     /* Config header and parity byte 2 */
0295     value = dp_audio_get_header(catalog,
0296             DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
0297 
0298     new_value = 0x0F;
0299     parity_byte = dp_audio_calculate_parity(new_value);
0300     value |= ((new_value << HEADER_BYTE_2_BIT)
0301             | (parity_byte << PARITY_BYTE_2_BIT));
0302     drm_dbg_dp(audio->drm_dev,
0303             "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
0304             value, parity_byte);
0305     dp_audio_set_header(catalog, value,
0306         DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
0307 
0308     /* Config header and parity byte 3 */
0309     value = dp_audio_get_header(catalog,
0310             DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
0311 
0312     new_value = 0x0;
0313     parity_byte = dp_audio_calculate_parity(new_value);
0314     value |= ((new_value << HEADER_BYTE_3_BIT)
0315             | (parity_byte << PARITY_BYTE_3_BIT));
0316     drm_dbg_dp(audio->drm_dev,
0317             "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
0318             value, parity_byte);
0319     dp_audio_set_header(catalog, value,
0320         DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
0321 }
0322 
0323 static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
0324 {
0325     struct dp_catalog *catalog = audio->catalog;
0326     u32 value, new_value;
0327     u8 parity_byte;
0328 
0329     /* Config header and parity byte 1 */
0330     value = dp_audio_get_header(catalog,
0331             DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
0332 
0333     new_value = 0x06;
0334     parity_byte = dp_audio_calculate_parity(new_value);
0335     value |= ((new_value << HEADER_BYTE_1_BIT)
0336             | (parity_byte << PARITY_BYTE_1_BIT));
0337     drm_dbg_dp(audio->drm_dev,
0338             "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
0339             value, parity_byte);
0340     dp_audio_set_header(catalog, value,
0341         DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
0342 
0343     /* Config header and parity byte 2 */
0344     value = dp_audio_get_header(catalog,
0345             DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
0346 
0347     new_value = 0x0F;
0348     parity_byte = dp_audio_calculate_parity(new_value);
0349     value |= ((new_value << HEADER_BYTE_2_BIT)
0350             | (parity_byte << PARITY_BYTE_2_BIT));
0351     drm_dbg_dp(audio->drm_dev,
0352             "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
0353             value, parity_byte);
0354     dp_audio_set_header(catalog, value,
0355         DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
0356 }
0357 
0358 static void dp_audio_setup_sdp(struct dp_audio_private *audio)
0359 {
0360     dp_catalog_audio_config_sdp(audio->catalog);
0361 
0362     dp_audio_stream_sdp(audio);
0363     dp_audio_timestamp_sdp(audio);
0364     dp_audio_infoframe_sdp(audio);
0365     dp_audio_copy_management_sdp(audio);
0366     dp_audio_isrc_sdp(audio);
0367 }
0368 
0369 static void dp_audio_setup_acr(struct dp_audio_private *audio)
0370 {
0371     u32 select = 0;
0372     struct dp_catalog *catalog = audio->catalog;
0373 
0374     switch (audio->dp_audio.bw_code) {
0375     case DP_LINK_BW_1_62:
0376         select = 0;
0377         break;
0378     case DP_LINK_BW_2_7:
0379         select = 1;
0380         break;
0381     case DP_LINK_BW_5_4:
0382         select = 2;
0383         break;
0384     case DP_LINK_BW_8_1:
0385         select = 3;
0386         break;
0387     default:
0388         drm_dbg_dp(audio->drm_dev, "Unknown link rate\n");
0389         select = 0;
0390         break;
0391     }
0392 
0393     catalog->audio_data = select;
0394     dp_catalog_audio_config_acr(catalog);
0395 }
0396 
0397 static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
0398 {
0399     struct dp_catalog *catalog = audio->catalog;
0400     u32 safe_to_exit_level = 0;
0401 
0402     switch (audio->dp_audio.lane_count) {
0403     case 1:
0404         safe_to_exit_level = 14;
0405         break;
0406     case 2:
0407         safe_to_exit_level = 8;
0408         break;
0409     case 4:
0410         safe_to_exit_level = 5;
0411         break;
0412     default:
0413         drm_dbg_dp(audio->drm_dev,
0414                 "setting the default safe_to_exit_level = %u\n",
0415                 safe_to_exit_level);
0416         safe_to_exit_level = 14;
0417         break;
0418     }
0419 
0420     catalog->audio_data = safe_to_exit_level;
0421     dp_catalog_audio_sfe_level(catalog);
0422 }
0423 
0424 static void dp_audio_enable(struct dp_audio_private *audio, bool enable)
0425 {
0426     struct dp_catalog *catalog = audio->catalog;
0427 
0428     catalog->audio_data = enable;
0429     dp_catalog_audio_enable(catalog);
0430 
0431     audio->engine_on = enable;
0432 }
0433 
0434 static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev)
0435 {
0436     struct dp_audio *dp_audio;
0437     struct msm_dp *dp_display;
0438 
0439     if (!pdev) {
0440         DRM_ERROR("invalid input\n");
0441         return ERR_PTR(-ENODEV);
0442     }
0443 
0444     dp_display = platform_get_drvdata(pdev);
0445     if (!dp_display) {
0446         DRM_ERROR("invalid input\n");
0447         return ERR_PTR(-ENODEV);
0448     }
0449 
0450     dp_audio = dp_display->dp_audio;
0451 
0452     if (!dp_audio) {
0453         DRM_ERROR("invalid dp_audio data\n");
0454         return ERR_PTR(-EINVAL);
0455     }
0456 
0457     return container_of(dp_audio, struct dp_audio_private, dp_audio);
0458 }
0459 
0460 static int dp_audio_hook_plugged_cb(struct device *dev, void *data,
0461         hdmi_codec_plugged_cb fn,
0462         struct device *codec_dev)
0463 {
0464 
0465     struct platform_device *pdev;
0466     struct msm_dp *dp_display;
0467 
0468     pdev = to_platform_device(dev);
0469     if (!pdev) {
0470         pr_err("invalid input\n");
0471         return -ENODEV;
0472     }
0473 
0474     dp_display = platform_get_drvdata(pdev);
0475     if (!dp_display) {
0476         pr_err("invalid input\n");
0477         return -ENODEV;
0478     }
0479 
0480     return dp_display_set_plugged_cb(dp_display, fn, codec_dev);
0481 }
0482 
0483 static int dp_audio_get_eld(struct device *dev,
0484     void *data, uint8_t *buf, size_t len)
0485 {
0486     struct platform_device *pdev;
0487     struct msm_dp *dp_display;
0488 
0489     pdev = to_platform_device(dev);
0490 
0491     if (!pdev) {
0492         DRM_ERROR("invalid input\n");
0493         return -ENODEV;
0494     }
0495 
0496     dp_display = platform_get_drvdata(pdev);
0497     if (!dp_display) {
0498         DRM_ERROR("invalid input\n");
0499         return -ENODEV;
0500     }
0501 
0502     memcpy(buf, dp_display->connector->eld,
0503         min(sizeof(dp_display->connector->eld), len));
0504 
0505     return 0;
0506 }
0507 
0508 int dp_audio_hw_params(struct device *dev,
0509     void *data,
0510     struct hdmi_codec_daifmt *daifmt,
0511     struct hdmi_codec_params *params)
0512 {
0513     int rc = 0;
0514     struct dp_audio_private *audio;
0515     struct platform_device *pdev;
0516     struct msm_dp *dp_display;
0517 
0518     pdev = to_platform_device(dev);
0519     dp_display = platform_get_drvdata(pdev);
0520 
0521     /*
0522      * there could be cases where sound card can be opened even
0523      * before OR even when DP is not connected . This can cause
0524      * unclocked access as the audio subsystem relies on the DP
0525      * driver to maintain the correct state of clocks. To protect
0526      * such cases check for connection status and bail out if not
0527      * connected.
0528      */
0529     if (!dp_display->power_on) {
0530         rc = -EINVAL;
0531         goto end;
0532     }
0533 
0534     audio = dp_audio_get_data(pdev);
0535     if (IS_ERR(audio)) {
0536         rc = PTR_ERR(audio);
0537         goto end;
0538     }
0539 
0540     audio->channels = params->channels;
0541 
0542     dp_audio_setup_sdp(audio);
0543     dp_audio_setup_acr(audio);
0544     dp_audio_safe_to_exit_level(audio);
0545     dp_audio_enable(audio, true);
0546     dp_display_signal_audio_start(dp_display);
0547     dp_display->audio_enabled = true;
0548 
0549 end:
0550     return rc;
0551 }
0552 
0553 static void dp_audio_shutdown(struct device *dev, void *data)
0554 {
0555     struct dp_audio_private *audio;
0556     struct platform_device *pdev;
0557     struct msm_dp *dp_display;
0558 
0559     pdev = to_platform_device(dev);
0560     dp_display = platform_get_drvdata(pdev);
0561     audio = dp_audio_get_data(pdev);
0562     if (IS_ERR(audio)) {
0563         DRM_ERROR("failed to get audio data\n");
0564         return;
0565     }
0566 
0567     /*
0568      * if audio was not enabled there is no need
0569      * to execute the shutdown and we can bail out early.
0570      * This also makes sure that we dont cause an unclocked
0571      * access when audio subsystem calls this without DP being
0572      * connected. is_connected cannot be used here as its set
0573      * to false earlier than this call
0574      */
0575     if (!dp_display->audio_enabled)
0576         return;
0577 
0578     dp_audio_enable(audio, false);
0579     /* signal the dp display to safely shutdown clocks */
0580     dp_display_signal_audio_complete(dp_display);
0581 }
0582 
0583 static const struct hdmi_codec_ops dp_audio_codec_ops = {
0584     .hw_params = dp_audio_hw_params,
0585     .audio_shutdown = dp_audio_shutdown,
0586     .get_eld = dp_audio_get_eld,
0587     .hook_plugged_cb = dp_audio_hook_plugged_cb,
0588 };
0589 
0590 static struct hdmi_codec_pdata codec_data = {
0591     .ops = &dp_audio_codec_ops,
0592     .max_i2s_channels = 8,
0593     .i2s = 1,
0594 };
0595 
0596 int dp_register_audio_driver(struct device *dev,
0597         struct dp_audio *dp_audio)
0598 {
0599     struct dp_audio_private *audio_priv;
0600 
0601     audio_priv = container_of(dp_audio,
0602             struct dp_audio_private, dp_audio);
0603 
0604     audio_priv->audio_pdev = platform_device_register_data(dev,
0605                         HDMI_CODEC_DRV_NAME,
0606                         PLATFORM_DEVID_AUTO,
0607                         &codec_data,
0608                         sizeof(codec_data));
0609     return PTR_ERR_OR_ZERO(audio_priv->audio_pdev);
0610 }
0611 
0612 struct dp_audio *dp_audio_get(struct platform_device *pdev,
0613             struct dp_panel *panel,
0614             struct dp_catalog *catalog)
0615 {
0616     int rc = 0;
0617     struct dp_audio_private *audio;
0618     struct dp_audio *dp_audio;
0619 
0620     if (!pdev || !panel || !catalog) {
0621         DRM_ERROR("invalid input\n");
0622         rc = -EINVAL;
0623         goto error;
0624     }
0625 
0626     audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
0627     if (!audio) {
0628         rc = -ENOMEM;
0629         goto error;
0630     }
0631 
0632     audio->pdev = pdev;
0633     audio->panel = panel;
0634     audio->catalog = catalog;
0635 
0636     dp_audio = &audio->dp_audio;
0637 
0638     dp_catalog_audio_init(catalog);
0639 
0640     return dp_audio;
0641 error:
0642     return ERR_PTR(rc);
0643 }
0644 
0645 void dp_audio_put(struct dp_audio *dp_audio)
0646 {
0647     struct dp_audio_private *audio;
0648 
0649     if (!dp_audio)
0650         return;
0651 
0652     audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
0653 
0654     devm_kfree(&audio->pdev->dev, audio);
0655 }