[Freedreno] [PATCH] drm/msm/dp: unregister audio driver during unbind
while binding the code always registers a audio driver, however there is no corresponding unregistration done in unbind. This leads to multiple redundant audio platform devices if dp_display_bind and dp_display_unbind happens multiple times during startup. On X13s platform this resulted in 6 to 9 audio codec device instead of just 3 codec devices for 3 dp ports. Fix this by unregistering codecs on unbind. Signed-off-by: Srinivas Kandagatla --- drivers/gpu/drm/msm/dp/dp_audio.c | 12 drivers/gpu/drm/msm/dp/dp_audio.h | 2 ++ drivers/gpu/drm/msm/dp/dp_display.c | 1 + 3 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c index 783e1468..1245c7aa49df 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.c +++ b/drivers/gpu/drm/msm/dp/dp_audio.c @@ -593,6 +593,18 @@ static struct hdmi_codec_pdata codec_data = { .i2s = 1, }; +void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio) +{ + struct dp_audio_private *audio_priv; + + audio_priv = container_of(dp_audio, struct dp_audio_private, dp_audio); + + if (audio_priv->audio_pdev) { + platform_device_unregister(audio_priv->audio_pdev); + audio_priv->audio_pdev = NULL; + } +} + int dp_register_audio_driver(struct device *dev, struct dp_audio *dp_audio) { diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h index 84e5f4a5d26b..4ab78880af82 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.h +++ b/drivers/gpu/drm/msm/dp/dp_audio.h @@ -53,6 +53,8 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev, int dp_register_audio_driver(struct device *dev, struct dp_audio *dp_audio); +void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio); + /** * dp_audio_put() * diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 3e13acdfa7e5..99a38dbe51c0 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -326,6 +326,7 @@ static void dp_display_unbind(struct device *dev, struct device *master, kthread_stop(dp->ev_tsk); dp_power_client_deinit(dp->power); + dp_unregister_audio_driver(dev, dp->audio); dp_aux_unregister(dp->aux); dp->drm_dev = NULL; dp->aux->drm_dev = NULL; -- 2.21.0
Re: [Freedreno] [PATCH 1/3] drm/msm: Fix speed-bin support not to access outside valid memory
On 05/03/2021 14:45, Doug Anderson wrote: Hi, On Fri, Mar 5, 2021 at 2:28 AM Srinivas Kandagatla wrote: On 27/02/2021 00:26, Douglas Anderson wrote: When running the latest kernel on an sc7180 with KASAN I got this splat: BUG: KASAN: slab-out-of-bounds in a6xx_gpu_init+0x618/0x644 Read of size 4 at addr ff8088f36100 by task kworker/7:1/58 CPU: 7 PID: 58 Comm: kworker/7:1 Not tainted 5.11.0+ #3 Hardware name: Google Lazor (rev1 - 2) with LTE (DT) Workqueue: events deferred_probe_work_func Call trace: dump_backtrace+0x0/0x3a8 show_stack+0x24/0x30 dump_stack+0x174/0x1e0 print_address_description+0x70/0x2e4 kasan_report+0x178/0x1bc __asan_report_load4_noabort+0x44/0x50 a6xx_gpu_init+0x618/0x644 adreno_bind+0x26c/0x438 This is because the speed bin is defined like this: gpu_speed_bin: gpu_speed_bin@1d2 { reg = <0x1d2 0x2>; bits = <5 8>; }; As you can see the "length" is 2 bytes. That means that the nvmem subsystem allocates only 2 bytes. The GPU code, however, was casting the pointer allocated by nvmem to a (u32 *) and dereferencing. That's not so good. Let's fix this to just use the nvmem_cell_read_u16() accessor function which simplifies things and also gets rid of the splat. Let's also put an explicit conversion from little endian in place just to make things clear. The nvmem subsystem today is assuming little endian and this makes it clear. Specifically, the way the above sc7180 cell is interpreted: NVMEM: ++++++ | .. | 0x1d3 | 0x1d2 | .. | 0x000 | ++++++ ^ ^ msb lsb You can see that the least significant data is at the lower address which is little endian. NOTE: someone who is truly paying attention might wonder about me picking the "u16" version of this accessor instead of the "u8" (since the value is 8 bits big) or the u32 version (just for fun). At the moment you need to pick the accessor that exactly matches the length the cell was specified as in the device tree. Hopefully future patches to the nvmem subsystem will fix this. Fixes: fe7952c629da ("drm/msm: Add speed-bin support to a618 gpu") Signed-off-by: Douglas Anderson --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 31 +++ 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index ba8e9d3cf0fe..0e2024defd79 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1350,35 +1350,20 @@ static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu, u32 revn) { struct opp_table *opp_table; - struct nvmem_cell *cell; u32 supp_hw = UINT_MAX; - void *buf; - - cell = nvmem_cell_get(dev, "speed_bin"); - /* - * -ENOENT means that the platform doesn't support speedbin which is - * fine - */ - if (PTR_ERR(cell) == -ENOENT) - return 0; - else if (IS_ERR(cell)) { - DRM_DEV_ERROR(dev, - "failed to read speed-bin. Some OPPs may not be supported by hardware"); - goto done; - } + u16 speedbin; + int ret; - buf = nvmem_cell_read(cell, NULL); I think the issue here is not passing len pointer which should return how many bytes the cell is! Then from there we can decide to do le16_to_cpu or le32_to_cpu or not! This will also future proof the code to handle speed_bins of different sizes! I think what you're saying is that you want to copy/paste this code (or something similar) everywhere that accesses an nvmem cell. Is that correct? ...or maybe you can suggest some smaller / shorter code that I'm missing? It depends what the consumer is doing! If it is already aware of what size of data its expecting then you can use nvmem_cell_read_u8/16/32/64 variants, however it wants to do bit more with the data then nvmem_cell_read() should give more flexibility! --- { struct nvmem_cell *cell; ssize_t len; char *ret; int i; *data = 0; cell = nvmem_cell_get(dev, cname); if (IS_ERR(cell)) { if (PTR_ERR(cell) != -EPROBE_DEFER) dev_err(dev, "undefined cell %s\n", cname); return PTR_ERR(cell); } ret = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); if (IS_ERR(ret)) { dev_err(dev, "can't read cell %s\n", cname); return PTR_ERR(ret); } for (i = 0; i < len; i++) *data |= ret[i] << (8 * i); kfree(ret); dev_dbg(dev, "efuse read(%s) = %x, bytes %zd\n", cname, *data, len); return 0; } --- The above code is from cpr_read_efuse() in "cpr.c". I mentioned in the c
Re: [Freedreno] [PATCH 1/3] drm/msm: Fix speed-bin support not to access outside valid memory
On 27/02/2021 00:26, Douglas Anderson wrote: When running the latest kernel on an sc7180 with KASAN I got this splat: BUG: KASAN: slab-out-of-bounds in a6xx_gpu_init+0x618/0x644 Read of size 4 at addr ff8088f36100 by task kworker/7:1/58 CPU: 7 PID: 58 Comm: kworker/7:1 Not tainted 5.11.0+ #3 Hardware name: Google Lazor (rev1 - 2) with LTE (DT) Workqueue: events deferred_probe_work_func Call trace: dump_backtrace+0x0/0x3a8 show_stack+0x24/0x30 dump_stack+0x174/0x1e0 print_address_description+0x70/0x2e4 kasan_report+0x178/0x1bc __asan_report_load4_noabort+0x44/0x50 a6xx_gpu_init+0x618/0x644 adreno_bind+0x26c/0x438 This is because the speed bin is defined like this: gpu_speed_bin: gpu_speed_bin@1d2 { reg = <0x1d2 0x2>; bits = <5 8>; }; As you can see the "length" is 2 bytes. That means that the nvmem subsystem allocates only 2 bytes. The GPU code, however, was casting the pointer allocated by nvmem to a (u32 *) and dereferencing. That's not so good. Let's fix this to just use the nvmem_cell_read_u16() accessor function which simplifies things and also gets rid of the splat. Let's also put an explicit conversion from little endian in place just to make things clear. The nvmem subsystem today is assuming little endian and this makes it clear. Specifically, the way the above sc7180 cell is interpreted: NVMEM: ++++++ | .. | 0x1d3 | 0x1d2 | .. | 0x000 | ++++++ ^ ^ msb lsb You can see that the least significant data is at the lower address which is little endian. NOTE: someone who is truly paying attention might wonder about me picking the "u16" version of this accessor instead of the "u8" (since the value is 8 bits big) or the u32 version (just for fun). At the moment you need to pick the accessor that exactly matches the length the cell was specified as in the device tree. Hopefully future patches to the nvmem subsystem will fix this. Fixes: fe7952c629da ("drm/msm: Add speed-bin support to a618 gpu") Signed-off-by: Douglas Anderson --- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 31 +++ 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index ba8e9d3cf0fe..0e2024defd79 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1350,35 +1350,20 @@ static int a6xx_set_supported_hw(struct device *dev, struct a6xx_gpu *a6xx_gpu, u32 revn) { struct opp_table *opp_table; - struct nvmem_cell *cell; u32 supp_hw = UINT_MAX; - void *buf; - - cell = nvmem_cell_get(dev, "speed_bin"); - /* -* -ENOENT means that the platform doesn't support speedbin which is -* fine -*/ - if (PTR_ERR(cell) == -ENOENT) - return 0; - else if (IS_ERR(cell)) { - DRM_DEV_ERROR(dev, - "failed to read speed-bin. Some OPPs may not be supported by hardware"); - goto done; - } + u16 speedbin; + int ret; - buf = nvmem_cell_read(cell, NULL); I think the issue here is not passing len pointer which should return how many bytes the cell is! Then from there we can decide to do le16_to_cpu or le32_to_cpu or not! This will also future proof the code to handle speed_bins of different sizes! --srini - if (IS_ERR(buf)) { - nvmem_cell_put(cell); + ret = nvmem_cell_read_u16(dev, "speed_bin", &speedbin); + if (ret) { DRM_DEV_ERROR(dev, - "failed to read speed-bin. Some OPPs may not be supported by hardware"); + "failed to read speed-bin (%d). Some OPPs may not be supported by hardware", + ret); goto done; } + speedbin = le16_to_cpu(speedbin); - supp_hw = fuse_to_supp_hw(dev, revn, *((u32 *) buf)); - - kfree(buf); - nvmem_cell_put(cell); + supp_hw = fuse_to_supp_hw(dev, revn, speedbin); done: opp_table = dev_pm_opp_set_supported_hw(dev, &supp_hw, 1); ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH v14 0/4] iommu/arm-smmu: Add runtime pm/sleep support
On 27/07/18 08:02, Vivek Gautam wrote: Sricharan R (3): iommu/arm-smmu: Add pm_runtime/sleep ops iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device iommu/arm-smmu: Add the device_link between masters and smmu Vivek Gautam (1): iommu/arm-smmu: Add support for qcom,smmu-v2 variant .../devicetree/bindings/iommu/arm,smmu.txt | 42 + drivers/iommu/arm-smmu.c | 194 +++-- 2 files changed, 225 insertions(+), 11 deletions(-) MSM8896 audio and display on top of mainline totally depends on this patches, I have been testing various version this series on DB820c for both display and audio. Tested-by: Srinivas Kandagatla --srini ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [PATCH v2] drm: msm: Add ASoC generic hdmi audio codec support.
This patch adds support to generic audio codec via ASoC hdmi-codec infrastucture which is merged recently. Signed-off-by: Srinivas Kandagatla --- Changes since v1: -Fixed typo for 44.1Kz case spotted by Jyri Sarha drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/hdmi/hdmi.c | 120 +++- drivers/gpu/drm/msm/hdmi/hdmi.h | 14 + 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 167a497..7c7a031 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -10,6 +10,7 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM + select SND_SOC_HDMI_CODEC if SND_SOC default y help DRM/KMS driver for MSM/snapdragon. diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 51b9ea5..aada355 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -19,6 +19,7 @@ #include #include +#include #include "hdmi.h" void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) @@ -434,6 +435,114 @@ static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name) return gpio; } +/* + * HDMI audio codec callbacks + */ +static int msm_hdmi_audio_hw_params(struct device *dev, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct hdmi *hdmi = dev_get_drvdata(dev); + unsigned int chan; + unsigned int channel_allocation = 0; + unsigned int rate; + unsigned int level_shift = 0; /* 0dB */ + bool down_mix = false; + + dev_dbg(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate, +params->sample_width, params->cea.channels); + + switch (params->cea.channels) { + case 2: + /* FR and FL speakers */ + channel_allocation = 0; + chan = MSM_HDMI_AUDIO_CHANNEL_2; + break; + case 4: + /* FC, LFE, FR and FL speakers */ + channel_allocation = 0x3; + chan = MSM_HDMI_AUDIO_CHANNEL_4; + break; + case 6: + /* RR, RL, FC, LFE, FR and FL speakers */ + channel_allocation = 0x0B; + chan = MSM_HDMI_AUDIO_CHANNEL_6; + break; + case 8: + /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */ + channel_allocation = 0x1F; + chan = MSM_HDMI_AUDIO_CHANNEL_8; + break; + default: + return -EINVAL; + } + + switch (params->sample_rate) { + case 32000: + rate = HDMI_SAMPLE_RATE_32KHZ; + break; + case 44100: + rate = HDMI_SAMPLE_RATE_44_1KHZ; + break; + case 48000: + rate = HDMI_SAMPLE_RATE_48KHZ; + break; + case 88200: + rate = HDMI_SAMPLE_RATE_88_2KHZ; + break; + case 96000: + rate = HDMI_SAMPLE_RATE_96KHZ; + break; + case 176400: + rate = HDMI_SAMPLE_RATE_176_4KHZ; + break; + case 192000: + rate = HDMI_SAMPLE_RATE_192KHZ; + break; + default: + dev_err(dev, "rate[%d] not supported!\n", + params->sample_rate); + return -EINVAL; + } + + msm_hdmi_audio_set_sample_rate(hdmi, rate); + msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation, + level_shift, down_mix); + + return 0; +} + +static void msm_hdmi_audio_shutdown(struct device *dev) +{ + struct hdmi *hdmi = dev_get_drvdata(dev); + + msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0); +} + +static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = { + .hw_params = msm_hdmi_audio_hw_params, + .audio_shutdown = msm_hdmi_audio_shutdown, +}; + +static struct hdmi_codec_pdata codec_data = { + .ops = &msm_hdmi_audio_codec_ops, + .max_i2s_channels = 8, + .i2s = 1, +}; + +static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) +{ + hdmi->audio_pdev = platform_device_register_data(dev, +HDMI_CODEC_DRV_NAME, +PLATFORM_DEVID_AUTO, +&codec_data, +sizeof(codec_data)); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); + + return 0; +} + static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) { struct drm_devi
Re: [Freedreno] [RFC PATCH] drm: msm: Add ASoC generic hdmi audio codec support.
On 06/06/16 13:23, Jyri Sarha wrote: On 06/03/16 16:56, Srinivas Kandagatla wrote: >This patch adds support to generic audio codec via >ASoC hdmi-codec infrastucture which is merged recently. > I know nothing about msm HW, but from the hdmi-codec point of view this looks like a correct usage. However, the hdmi-codec could probably do more to connect the hdmi audio infoframe's channel allocation field and ALSA's channel mapping API together. Yes, that would be nice to get the channel allocation into hdmi-codec. There looks to be a bug in selecting 44100 sample rate bellow. Thanks for spotting this, yes this looks like a typo, I will fix this in v2. Thanks, srini BR, Jyri >Signed-off-by: Srinivas Kandagatla >--- > drivers/gpu/drm/msm/Kconfig | 1 + > drivers/gpu/drm/msm/hdmi/hdmi.c | 120 +++- > drivers/gpu/drm/msm/hdmi/hdmi.h | 14 + > 3 files changed, 134 insertions(+), 1 deletion(-) >diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c >index 51b9ea5..3281496 100644 >--- a/drivers/gpu/drm/msm/hdmi/hdmi.c >+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c >@@ -19,6 +19,7 @@ > #include > #include > >+#include > #include "hdmi.h" > > void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) >@@ -434,6 +435,114 @@ static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name) >return gpio; ... >+ case 32000: >+ rate = HDMI_SAMPLE_RATE_32KHZ; >+ break; >+ case 44100: >+ rate = HDMI_SAMPLE_RATE_48KHZ; >+ break; This looks like a bug... ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
[Freedreno] [RFC PATCH] drm: msm: Add ASoC generic hdmi audio codec support.
This patch adds support to generic audio codec via ASoC hdmi-codec infrastucture which is merged recently. Signed-off-by: Srinivas Kandagatla --- drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/hdmi/hdmi.c | 120 +++- drivers/gpu/drm/msm/hdmi/hdmi.h | 14 + 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 167a497..7c7a031 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -10,6 +10,7 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM + select SND_SOC_HDMI_CODEC if SND_SOC default y help DRM/KMS driver for MSM/snapdragon. diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 51b9ea5..3281496 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -19,6 +19,7 @@ #include #include +#include #include "hdmi.h" void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) @@ -434,6 +435,114 @@ static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name) return gpio; } +/* + * HDMI audio codec callbacks + */ +static int msm_hdmi_audio_hw_params(struct device *dev, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct hdmi *hdmi = dev_get_drvdata(dev); + unsigned int chan; + unsigned int channel_allocation = 0; + unsigned int rate; + unsigned int level_shift = 0; /* 0dB */ + bool down_mix = false; + + dev_dbg(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate, +params->sample_width, params->cea.channels); + + switch (params->cea.channels) { + case 2: + /* FR and FL speakers */ + channel_allocation = 0; + chan = MSM_HDMI_AUDIO_CHANNEL_2; + break; + case 4: + /* FC, LFE, FR and FL speakers */ + channel_allocation = 0x3; + chan = MSM_HDMI_AUDIO_CHANNEL_4; + break; + case 6: + /* RR, RL, FC, LFE, FR and FL speakers */ + channel_allocation = 0x0B; + chan = MSM_HDMI_AUDIO_CHANNEL_6; + break; + case 8: + /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */ + channel_allocation = 0x1F; + chan = MSM_HDMI_AUDIO_CHANNEL_8; + break; + default: + return -EINVAL; + } + + switch (params->sample_rate) { + case 32000: + rate = HDMI_SAMPLE_RATE_32KHZ; + break; + case 44100: + rate = HDMI_SAMPLE_RATE_48KHZ; + break; + case 48000: + rate = HDMI_SAMPLE_RATE_48KHZ; + break; + case 88200: + rate = HDMI_SAMPLE_RATE_88_2KHZ; + break; + case 96000: + rate = HDMI_SAMPLE_RATE_96KHZ; + break; + case 176400: + rate = HDMI_SAMPLE_RATE_176_4KHZ; + break; + case 192000: + rate = HDMI_SAMPLE_RATE_192KHZ; + break; + default: + dev_err(dev, "rate[%d] not supported!\n", + params->sample_rate); + return -EINVAL; + } + + msm_hdmi_audio_set_sample_rate(hdmi, rate); + msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation, + level_shift, down_mix); + + return 0; +} + +static void msm_hdmi_audio_shutdown(struct device *dev) +{ + struct hdmi *hdmi = dev_get_drvdata(dev); + + msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0); +} + +static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = { + .hw_params = msm_hdmi_audio_hw_params, + .audio_shutdown = msm_hdmi_audio_shutdown, +}; + +static struct hdmi_codec_pdata codec_data = { + .ops = &msm_hdmi_audio_codec_ops, + .max_i2s_channels = 8, + .i2s = 1, +}; + +static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) +{ + hdmi->audio_pdev = platform_device_register_data(dev, +HDMI_CODEC_DRV_NAME, +PLATFORM_DEVID_AUTO, +&codec_data, +sizeof(codec_data)); + if (IS_ERR(hdmi->audio_pdev)) + return PTR_ERR(hdmi->audio_pdev); + + return 0; +} + static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = dev_get_drvdata(master); @@ -441,7 +550,7 @@ static int msm_hdmi_bind(struc