On Mon, Feb 03, 2025 at 04:23:56PM -0300, rafael@xxxxxxxx wrote: > From: Rafael Beims <rafael.beims@xxxxxxxxxxx> > > Add support for HDMI codec with audio coming from the I2S input. > Support 48kHz and 96kHz sample rate, with 16 bits word size. > > Co-developed-by: João Paulo Gonçalves <joao.goncalves@xxxxxxxxxxx> > Signed-off-by: João Paulo Gonçalves <joao.goncalves@xxxxxxxxxxx> > Signed-off-by: Rafael Beims <rafael.beims@xxxxxxxxxxx> Please turn the bridge to support DRM_BRIDGE_OP_HDMI and then use drm_hdmi_audio_helper features to provide audio support. Your implementations misses ELD, plugged callback, etc. > --- > drivers/gpu/drm/bridge/Kconfig | 1 + > drivers/gpu/drm/bridge/lontium-lt8912b.c | 107 ++++++++++++++++++++++- > 2 files changed, 107 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig > index 6b4664d91faa..489ce1041203 100644 > --- a/drivers/gpu/drm/bridge/Kconfig > +++ b/drivers/gpu/drm/bridge/Kconfig > @@ -117,6 +117,7 @@ config DRM_ITE_IT6505 > > config DRM_LONTIUM_LT8912B > tristate "Lontium LT8912B DSI/HDMI bridge" > + select SND_SOC_HDMI_CODEC if SND_SOC > depends on OF > select DRM_PANEL_BRIDGE > select DRM_KMS_HELPER > diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c > index 52da204f5740..2100b41e5f61 100644 > --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c > +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c > @@ -8,6 +8,8 @@ > #include <linux/gpio/consumer.h> > #include <linux/i2c.h> > #include <linux/media-bus-format.h> > +#include <linux/of_graph.h> > +#include <linux/platform_device.h> > #include <linux/regmap.h> > > #include <drm/drm_probe_helper.h> > @@ -16,6 +18,8 @@ > #include <drm/drm_mipi_dsi.h> > #include <drm/drm_of.h> > > +#include <sound/hdmi-codec.h> > + > #include <video/videomode.h> > > #define I2C_MAIN 0 > @@ -24,7 +28,10 @@ > #define I2C_CEC_DSI 1 > #define I2C_ADDR_CEC_DSI 0x49 > > -#define I2C_MAX_IDX 2 > +#define I2C_AUDIO 2 > +#define I2C_ADDR_AUDIO 0x4a > + > +#define I2C_MAX_IDX 3 > > struct lt8912 { > struct device *dev; > @@ -38,6 +45,7 @@ struct lt8912 { > struct drm_bridge *hdmi_port; > > struct mipi_dsi_device *dsi; > + struct platform_device *audio_pdev; > > struct gpio_desc *gp_reset; > > @@ -226,6 +234,7 @@ static int lt8912_init_i2c(struct lt8912 *lt, struct i2c_client *client) > struct i2c_board_info info[] = { > { I2C_BOARD_INFO("lt8912p0", I2C_ADDR_MAIN), }, > { I2C_BOARD_INFO("lt8912p1", I2C_ADDR_CEC_DSI), }, > + { I2C_BOARD_INFO("lt8912p2", I2C_ADDR_AUDIO), }, > }; > > if (!lt) > @@ -754,6 +763,97 @@ static int lt8912_put_dt(struct lt8912 *lt) > return 0; > } > > +static int lt8912_hdmi_hw_params(struct device *dev, void *data, > + struct hdmi_codec_daifmt *fmt, > + struct hdmi_codec_params *hparms) > +{ > + struct lt8912 *lt = data; > + unsigned int audio_params = 0x08; /* 16 bit word size */ > + > + if (hparms->sample_width != 16) > + return -EINVAL; > + > + if (hparms->sample_rate == 48000) > + audio_params |= 0x20; > + else if (hparms->sample_rate == 96000) > + audio_params |= 0xa0; > + else > + return -EINVAL; > + > + regmap_write(lt->regmap[I2C_AUDIO], 0x0f, audio_params); > + regmap_write(lt->regmap[I2C_AUDIO], 0x35, 0x00); > + regmap_write(lt->regmap[I2C_AUDIO], 0x36, 0x18); > + regmap_write(lt->regmap[I2C_AUDIO], 0x37, 0x00); > + > + return 0; > +} > + > +static int lt8912_audio_startup(struct device *dev, void *data) > +{ > + struct lt8912 *lt = data; > + > + regmap_write(lt->regmap[I2C_AUDIO], 0x34, 0xe2); > + regmap_write(lt->regmap[I2C_AUDIO], 0x3c, 0x60); > + regmap_write(lt->regmap[I2C_AUDIO], 0x07, 0xf0); > + regmap_write(lt->regmap[I2C_AUDIO], 0x06, 0x08); > + > + return 0; > +} > + > +static void lt8912_audio_shutdown(struct device *dev, void *data) > +{ > + struct lt8912 *lt = data; > + > + regmap_write(lt->regmap[I2C_AUDIO], 0x06, 0x00); > + regmap_write(lt->regmap[I2C_AUDIO], 0x07, 0x00); > + regmap_write(lt->regmap[I2C_AUDIO], 0x34, 0x52); > + regmap_write(lt->regmap[I2C_AUDIO], 0x3c, 0x40); > +} > + > +static int lt8912_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; > + > + if (of_ep.port != 2) > + return -EINVAL; > + > + return 0; > +} > + > +static const struct hdmi_codec_ops lt8912_codec_ops = { > + .hw_params = lt8912_hdmi_hw_params, > + .audio_shutdown = lt8912_audio_shutdown, > + .audio_startup = lt8912_audio_startup, > + .get_dai_id = lt8912_hdmi_i2s_get_dai_id, > +}; > + > +static int lt8912_audio_init(struct device *dev, struct lt8912 *lt) > +{ > + struct hdmi_codec_pdata codec_data = { > + .ops = <8912_codec_ops, > + .max_i2s_channels = 2, > + .i2s = 1, > + .data = lt, > + }; > + > + lt->audio_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, > + PLATFORM_DEVID_AUTO, > + &codec_data, sizeof(codec_data)); > + > + return PTR_ERR_OR_ZERO(lt->audio_pdev); > +} > + > +static void lt8912_audio_exit(struct lt8912 *lt) > +{ > + platform_device_unregister(lt->audio_pdev); > +} > + > static int lt8912_probe(struct i2c_client *client) > { > static struct lt8912 *lt; > @@ -788,6 +888,10 @@ static int lt8912_probe(struct i2c_client *client) > if (ret) > goto err_attach; > > + ret = lt8912_audio_init(dev, lt); > + if (ret) > + goto err_attach; > + > return 0; > > err_attach: > @@ -803,6 +907,7 @@ static void lt8912_remove(struct i2c_client *client) > { > struct lt8912 *lt = i2c_get_clientdata(client); > > + lt8912_audio_exit(lt); > drm_bridge_remove(<->bridge); > lt8912_free_i2c(lt); > lt8912_put_dt(lt); > -- > 2.47.2 > -- With best wishes Dmitry