File Index
Files and directories
Sign in
FILE

drm_hdmi_audio_helper.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/display/drm_hdmi_audio_helper.c C
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright (c) 2024 Linaro Ltd
  4 */
  5
  6#include <linux/export.h>
  7#include <linux/mutex.h>
  8#include <linux/of_graph.h>
  9#include <linux/platform_device.h>
 10
 11#include <drm/drm_connector.h>
 12#include <drm/drm_device.h>
 13#include <drm/display/drm_hdmi_audio_helper.h>
 14
 15#include <sound/hdmi-codec.h>
 16
 17static int drm_connector_hdmi_audio_startup(struct device *dev, void *data)
 18{
 19	struct drm_connector *connector = data;
 20	const struct drm_connector_hdmi_audio_funcs *funcs =
 21		connector->hdmi_audio.funcs;
 22
 23	if (funcs->startup)
 24		return funcs->startup(connector);
 25
 26	return 0;
 27}
 28
 29static int drm_connector_hdmi_audio_prepare(struct device *dev, void *data,
 30					    struct hdmi_codec_daifmt *fmt,
 31					    struct hdmi_codec_params *hparms)
 32{
 33	struct drm_connector *connector = data;
 34	const struct drm_connector_hdmi_audio_funcs *funcs =
 35		connector->hdmi_audio.funcs;
 36
 37	return funcs->prepare(connector, fmt, hparms);
 38}
 39
 40static void drm_connector_hdmi_audio_shutdown(struct device *dev, void *data)
 41{
 42	struct drm_connector *connector = data;
 43	const struct drm_connector_hdmi_audio_funcs *funcs =
 44		connector->hdmi_audio.funcs;
 45
 46	return funcs->shutdown(connector);
 47}
 48
 49static int drm_connector_hdmi_audio_mute_stream(struct device *dev, void *data,
 50						bool enable, int direction)
 51{
 52	struct drm_connector *connector = data;
 53	const struct drm_connector_hdmi_audio_funcs *funcs =
 54		connector->hdmi_audio.funcs;
 55
 56	if (funcs->mute_stream)
 57		return funcs->mute_stream(connector, enable, direction);
 58
 59	return -ENOTSUPP;
 60}
 61
 62static int drm_connector_hdmi_audio_get_dai_id(struct snd_soc_component *comment,
 63					       struct device_node *endpoint,
 64					       void *data)
 65{
 66	struct drm_connector *connector = data;
 67	struct of_endpoint of_ep;
 68	int ret;
 69
 70	if (connector->hdmi_audio.dai_port < 0)
 71		return -ENOTSUPP;
 72
 73	ret = of_graph_parse_endpoint(endpoint, &of_ep);
 74	if (ret < 0)
 75		return ret;
 76
 77	if (of_ep.port == connector->hdmi_audio.dai_port)
 78		return 0;
 79
 80	return -EINVAL;
 81}
 82
 83static int drm_connector_hdmi_audio_get_eld(struct device *dev, void *data,
 84					    uint8_t *buf, size_t len)
 85{
 86	struct drm_connector *connector = data;
 87
 88	mutex_lock(&connector->eld_mutex);
 89	memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
 90	mutex_unlock(&connector->eld_mutex);
 91
 92	return 0;
 93}
 94
 95static int drm_connector_hdmi_audio_hook_plugged_cb(struct device *dev,
 96						    void *data,
 97						    hdmi_codec_plugged_cb fn,
 98						    struct device *codec_dev)
 99{
100	struct drm_connector *connector = data;
101
102	mutex_lock(&connector->hdmi_audio.lock);
103
104	connector->hdmi_audio.plugged_cb = fn;
105	connector->hdmi_audio.plugged_cb_dev = codec_dev;
106
107	if (fn)
108		fn(codec_dev, connector->hdmi_audio.last_state);
109
110	mutex_unlock(&connector->hdmi_audio.lock);
111
112	return 0;
113}
114
115void drm_connector_hdmi_audio_plugged_notify(struct drm_connector *connector,
116					     bool plugged)
117{
118	mutex_lock(&connector->hdmi_audio.lock);
119
120	connector->hdmi_audio.last_state = plugged;
121
122	if (connector->hdmi_audio.plugged_cb &&
123	    connector->hdmi_audio.plugged_cb_dev)
124		connector->hdmi_audio.plugged_cb(connector->hdmi_audio.plugged_cb_dev,
125						 connector->hdmi_audio.last_state);
126
127	mutex_unlock(&connector->hdmi_audio.lock);
128}
129EXPORT_SYMBOL(drm_connector_hdmi_audio_plugged_notify);
130
131static const struct hdmi_codec_ops drm_connector_hdmi_audio_ops = {
132	.audio_startup = drm_connector_hdmi_audio_startup,
133	.prepare = drm_connector_hdmi_audio_prepare,
134	.audio_shutdown = drm_connector_hdmi_audio_shutdown,
135	.mute_stream = drm_connector_hdmi_audio_mute_stream,
136	.get_eld = drm_connector_hdmi_audio_get_eld,
137	.get_dai_id = drm_connector_hdmi_audio_get_dai_id,
138	.hook_plugged_cb = drm_connector_hdmi_audio_hook_plugged_cb,
139};
140
141/**
142 * drm_connector_hdmi_audio_init - Initialize HDMI Codec device for the DRM connector
143 * @connector: A pointer to the connector to allocate codec for
144 * @hdmi_codec_dev: device to be used as a parent for the HDMI Codec
145 * @funcs: callbacks for this HDMI Codec
146 * @max_i2s_playback_channels: maximum number of playback I2S channels
147 * @i2s_formats: set of I2S formats (use 0 for a bus-specific set)
148 * @spdif_playback: set if HDMI codec has S/PDIF playback port
149 * @dai_port: sound DAI port, -1 if it is not enabled
150 *
151 * Create a HDMI codec device to be used with the specified connector.
152 *
153 * Returns:
154 * Zero on success, error code on failure.
155 */
156int drm_connector_hdmi_audio_init(struct drm_connector *connector,
157				  struct device *hdmi_codec_dev,
158				  const struct drm_connector_hdmi_audio_funcs *funcs,
159				  unsigned int max_i2s_playback_channels,
160				  u64 i2s_formats,
161				  bool spdif_playback,
162				  int dai_port)
163{
164	struct hdmi_codec_pdata codec_pdata = {
165		.ops = &drm_connector_hdmi_audio_ops,
166		.max_i2s_channels = max_i2s_playback_channels,
167		.i2s = !!max_i2s_playback_channels,
168		.i2s_formats = i2s_formats,
169		.spdif = spdif_playback,
170		.no_i2s_capture = true,
171		.no_spdif_capture = true,
172		.data = connector,
173	};
174	struct platform_device *pdev;
175
176	if (!funcs ||
177	    !funcs->prepare ||
178	    !funcs->shutdown)
179		return -EINVAL;
180
181	connector->hdmi_audio.funcs = funcs;
182	connector->hdmi_audio.dai_port = dai_port;
183
184	pdev = platform_device_register_data(hdmi_codec_dev,
185					     HDMI_CODEC_DRV_NAME,
186					     PLATFORM_DEVID_AUTO,
187					     &codec_pdata, sizeof(codec_pdata));
188	if (IS_ERR(pdev))
189		return PTR_ERR(pdev);
190
191	connector->hdmi_audio.codec_pdev = pdev;
192
193	return 0;
194}
195EXPORT_SYMBOL(drm_connector_hdmi_audio_init);
~/ Read-only file preview.