Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i2c: tda998x: Register ASoC hdmi-codec and add audio DT binding

Register ASoC HDMI codec for audio functionality and adds device tree
binding for audio configuration.

With the registered HDMI codec the tda998x node can be used like a
regular codec node in ASoC card configurations. HDMI audio info-frame
and audio stream header is generated by the ASoC HDMI codec. The codec
also applies constraints for available sample-rates based on Edid Like
Data from the display. The device tree binding document has been
updated [1].

Part of this patch has been inspired by Jean Francoise's "drm/i2c: tda998x:
Add support of a DT graph of ports"-patch [2]. There may still be some
identical lines left from the original patch and some of the ideas
have come from there.

[1] Documentation/devicetree/bindings/display/bridge/tda998x.txt
[2] http://mailman.alsa-project.org/pipermail/alsa-devel/2015-July/095255.html

Signed-off-by: Jyri Sarha <jsarha@ti.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>

authored by

Jyri Sarha and committed by
Russell King
7e567624 95db3b25

+239 -5
+18
Documentation/devicetree/bindings/display/bridge/tda998x.txt
··· 21 21 - video-ports: 24 bits value which defines how the video controller 22 22 output is wired to the TDA998x input - default: <0x230145> 23 23 24 + - audio-ports: array of 8-bit values, 2 values per one DAI[1]. 25 + The first value defines the DAI type: TDA998x_SPDIF or TDA998x_I2S[2]. 26 + The second value defines the tda998x AP_ENA reg content when the DAI 27 + in question is used. The implementation allows one or two DAIs. If two 28 + DAIs are defined, they must be of different type. 29 + 30 + [1] Documentation/sound/alsa/soc/DAI.txt 31 + [2] include/dt-bindings/display/tda998x.h 32 + 24 33 Example: 34 + 35 + #include <dt-bindings/display/tda998x.h> 25 36 26 37 tda998x: hdmi-encoder { 27 38 compatible = "nxp,tda998x"; ··· 41 30 interrupts = <27 2>; /* falling edge */ 42 31 pinctrl-0 = <&pmx_camera>; 43 32 pinctrl-names = "default"; 33 + video-ports = <0x230145>; 34 + 35 + #sound-dai-cells = <2>; 36 + /* DAI-format AP_ENA reg value */ 37 + audio-ports = < TDA998x_SPDIF 0x04 38 + TDA998x_I2S 0x03>; 39 + 44 40 };
+1
drivers/gpu/drm/i2c/Kconfig
··· 28 28 config DRM_I2C_NXP_TDA998X 29 29 tristate "NXP Semiconductors TDA998X HDMI encoder" 30 30 default m if DRM_TILCDC 31 + select SND_SOC_HDMI_CODEC if SND_SOC 31 32 help 32 33 Support for NXP Semiconductors TDA998X HDMI encoders. 33 34
+210 -3
drivers/gpu/drm/i2c/tda998x_drv.c
··· 20 20 #include <linux/module.h> 21 21 #include <linux/irq.h> 22 22 #include <sound/asoundef.h> 23 + #include <sound/hdmi-codec.h> 23 24 24 25 #include <drm/drmP.h> 25 26 #include <drm/drm_atomic_helper.h> ··· 30 29 #include <drm/i2c/tda998x.h> 31 30 32 31 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) 32 + 33 + struct tda998x_audio_port { 34 + u8 format; /* AFMT_xxx */ 35 + u8 config; /* AP value */ 36 + }; 33 37 34 38 struct tda998x_priv { 35 39 struct i2c_client *cec; ··· 49 43 u8 vip_cntrl_2; 50 44 struct tda998x_audio_params audio_params; 51 45 46 + struct platform_device *audio_pdev; 47 + struct mutex audio_mutex; 48 + 52 49 wait_queue_head_t wq_edid; 53 50 volatile int wq_edid_wait; 54 51 ··· 62 53 63 54 struct drm_encoder encoder; 64 55 struct drm_connector connector; 56 + 57 + struct tda998x_audio_port audio_port[2]; 65 58 }; 66 59 67 60 #define conn_to_tda998x_priv(x) \ ··· 754 743 break; 755 744 756 745 default: 757 - BUG(); 746 + dev_err(&priv->hdmi->dev, "Unsupported I2S format\n"); 758 747 return -EINVAL; 759 748 } 760 749 ··· 1075 1064 tda998x_write_avi(priv, adjusted_mode); 1076 1065 1077 1066 if (priv->audio_params.format != AFMT_UNUSED) { 1067 + mutex_lock(&priv->audio_mutex); 1078 1068 tda998x_configure_audio(priv, 1079 1069 &priv->audio_params, 1080 1070 adjusted_mode->clock); 1071 + mutex_unlock(&priv->audio_mutex); 1081 1072 } 1082 1073 } 1083 1074 } ··· 1180 1167 drm_mode_connector_update_edid_property(connector, edid); 1181 1168 n = drm_add_edid_modes(connector, edid); 1182 1169 priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); 1170 + drm_edid_to_eld(connector, edid); 1171 + 1183 1172 kfree(edid); 1184 1173 1185 1174 return n; ··· 1203 1188 cec_write(priv, REG_CEC_RXSHPDINTENA, 0); 1204 1189 reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); 1205 1190 1191 + if (priv->audio_pdev) 1192 + platform_device_unregister(priv->audio_pdev); 1193 + 1206 1194 if (priv->hdmi->irq) 1207 1195 free_irq(priv->hdmi->irq, priv); 1208 1196 ··· 1215 1197 i2c_unregister_device(priv->cec); 1216 1198 } 1217 1199 1200 + static int tda998x_audio_hw_params(struct device *dev, void *data, 1201 + struct hdmi_codec_daifmt *daifmt, 1202 + struct hdmi_codec_params *params) 1203 + { 1204 + struct tda998x_priv *priv = dev_get_drvdata(dev); 1205 + int i, ret; 1206 + struct tda998x_audio_params audio = { 1207 + .sample_width = params->sample_width, 1208 + .sample_rate = params->sample_rate, 1209 + .cea = params->cea, 1210 + }; 1211 + 1212 + if (!priv->encoder.crtc) 1213 + return -ENODEV; 1214 + 1215 + memcpy(audio.status, params->iec.status, 1216 + min(sizeof(audio.status), sizeof(params->iec.status))); 1217 + 1218 + switch (daifmt->fmt) { 1219 + case HDMI_I2S: 1220 + if (daifmt->bit_clk_inv || daifmt->frame_clk_inv || 1221 + daifmt->bit_clk_master || daifmt->frame_clk_master) { 1222 + dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, 1223 + daifmt->bit_clk_inv, daifmt->frame_clk_inv, 1224 + daifmt->bit_clk_master, 1225 + daifmt->frame_clk_master); 1226 + return -EINVAL; 1227 + } 1228 + for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) 1229 + if (priv->audio_port[i].format == AFMT_I2S) 1230 + audio.config = priv->audio_port[i].config; 1231 + audio.format = AFMT_I2S; 1232 + break; 1233 + case HDMI_SPDIF: 1234 + for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) 1235 + if (priv->audio_port[i].format == AFMT_SPDIF) 1236 + audio.config = priv->audio_port[i].config; 1237 + audio.format = AFMT_SPDIF; 1238 + break; 1239 + default: 1240 + dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); 1241 + return -EINVAL; 1242 + } 1243 + 1244 + if (audio.config == 0) { 1245 + dev_err(dev, "%s: No audio configutation found\n", __func__); 1246 + return -EINVAL; 1247 + } 1248 + 1249 + mutex_lock(&priv->audio_mutex); 1250 + ret = tda998x_configure_audio(priv, 1251 + &audio, 1252 + priv->encoder.crtc->hwmode.clock); 1253 + 1254 + if (ret == 0) 1255 + priv->audio_params = audio; 1256 + mutex_unlock(&priv->audio_mutex); 1257 + 1258 + return ret; 1259 + } 1260 + 1261 + static void tda998x_audio_shutdown(struct device *dev, void *data) 1262 + { 1263 + struct tda998x_priv *priv = dev_get_drvdata(dev); 1264 + 1265 + mutex_lock(&priv->audio_mutex); 1266 + 1267 + reg_write(priv, REG_ENA_AP, 0); 1268 + 1269 + priv->audio_params.format = AFMT_UNUSED; 1270 + 1271 + mutex_unlock(&priv->audio_mutex); 1272 + } 1273 + 1274 + int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable) 1275 + { 1276 + struct tda998x_priv *priv = dev_get_drvdata(dev); 1277 + 1278 + mutex_lock(&priv->audio_mutex); 1279 + 1280 + tda998x_audio_mute(priv, enable); 1281 + 1282 + mutex_unlock(&priv->audio_mutex); 1283 + return 0; 1284 + } 1285 + 1286 + static int tda998x_audio_get_eld(struct device *dev, void *data, 1287 + uint8_t *buf, size_t len) 1288 + { 1289 + struct tda998x_priv *priv = dev_get_drvdata(dev); 1290 + struct drm_mode_config *config = &priv->encoder.dev->mode_config; 1291 + struct drm_connector *connector; 1292 + int ret = -ENODEV; 1293 + 1294 + mutex_lock(&config->mutex); 1295 + list_for_each_entry(connector, &config->connector_list, head) { 1296 + if (&priv->encoder == connector->encoder) { 1297 + memcpy(buf, connector->eld, 1298 + min(sizeof(connector->eld), len)); 1299 + ret = 0; 1300 + } 1301 + } 1302 + mutex_unlock(&config->mutex); 1303 + 1304 + return ret; 1305 + } 1306 + 1307 + static const struct hdmi_codec_ops audio_codec_ops = { 1308 + .hw_params = tda998x_audio_hw_params, 1309 + .audio_shutdown = tda998x_audio_shutdown, 1310 + .digital_mute = tda998x_audio_digital_mute, 1311 + .get_eld = tda998x_audio_get_eld, 1312 + }; 1313 + 1314 + static int tda998x_audio_codec_init(struct tda998x_priv *priv, 1315 + struct device *dev) 1316 + { 1317 + struct hdmi_codec_pdata codec_data = { 1318 + .ops = &audio_codec_ops, 1319 + .max_i2s_channels = 2, 1320 + }; 1321 + int i; 1322 + 1323 + for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++) { 1324 + if (priv->audio_port[i].format == AFMT_I2S && 1325 + priv->audio_port[i].config != 0) 1326 + codec_data.i2s = 1; 1327 + if (priv->audio_port[i].format == AFMT_SPDIF && 1328 + priv->audio_port[i].config != 0) 1329 + codec_data.spdif = 1; 1330 + } 1331 + 1332 + priv->audio_pdev = platform_device_register_data( 1333 + dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, 1334 + &codec_data, sizeof(codec_data)); 1335 + 1336 + return PTR_ERR_OR_ZERO(priv->audio_pdev); 1337 + } 1338 + 1218 1339 /* I2C driver functions */ 1340 + 1341 + static int tda998x_get_audio_ports(struct tda998x_priv *priv, 1342 + struct device_node *np) 1343 + { 1344 + const u32 *port_data; 1345 + u32 size; 1346 + int i; 1347 + 1348 + port_data = of_get_property(np, "audio-ports", &size); 1349 + if (!port_data) 1350 + return 0; 1351 + 1352 + size /= sizeof(u32); 1353 + if (size > 2 * ARRAY_SIZE(priv->audio_port) || size % 2 != 0) { 1354 + dev_err(&priv->hdmi->dev, 1355 + "Bad number of elements in audio-ports dt-property\n"); 1356 + return -EINVAL; 1357 + } 1358 + 1359 + size /= 2; 1360 + 1361 + for (i = 0; i < size; i++) { 1362 + u8 afmt = be32_to_cpup(&port_data[2*i]); 1363 + u8 ena_ap = be32_to_cpup(&port_data[2*i+1]); 1364 + 1365 + if (afmt != AFMT_SPDIF && afmt != AFMT_I2S) { 1366 + dev_err(&priv->hdmi->dev, 1367 + "Bad audio format %u\n", afmt); 1368 + return -EINVAL; 1369 + } 1370 + 1371 + priv->audio_port[i].format = afmt; 1372 + priv->audio_port[i].config = ena_ap; 1373 + } 1374 + 1375 + if (priv->audio_port[0].format == priv->audio_port[1].format) { 1376 + dev_err(&priv->hdmi->dev, 1377 + "There can only be on I2S port and one SPDIF port\n"); 1378 + return -EINVAL; 1379 + } 1380 + return 0; 1381 + } 1219 1382 1220 1383 static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) 1221 1384 { ··· 1511 1312 if (!np) 1512 1313 return 0; /* non-DT */ 1513 1314 1514 - /* get the optional video properties */ 1315 + /* get the device tree parameters */ 1515 1316 ret = of_property_read_u32(np, "video-ports", &video); 1516 1317 if (ret == 0) { 1517 1318 priv->vip_cntrl_0 = video >> 16; ··· 1519 1320 priv->vip_cntrl_2 = video; 1520 1321 } 1521 1322 1522 - return 0; 1323 + mutex_init(&priv->audio_mutex); /* Protect access from audio thread */ 1523 1324 1325 + ret = tda998x_get_audio_ports(priv, np); 1326 + if (ret) 1327 + goto fail; 1328 + 1329 + if (priv->audio_port[0].format != AFMT_UNUSED) 1330 + tda998x_audio_codec_init(priv, &client->dev); 1331 + 1332 + return 0; 1524 1333 fail: 1525 1334 /* if encoder_init fails, the encoder slave is never registered, 1526 1335 * so cleanup here:
+3 -2
include/drm/i2c/tda998x.h
··· 2 2 #define __DRM_I2C_TDA998X_H__ 3 3 4 4 #include <linux/hdmi.h> 5 + #include <dt-bindings/display/tda998x.h> 5 6 6 7 enum { 7 8 AFMT_UNUSED = 0, 8 - AFMT_SPDIF = 1, 9 - AFMT_I2S = 2, 9 + AFMT_SPDIF = TDA998x_SPDIF, 10 + AFMT_I2S = TDA998x_I2S, 10 11 }; 11 12 12 13 struct tda998x_audio_params {
+7
include/dt-bindings/display/tda998x.h
··· 1 + #ifndef _DT_BINDINGS_TDA998X_H 2 + #define _DT_BINDINGS_TDA998X_H 3 + 4 + #define TDA998x_SPDIF 1 5 + #define TDA998x_I2S 2 6 + 7 + #endif /*_DT_BINDINGS_TDA998X_H */