0001
0002
0003
0004
0005
0006
0007 #include <linux/io.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/dmaengine.h>
0012 #include <linux/dma-mapping.h>
0013 #include <drm/bridge/dw_hdmi.h>
0014 #include <drm/drm_edid.h>
0015 #include <drm/drm_connector.h>
0016
0017 #include <sound/hdmi-codec.h>
0018 #include <sound/asoundef.h>
0019 #include <sound/core.h>
0020 #include <sound/initval.h>
0021 #include <sound/pcm.h>
0022 #include <sound/pcm_drm_eld.h>
0023 #include <sound/pcm_iec958.h>
0024 #include <sound/dmaengine_pcm.h>
0025
0026 #include "dw-hdmi-audio.h"
0027
0028 #define DRIVER_NAME "dw-hdmi-gp-audio"
0029 #define DRV_NAME "hdmi-gp-audio"
0030
0031 struct snd_dw_hdmi {
0032 struct dw_hdmi_audio_data data;
0033 struct platform_device *audio_pdev;
0034 unsigned int pos;
0035 };
0036
0037 struct dw_hdmi_channel_conf {
0038 u8 conf1;
0039 u8 ca;
0040 };
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
0066 { 0x03, 0x00 },
0067 { 0x0b, 0x02 },
0068 { 0x33, 0x08 },
0069 { 0x37, 0x09 },
0070 { 0x3f, 0x0b },
0071 { 0x7f, 0x0f },
0072 { 0xff, 0x13 },
0073 };
0074
0075 static int audio_hw_params(struct device *dev, void *data,
0076 struct hdmi_codec_daifmt *daifmt,
0077 struct hdmi_codec_params *params)
0078 {
0079 struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
0080 u8 ca;
0081
0082 dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
0083
0084 ca = default_hdmi_channel_config[params->channels - 2].ca;
0085
0086 dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
0087 dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
0088
0089 dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
0090 params->iec.status[0] & IEC958_AES0_NONAUDIO);
0091 dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
0092
0093 return 0;
0094 }
0095
0096 static void audio_shutdown(struct device *dev, void *data)
0097 {
0098 }
0099
0100 static int audio_mute_stream(struct device *dev, void *data,
0101 bool enable, int direction)
0102 {
0103 struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
0104
0105 if (!enable)
0106 dw_hdmi_audio_enable(dw->data.hdmi);
0107 else
0108 dw_hdmi_audio_disable(dw->data.hdmi);
0109
0110 return 0;
0111 }
0112
0113 static int audio_get_eld(struct device *dev, void *data,
0114 u8 *buf, size_t len)
0115 {
0116 struct dw_hdmi_audio_data *audio = data;
0117 u8 *eld;
0118
0119 eld = audio->get_eld(audio->hdmi);
0120 if (eld)
0121 memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
0122 else
0123
0124 memset(buf, 0, len);
0125
0126 return 0;
0127 }
0128
0129 static int audio_hook_plugged_cb(struct device *dev, void *data,
0130 hdmi_codec_plugged_cb fn,
0131 struct device *codec_dev)
0132 {
0133 struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
0134
0135 return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
0136 }
0137
0138 static const struct hdmi_codec_ops audio_codec_ops = {
0139 .hw_params = audio_hw_params,
0140 .audio_shutdown = audio_shutdown,
0141 .mute_stream = audio_mute_stream,
0142 .get_eld = audio_get_eld,
0143 .hook_plugged_cb = audio_hook_plugged_cb,
0144 };
0145
0146 static int snd_dw_hdmi_probe(struct platform_device *pdev)
0147 {
0148 struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
0149 struct snd_dw_hdmi *dw;
0150
0151 const struct hdmi_codec_pdata codec_data = {
0152 .i2s = 1,
0153 .spdif = 0,
0154 .ops = &audio_codec_ops,
0155 .max_i2s_channels = 8,
0156 .data = data,
0157 };
0158
0159 dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
0160 if (!dw)
0161 return -ENOMEM;
0162
0163 dw->data = *data;
0164
0165 platform_set_drvdata(pdev, dw);
0166
0167 dw->audio_pdev = platform_device_register_data(&pdev->dev,
0168 HDMI_CODEC_DRV_NAME, 1,
0169 &codec_data,
0170 sizeof(codec_data));
0171
0172 return PTR_ERR_OR_ZERO(dw->audio_pdev);
0173 }
0174
0175 static int snd_dw_hdmi_remove(struct platform_device *pdev)
0176 {
0177 struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
0178
0179 platform_device_unregister(dw->audio_pdev);
0180
0181 return 0;
0182 }
0183
0184 static struct platform_driver snd_dw_hdmi_driver = {
0185 .probe = snd_dw_hdmi_probe,
0186 .remove = snd_dw_hdmi_remove,
0187 .driver = {
0188 .name = DRIVER_NAME,
0189 },
0190 };
0191
0192 module_platform_driver(snd_dw_hdmi_driver);
0193
0194 MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
0195 MODULE_DESCRIPTION("Synopsys Designware HDMI GPA ALSA interface");
0196 MODULE_LICENSE("GPL");
0197 MODULE_ALIAS("platform:" DRIVER_NAME);