* Re: [PATCH 2/2] drm/bridge: lt8912b: Add support for audio
2025-02-03 19:23 ` [PATCH 2/2] drm/bridge: lt8912b: Add support for audio rafael
@ 2025-02-03 21:05 ` Rafael Beims
2025-02-04 0:53 ` Dmitry Baryshkov
1 sibling, 0 replies; 6+ messages in thread
From: Rafael Beims @ 2025-02-03 21:05 UTC (permalink / raw)
To: Adrien Grassein, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Joao Paulo Goncalves
Cc: Rafael Beims, dri-devel, devicetree, linux-kernel
On 03/02/2025 16:23, rafael@beims.me wrote:
> From: Rafael Beims <rafael.beims@toradex.com>
>
> 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@toradex.com>
> Signed-off-by: João Paulo Gonçalves <joao.goncalves@toradex.com>
> Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
> ---
> 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);
This patch contains an error, v2 with the fix will follow shortly.
Rafael
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH 2/2] drm/bridge: lt8912b: Add support for audio
2025-02-03 19:23 ` [PATCH 2/2] drm/bridge: lt8912b: Add support for audio rafael
2025-02-03 21:05 ` Rafael Beims
@ 2025-02-04 0:53 ` Dmitry Baryshkov
1 sibling, 0 replies; 6+ messages in thread
From: Dmitry Baryshkov @ 2025-02-04 0:53 UTC (permalink / raw)
To: rafael
Cc: Adrien Grassein, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Joao Paulo Goncalves, Rafael Beims, dri-devel,
devicetree, linux-kernel
On Mon, Feb 03, 2025 at 04:23:56PM -0300, rafael@beims.me wrote:
> From: Rafael Beims <rafael.beims@toradex.com>
>
> 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@toradex.com>
> Signed-off-by: João Paulo Gonçalves <joao.goncalves@toradex.com>
> Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
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
^ permalink raw reply [flat|nested] 6+ messages in thread