X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-linux.git;a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fmsm%2Fhdmi%2Fhdmi.c;h=be522ac6cc81167f24a2f42966d3f69f4d97b0b5;hp=1f4a95eeb348190a01aaa05207abc9c20679982a;hb=b11f1771c9c41aaed46f497640ebbace046eb8ed;hpb=62bdb21787f1bef34924c540bea8641210baf039;ds=sidebyside diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 1f4a95eeb348..be522ac6cc81 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -17,6 +17,9 @@ */ #include +#include + +#include #include "hdmi.h" void hdmi_set_mode(struct hdmi *hdmi, bool power_on) @@ -415,6 +418,114 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char } #endif +/* + * 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; + } + + hdmi_audio_set_sample_rate(hdmi, rate); + 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); + + 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 hdmi_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = dev_get_drvdata(master); @@ -424,6 +535,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) #ifdef CONFIG_OF struct device_node *of_node = dev->of_node; const struct of_device_id *match; + int err; match = of_match_node(dt_match, of_node); if (match && match->data) { @@ -499,6 +611,12 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(hdmi); priv->hdmi = hdmi; + err = msm_hdmi_register_audio_driver(hdmi, dev); + if (err) { + DRM_ERROR("Failed to attach an audio codec %d\n", err); + hdmi->audio_pdev = NULL; + } + return 0; } @@ -509,6 +627,9 @@ static void hdmi_unbind(struct device *dev, struct device *master, struct msm_drm_private *priv = drm->dev_private; if (priv->hdmi) { hdmi_destroy(priv->hdmi); + if (priv->hdmi->audio_pdev) + platform_device_unregister(priv->hdmi->audio_pdev); + priv->hdmi = NULL; } }