linux-stable/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
Uwe Kleine-König ed58ee126c drm/bridge: dw-hdmi-i2s-audio: Convert to platform remove callback returning void
The .remove() callback for a platform driver returns an int which makes
many driver authors wrongly assume it's possible to do error handling by
returning an error code. However the value returned is (mostly) ignored
and this typically results in resource leaks. To improve here there is a
quest to make the remove callback return void. In the first step of this
quest all drivers are converted to .remove_new() which already returns
void.

Trivially convert this driver from always returning zero in the remove
callback to the void returning variant.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230318190804.234610-18-u.kleine-koenig@pengutronix.de
2023-03-20 11:51:55 +01:00

238 lines
5.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* dw-hdmi-i2s-audio.c
*
* Copyright (c) 2017 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <drm/bridge/dw_hdmi.h>
#include <drm/drm_crtc.h>
#include <sound/hdmi-codec.h>
#include "dw-hdmi.h"
#include "dw-hdmi-audio.h"
#define DRIVER_NAME "dw-hdmi-i2s-audio"
static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
u8 val, int offset)
{
struct dw_hdmi *hdmi = audio->hdmi;
audio->write(hdmi, val, offset);
}
static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
{
struct dw_hdmi *hdmi = audio->hdmi;
return audio->read(hdmi, offset);
}
static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms)
{
struct dw_hdmi_i2s_audio_data *audio = data;
struct dw_hdmi *hdmi = audio->hdmi;
u8 conf0 = 0;
u8 conf1 = 0;
u8 inputclkfs = 0;
/* it cares I2S only */
if (fmt->bit_clk_provider | fmt->frame_clk_provider) {
dev_err(dev, "unsupported clock settings\n");
return -EINVAL;
}
/* Reset the FIFOs before applying new params */
hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ);
inputclkfs = HDMI_AUD_INPUTCLKFS_64FS;
conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0);
/* Enable the required i2s lanes */
switch (hparms->channels) {
case 7 ... 8:
conf0 |= HDMI_AUD_CONF0_I2S_EN3;
fallthrough;
case 5 ... 6:
conf0 |= HDMI_AUD_CONF0_I2S_EN2;
fallthrough;
case 3 ... 4:
conf0 |= HDMI_AUD_CONF0_I2S_EN1;
/* Fall-thru */
}
switch (hparms->sample_width) {
case 16:
conf1 = HDMI_AUD_CONF1_WIDTH_16;
break;
case 24:
case 32:
conf1 = HDMI_AUD_CONF1_WIDTH_24;
break;
}
switch (fmt->fmt) {
case HDMI_I2S:
conf1 |= HDMI_AUD_CONF1_MODE_I2S;
break;
case HDMI_RIGHT_J:
conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J;
break;
case HDMI_LEFT_J:
conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J;
break;
case HDMI_DSP_A:
conf1 |= HDMI_AUD_CONF1_MODE_BURST_1;
break;
case HDMI_DSP_B:
conf1 |= HDMI_AUD_CONF1_MODE_BURST_2;
break;
default:
dev_err(dev, "unsupported format\n");
return -EINVAL;
}
dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
dw_hdmi_set_channel_status(hdmi, hparms->iec.status);
dw_hdmi_set_channel_count(hdmi, hparms->channels);
dw_hdmi_set_channel_allocation(hdmi, hparms->cea.channel_allocation);
hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
hdmi_write(audio, conf0, HDMI_AUD_CONF0);
hdmi_write(audio, conf1, HDMI_AUD_CONF1);
return 0;
}
static int dw_hdmi_i2s_audio_startup(struct device *dev, void *data)
{
struct dw_hdmi_i2s_audio_data *audio = data;
struct dw_hdmi *hdmi = audio->hdmi;
dw_hdmi_audio_enable(hdmi);
return 0;
}
static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
{
struct dw_hdmi_i2s_audio_data *audio = data;
struct dw_hdmi *hdmi = audio->hdmi;
dw_hdmi_audio_disable(hdmi);
}
static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf,
size_t len)
{
struct dw_hdmi_i2s_audio_data *audio = data;
u8 *eld;
eld = audio->get_eld(audio->hdmi);
if (eld)
memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
else
/* Pass en empty ELD if connector not available */
memset(buf, 0, len);
return 0;
}
static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
struct device_node *endpoint)
{
struct of_endpoint of_ep;
int ret;
ret = of_graph_parse_endpoint(endpoint, &of_ep);
if (ret < 0)
return ret;
/*
* HDMI sound should be located as reg = <2>
* Then, it is sound port 0
*/
if (of_ep.port == 2)
return 0;
return -EINVAL;
}
static int dw_hdmi_i2s_hook_plugged_cb(struct device *dev, void *data,
hdmi_codec_plugged_cb fn,
struct device *codec_dev)
{
struct dw_hdmi_i2s_audio_data *audio = data;
struct dw_hdmi *hdmi = audio->hdmi;
return dw_hdmi_set_plugged_cb(hdmi, fn, codec_dev);
}
static const struct hdmi_codec_ops dw_hdmi_i2s_ops = {
.hw_params = dw_hdmi_i2s_hw_params,
.audio_startup = dw_hdmi_i2s_audio_startup,
.audio_shutdown = dw_hdmi_i2s_audio_shutdown,
.get_eld = dw_hdmi_i2s_get_eld,
.get_dai_id = dw_hdmi_i2s_get_dai_id,
.hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb,
};
static int snd_dw_hdmi_probe(struct platform_device *pdev)
{
struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
struct platform_device_info pdevinfo;
struct hdmi_codec_pdata pdata;
struct platform_device *platform;
memset(&pdata, 0, sizeof(pdata));
pdata.ops = &dw_hdmi_i2s_ops;
pdata.i2s = 1;
pdata.max_i2s_channels = 8;
pdata.data = audio;
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.parent = pdev->dev.parent;
pdevinfo.id = PLATFORM_DEVID_AUTO;
pdevinfo.name = HDMI_CODEC_DRV_NAME;
pdevinfo.data = &pdata;
pdevinfo.size_data = sizeof(pdata);
pdevinfo.dma_mask = DMA_BIT_MASK(32);
platform = platform_device_register_full(&pdevinfo);
if (IS_ERR(platform))
return PTR_ERR(platform);
dev_set_drvdata(&pdev->dev, platform);
return 0;
}
static void snd_dw_hdmi_remove(struct platform_device *pdev)
{
struct platform_device *platform = dev_get_drvdata(&pdev->dev);
platform_device_unregister(platform);
}
static struct platform_driver snd_dw_hdmi_driver = {
.probe = snd_dw_hdmi_probe,
.remove_new = snd_dw_hdmi_remove,
.driver = {
.name = DRIVER_NAME,
},
};
module_platform_driver(snd_dw_hdmi_driver);
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);