Skip to content

Commit c054aa1

Browse files
committed
drm/bridge: lt9611: switch to using the DRM HDMI codec framework
Make the Lontium LT9611 DSI-to-HDMI bridge driver use the DRM HDMI Codec framework. This enables programming of Audio InfoFrames using the HDMI Connector interface and also enables support for the missing features, including the ELD retrieval and better hotplug support. Reviewed-by: Maxime Ripard <[email protected]> Tested-by: Dave Stevenson <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 0beba3f commit c054aa1

File tree

1 file changed

+68
-102
lines changed

1 file changed

+68
-102
lines changed

drivers/gpu/drm/bridge/lontium-lt9611.c

Lines changed: 68 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ struct lt9611 {
4545
struct device_node *dsi1_node;
4646
struct mipi_dsi_device *dsi0;
4747
struct mipi_dsi_device *dsi1;
48-
struct platform_device *audio_pdev;
4948

5049
bool ac_mode;
5150

@@ -855,6 +854,10 @@ static int lt9611_hdmi_clear_infoframe(struct drm_bridge *bridge,
855854
unsigned int mask;
856855

857856
switch (type) {
857+
case HDMI_INFOFRAME_TYPE_AUDIO:
858+
mask = LT9611_INFOFRAME_AUDIO;
859+
break;
860+
858861
case HDMI_INFOFRAME_TYPE_AVI:
859862
mask = LT9611_INFOFRAME_AVI;
860863
break;
@@ -888,6 +891,11 @@ static int lt9611_hdmi_write_infoframe(struct drm_bridge *bridge,
888891
int i;
889892

890893
switch (type) {
894+
case HDMI_INFOFRAME_TYPE_AUDIO:
895+
mask = LT9611_INFOFRAME_AUDIO;
896+
addr = 0x84b2;
897+
break;
898+
891899
case HDMI_INFOFRAME_TYPE_AVI:
892900
mask = LT9611_INFOFRAME_AVI;
893901
addr = 0x8440;
@@ -931,6 +939,55 @@ lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
931939
return MODE_OK;
932940
}
933941

942+
static int lt9611_hdmi_audio_startup(struct drm_connector *connector,
943+
struct drm_bridge *bridge)
944+
{
945+
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
946+
947+
regmap_write(lt9611->regmap, 0x82d6, 0x8c);
948+
regmap_write(lt9611->regmap, 0x82d7, 0x04);
949+
950+
regmap_write(lt9611->regmap, 0x8406, 0x08);
951+
regmap_write(lt9611->regmap, 0x8407, 0x10);
952+
953+
regmap_write(lt9611->regmap, 0x8434, 0xd5);
954+
955+
return 0;
956+
}
957+
958+
static int lt9611_hdmi_audio_prepare(struct drm_connector *connector,
959+
struct drm_bridge *bridge,
960+
struct hdmi_codec_daifmt *fmt,
961+
struct hdmi_codec_params *hparms)
962+
{
963+
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
964+
965+
if (hparms->sample_rate == 48000)
966+
regmap_write(lt9611->regmap, 0x840f, 0x2b);
967+
else if (hparms->sample_rate == 96000)
968+
regmap_write(lt9611->regmap, 0x840f, 0xab);
969+
else
970+
return -EINVAL;
971+
972+
regmap_write(lt9611->regmap, 0x8435, 0x00);
973+
regmap_write(lt9611->regmap, 0x8436, 0x18);
974+
regmap_write(lt9611->regmap, 0x8437, 0x00);
975+
976+
return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
977+
&hparms->cea);
978+
}
979+
980+
static void lt9611_hdmi_audio_shutdown(struct drm_connector *connector,
981+
struct drm_bridge *bridge)
982+
{
983+
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
984+
985+
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
986+
987+
regmap_write(lt9611->regmap, 0x8406, 0x00);
988+
regmap_write(lt9611->regmap, 0x8407, 0x00);
989+
}
990+
934991
static const struct drm_bridge_funcs lt9611_bridge_funcs = {
935992
.attach = lt9611_bridge_attach,
936993
.mode_valid = lt9611_bridge_mode_valid,
@@ -950,6 +1007,10 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
9501007
.hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,
9511008
.hdmi_write_infoframe = lt9611_hdmi_write_infoframe,
9521009
.hdmi_clear_infoframe = lt9611_hdmi_clear_infoframe,
1010+
1011+
.hdmi_audio_startup = lt9611_hdmi_audio_startup,
1012+
.hdmi_audio_prepare = lt9611_hdmi_audio_prepare,
1013+
.hdmi_audio_shutdown = lt9611_hdmi_audio_shutdown,
9531014
};
9541015

9551016
static int lt9611_parse_dt(struct device *dev,
@@ -1003,102 +1064,6 @@ static int lt9611_read_device_rev(struct lt9611 *lt9611)
10031064
return ret;
10041065
}
10051066

1006-
static int lt9611_hdmi_hw_params(struct device *dev, void *data,
1007-
struct hdmi_codec_daifmt *fmt,
1008-
struct hdmi_codec_params *hparms)
1009-
{
1010-
struct lt9611 *lt9611 = data;
1011-
1012-
if (hparms->sample_rate == 48000)
1013-
regmap_write(lt9611->regmap, 0x840f, 0x2b);
1014-
else if (hparms->sample_rate == 96000)
1015-
regmap_write(lt9611->regmap, 0x840f, 0xab);
1016-
else
1017-
return -EINVAL;
1018-
1019-
regmap_write(lt9611->regmap, 0x8435, 0x00);
1020-
regmap_write(lt9611->regmap, 0x8436, 0x18);
1021-
regmap_write(lt9611->regmap, 0x8437, 0x00);
1022-
1023-
return 0;
1024-
}
1025-
1026-
static int lt9611_audio_startup(struct device *dev, void *data)
1027-
{
1028-
struct lt9611 *lt9611 = data;
1029-
1030-
regmap_write(lt9611->regmap, 0x82d6, 0x8c);
1031-
regmap_write(lt9611->regmap, 0x82d7, 0x04);
1032-
1033-
regmap_write(lt9611->regmap, 0x8406, 0x08);
1034-
regmap_write(lt9611->regmap, 0x8407, 0x10);
1035-
1036-
regmap_write(lt9611->regmap, 0x8434, 0xd5);
1037-
1038-
return 0;
1039-
}
1040-
1041-
static void lt9611_audio_shutdown(struct device *dev, void *data)
1042-
{
1043-
struct lt9611 *lt9611 = data;
1044-
1045-
regmap_write(lt9611->regmap, 0x8406, 0x00);
1046-
regmap_write(lt9611->regmap, 0x8407, 0x00);
1047-
}
1048-
1049-
static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
1050-
struct device_node *endpoint,
1051-
void *data)
1052-
{
1053-
struct of_endpoint of_ep;
1054-
int ret;
1055-
1056-
ret = of_graph_parse_endpoint(endpoint, &of_ep);
1057-
if (ret < 0)
1058-
return ret;
1059-
1060-
/*
1061-
* HDMI sound should be located as reg = <2>
1062-
* Then, it is sound port 0
1063-
*/
1064-
if (of_ep.port == 2)
1065-
return 0;
1066-
1067-
return -EINVAL;
1068-
}
1069-
1070-
static const struct hdmi_codec_ops lt9611_codec_ops = {
1071-
.hw_params = lt9611_hdmi_hw_params,
1072-
.audio_shutdown = lt9611_audio_shutdown,
1073-
.audio_startup = lt9611_audio_startup,
1074-
.get_dai_id = lt9611_hdmi_i2s_get_dai_id,
1075-
};
1076-
1077-
static struct hdmi_codec_pdata codec_data = {
1078-
.ops = &lt9611_codec_ops,
1079-
.max_i2s_channels = 8,
1080-
.i2s = 1,
1081-
};
1082-
1083-
static int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611)
1084-
{
1085-
codec_data.data = lt9611;
1086-
lt9611->audio_pdev =
1087-
platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
1088-
PLATFORM_DEVID_AUTO,
1089-
&codec_data, sizeof(codec_data));
1090-
1091-
return PTR_ERR_OR_ZERO(lt9611->audio_pdev);
1092-
}
1093-
1094-
static void lt9611_audio_exit(struct lt9611 *lt9611)
1095-
{
1096-
if (lt9611->audio_pdev) {
1097-
platform_device_unregister(lt9611->audio_pdev);
1098-
lt9611->audio_pdev = NULL;
1099-
}
1100-
}
1101-
11021067
static int lt9611_probe(struct i2c_client *client)
11031068
{
11041069
struct lt9611 *lt9611;
@@ -1162,6 +1127,9 @@ static int lt9611_probe(struct i2c_client *client)
11621127

11631128
i2c_set_clientdata(client, lt9611);
11641129

1130+
/* Disable Audio InfoFrame, enabled by default */
1131+
regmap_update_bits(lt9611->regmap, 0x843d, LT9611_INFOFRAME_AUDIO, 0);
1132+
11651133
lt9611->bridge.funcs = &lt9611_bridge_funcs;
11661134
lt9611->bridge.of_node = client->dev.of_node;
11671135
lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
@@ -1170,6 +1138,9 @@ static int lt9611_probe(struct i2c_client *client)
11701138
lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
11711139
lt9611->bridge.vendor = "Lontium";
11721140
lt9611->bridge.product = "LT9611";
1141+
lt9611->bridge.hdmi_audio_dev = dev;
1142+
lt9611->bridge.hdmi_audio_max_i2s_playback_channels = 8;
1143+
lt9611->bridge.hdmi_audio_dai_port = 2;
11731144

11741145
drm_bridge_add(&lt9611->bridge);
11751146

@@ -1191,10 +1162,6 @@ static int lt9611_probe(struct i2c_client *client)
11911162

11921163
lt9611_enable_hpd_interrupts(lt9611);
11931164

1194-
ret = lt9611_audio_init(dev, lt9611);
1195-
if (ret)
1196-
goto err_remove_bridge;
1197-
11981165
return 0;
11991166

12001167
err_remove_bridge:
@@ -1215,7 +1182,6 @@ static void lt9611_remove(struct i2c_client *client)
12151182
struct lt9611 *lt9611 = i2c_get_clientdata(client);
12161183

12171184
disable_irq(client->irq);
1218-
lt9611_audio_exit(lt9611);
12191185
drm_bridge_remove(&lt9611->bridge);
12201186

12211187
regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);

0 commit comments

Comments
 (0)