media: i2c: it6625: add HDMI audio capture over I2S
Subsystems (4)
cover media: i2c: it6625: add HDMI audio capture over I2S
IT6625 and IT6626 decode the audio of their HDMI input and output it on an I2S interface, driving the bit and frame clocks themselves. The audio format is not configurable by the host; the bridge reports the stream it passes through in read-only status registers.
This series adds an ASoC capture DAI to the IT6625 V4L2 driver, so that this audio can be recorded through a SoC I2S controller, for example with simple-audio-card.
Patch 1 adds the '#sound-dai-cells' and 'ite,i2s-data-lanes' properties to the binding.
Patch 2 documents the existing driver-specific audio controls. Patch 3 decodes the audio status registers with FIELD_GET() and reads them in one place.
Patch 4 adds the I2S capture DAI for LPCM.
Patch 5 extends the DAI to compressed (IEC 61937) and HBR streams, and adds a read-only audio type control.
The series is based on media next and does not depend on the pending IT6625 reset timing [1] and DV timings [2] series; either applies before or after this one.
Tested by capturing HDMI audio from a signal generator, a PC and a second HDMI output looped back to the bridge, through an SoC I2S controller with simple-audio-card:
- LPCM at 32 kHz to 192 kHz with 2 channels on one data line and 8 channels on four data lines, from 16-bit and 24-bit sources. 128 kHz was not captured, as the I2S controller used does not support it.
- AC-3, DTS-HD and TrueHD bitstreams, captured bit-exact, including high bit rate streams on four data lines.
- Rate, channel and coding changes, unplug, AV mute and pause/resume while capturing, and the audio controls with no capture open.
One-bit, multi-stream and 3D audio could not be tested; the driver rejects them.
[1] https://lore.kernel.org/r/20261007-upstream-it6625-reset-delay-v2-0-c5d6b2522bbe@ite.com.tw
[2] https://lore.kernel.org/r/20261103-upstream-it6625-dv-timings-fix-v2-0-127b879da6d3@ite.com.tw
---
Hermes Wu (5):
dt-bindings: media: ite,it6625: add audio DAI properties
media: Documentation: it6625: document the audio controls
media: i2c: it6625: decode audio status fields with FIELD_GET()
media: i2c: it6625: add I2S audio capture DAI
media: i2c: it6625: capture compressed and HBR audio, not just LPCM
.../devicetree/bindings/media/i2c/ite,it6625.yaml | 23 +- .../userspace-api/media/drivers/index.rst | 1 + .../userspace-api/media/drivers/it6625.rst | 48 ++ MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/it6625.c | 879 +++++++++++++++++++-- include/uapi/linux/it6625.h | 25 + 7 files changed, 899 insertions(+), 79 deletions(-)
---
base-commit: d7e7bca7169873b46e857c025c10f3336c1258d8
change-id: 20261019-upstream-it6625-alsa-i2s-9a8e34878dbc
Best regards,
Signature · 1 line
Hermes Wu <[email protected]>
PATCH 1/5 dt-bindings: media: ite,it6625: add audio DAI properties
IT6625 and IT6626 decode the HDMI audio stream and output it on an I2S interface, driving the bit and frame clocks themselves. The bridge has up to eight I2S data pins.
Add '#sound-dai-cells' so the bridge can be referenced as an audio codec DAI, and 'ite,i2s-data-lanes' to describe which data pins are connected to the audio receiver, in HDMI channel-pair order. Without the property only SD0 is connected.
--- .../devicetree/bindings/media/i2c/ite,it6625.yaml | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/media/i2c/ite,it6625.yaml +22 -1
@@ -43,6 +43,23 @@ properties: ovdd-supply: description: I/O supply voltage + '#sound-dai-cells': + const: 0 + + ite,i2s-data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + uniqueItems: true + items: + enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ] + description: + I2S audio data pins (SD0 - SD7) that are connected to the audio + receiver, in HDMI channel-pair order. The first entry is the pin + carrying HDMI channels 1 and 2, the second the pin carrying channels 3 + and 4, and so on. The bridge drives the I2S bit and frame clocks. If + the property is absent, only SD0 is connected. + ports: $ref: /schemas/graph.yaml#/properties/ports properties:
@@ -111,6 +128,7 @@ required: - ovdd-supply allOf: + - $ref: /schemas/sound/dai-common.yaml# - if: properties: compatible:
@@ -131,7 +149,7 @@ allOf: required: - bus-type -additionalProperties: false +unevaluatedProperties: false examples: - |
@@ -153,6 +171,9 @@ examples: vdd33-supply = <&vdd33_reg>; ovdd-supply = <&ovdd_reg>; + #sound-dai-cells = <0>; + ite,i2s-data-lanes = <0 1 2 3>; + ports { #address-cells = <1>; #size-cells = <0>;
Signature · 1 line
2.34.1
Re: [PATCH 1/5] dt-bindings: media: ite,it6625: add audio DAI properties
Quoted 9 lines · Hermes Wu
IT6625 and IT6626 decode the HDMI audio stream and output it on an I2S interface, driving the bit and frame clocks themselves. The bridge has up to eight I2S data pins.
Add '#sound-dai-cells' so the bridge can be referenced as an audio codec DAI, and 'ite,i2s-data-lanes' to describe which data pins are connected to the audio receiver, in HDMI channel-pair order. Without the property only SD0 is connected.
Quoted 4 lines
Signed-off-by Hermes Wu <[email protected]>--- .../devicetree/bindings/media/i2c/ite,it6625.yaml | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
Best regards,
Krzysztof
RE: [PATCH 1/5] dt-bindings: media: ite,it6625: add audio DAI properties
Hi Krzysztof
Quoted 18 lines
-----Original Message-----
From: Krzysztof Kozlowski <[email protected]>
Sent: Wednesday, November 4, 2026 10:24 PM
To: Hermes Wu (吳佳宏) <[email protected]>
Cc: Mauro Carvalho Chehab <[email protected]>; Rob Herring <[email protected]>; Krzysztof Kozlowski <[email protected]>; Conor Dooley <[email protected]>; Hans Verkuil <[email protected]>; [email protected]; [email protected]; [email protected]; Mark Brown <[email protected]>; Liam Girdwood <[email protected]>; [email protected]; [email protected]
Subject: Re: [PATCH 1/5] dt-bindings: media: ite,it6625: add audio DAI propertiesQuoted 9 lines · Hermes Wu
IT6625 and IT6626 decode the HDMI audio stream and output it on an I2S interface, driving the bit and frame clocks themselves. The bridge has up to eight I2S data pins.
Add '#sound-dai-cells' so the bridge can be referenced as an audio codec DAI, and 'ite,i2s-data-lanes' to describe which data pins are connected to the audio receiver, in HDMI channel-pair order. Without the property only SD0 is connected.
Quoted 7 lines
Quoted 5 lines
Signed-off-by Hermes Wu <[email protected]>--- .../devicetree/bindings/media/i2c/ite,it6625.yaml | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)Reviewed-by Krzysztof Kozlowski <[email protected]>
Thanks for your review.
Quoted 4 lines
Best regards,
Krzysztof
PATCH 2/5 media: Documentation: it6625: document the audio controls
In reply to Hermes WuThe IT6625 driver exposes two read-only driver-specific controls, V4L2_CID_IT6625_AUDIO_SAMPLING_RATE and V4L2_CID_IT6625_AUDIO_PRESENT, which so far are described only in the uAPI header.
Add a page for the driver to the V4L2 driver-specific documentation that describes both controls, and list it in MAINTAINERS.
--- Documentation/userspace-api/media/drivers/index.rst | 1 + Documentation/userspace-api/media/drivers/it6625.rst | 18 ++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 20 insertions(+)
Documentation/userspace-api/media/drivers/index.rst +1 -0
@@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux. dcmipp dw100 imx-uapi + it6625 mali-c55 max2175 npcm-video
Documentation/userspace-api/media/drivers/it6625.rst new file +18 -0
@@ -0,0 +1,18 @@ +.. SPDX-License-Identifier: GPL-2.0 + +ITE IT6625/IT6626 HDMI to MIPI bridge driver +============================================ + +The IT6625 driver implements the following driver-specific controls. All of +them are read-only and describe the audio of the HDMI input. + +``V4L2_CID_IT6625_AUDIO_SAMPLING_RATE (integer)`` +------------------------------------------------- + The sampling rate of the HDMI audio stream, in Hz. 0 means that the rate + is not available: there is no stable input signal or no audio, the bridge + reported a rate code that the driver does not recognize, or reading the + audio status failed. + +``V4L2_CID_IT6625_AUDIO_PRESENT (boolean)`` +------------------------------------------- + Whether the bridge currently receives HDMI audio.
MAINTAINERS +1 -0
@@ -13972,6 +13972,7 @@ M: Hermes Wu <[email protected]> S: Maintained T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ite,it6625.yaml +F: Documentation/userspace-api/media/drivers/it6625.rst F: drivers/media/i2c/it6625.c F: include/uapi/linux/it6625.h
Signature · 1 line
2.34.1
Re: [PATCH 2/5] media: Documentation: it6625: document the audio controls
Hi Hermes,
Quoted 42 lines · On 03/11/2026 07:50, Hermes Wu via B4 Relay wrote:
From: Hermes Wu <[email protected]>
The IT6625 driver exposes two read-only driver-specific controls,
V4L2_CID_IT6625_AUDIO_SAMPLING_RATEandV4L2_CID_IT6625_AUDIO_PRESENT, which so far are described only in the uAPI header.Add a page for the driver to the V4L2 driver-specific documentation that describes both controls, and list it in
MAINTAINERS.Signed-off-by Hermes Wu <[email protected]>--- Documentation/userspace-api/media/drivers/index.rst | 1 + Documentation/userspace-api/media/drivers/it6625.rst | 18 ++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 20 insertions(+)Documentation/userspace-api/media/drivers/index.rst +1
-0@@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux. dcmipp dw100 imx-uapi + it6625 mali-c55 max2175 npcm-videoDocumentation/userspace-api/media/drivers/it6625.rst new file +8
-0@@ -0,0 +1,18 @@ +.. SPDX-License-Identifier: GPL-2.0 + +ITE IT6625/IT6626 HDMI to MIPI bridge driver +============================================ + +The IT6625 driver implements the following driver-specific controls. All of +them are read-only and describe the audio of the HDMI input. +
Documentation/userspace-api/media/drivers/it6625.rst line 18
Quoted 10 lines
Documentation/userspace-api/media/drivers/it6625.rst new file +10
-0+``V4L2_CID_IT6625_AUDIO_SAMPLING_RATE (integer)`` +------------------------------------------------- + The sampling rate of the HDMI audio stream, in Hz. 0 means that the rate + is not available: there is no stable input signal or no audio, the bridge + reported a rate code that the driver does not recognize, or reading the + audio status failed. + +``V4L2_CID_IT6625_AUDIO_PRESENT (boolean)`` +------------------------------------------- + Whether the bridge currently receives HDMI audio.
Mention in the documentation that these controls are read-only.
We need to make standard controls for the audio sampling rate and presence. They are also used by the tc358743 driver, and are in fact common for all HDMI receiver drivers (I know of a bunch of out-of-tree drivers that use the same controls).
So rather than creating driver-specific controls, can you add standard controls for this? They belong to the V4L2_CID_DV_CLASS control class.
So the defines become:
V4L2_CID_DV_RX_AUDIO_SAMPLING_RATE and V4L2_CID_DV_RX_AUDIO_PRESENT.
This also means that there is no need for a separate it6625.rst.
The tc358743 driver should be extended to also support the new standard controls. So tc358743_s_ctrl_audio_sampling_rate/_present set both the custom and the standard control.
Sorry for this, it is a bit more work but it makes userspace easier since there is a standard control for this instead of having driver-specific controls.
Make sure that the patches adding support to the v4l2 core for these two new standard controls are not mixed with the it656 changes. So first add it to the core, then use it in this driver.
Regards,
Hans
Quoted 13 lines
MAINTAINERS +1
-0@@ -13972,6 +13972,7 @@ M: Hermes Wu <[email protected]> S: Maintained T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ite,it6625.yaml +F: Documentation/userspace-api/media/drivers/it6625.rst F: drivers/media/i2c/it6625.c F: include/uapi/linux/it6625.h
PATCH 3/5 media: i2c: it6625: decode audio status fields with FIELD_GET()
In reply to Hermes WuThe sampling-rate control compares the whole HDMI_AUDIO_INFO1 byte against the AUD_FS code table, although AUD_FS occupies only bits [5:0]. Any set upper bit makes every rate read back as 0.
Describe the audio registers with GENMASK() fields and decode them with FIELD_GET(). Collect the audio status in one helper that runs underit6625_lock: it reads RX_STATUS once, for both the video-stable and the audio-present bits, and reads the read-only stream description in 0x6B-0x6E as a single 4-byte transfer only while audio is present. Both audio controls are then fed from that one sample.
Drop the 0x6E alignment/delay/polarity/shift defines; they were unused, and the audio output framing is fixed by the firmware.
Apart from masking AUD_FS, the controls behave as before: the rate reads 0 when there is no stable signal, no audio, an unknown code or a read error, and the present control follows the audio-present bit.
--- drivers/media/i2c/it6625.c | 206 +++++++++++++++++++++++++++++---------------- 1 file changed, 132 insertions(+), 74 deletions(-)
drivers/media/i2c/it6625.c +132 -74
@@ -83,25 +83,34 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");#define REG_HDMI_VIDEO_INFO 0x6A#define B_COLOR_MODE BIT(0)#define B_COLOR_DEPTH BIT(4) +/* +* 0x6B-0x6E describe the decoded HDMI audio stream that the firmware passes +* through to the audio output. They are read-only and only meaningful while +* REG_RX_STATUS reports audio present. +*/ #define REG_HDMI_AUDIO_INFO1 0x6B -#define B_AUD_FS BIT(0) +#define M_AUD_FS GENMASK(5, 0)#define REG_HDMI_AUDIO_INFO2 0x6C -#define B_AUD_CH BIT(0) -#define B_AUD_WL BIT(4) +#define M_AUD_CH GENMASK(3, 0) +#define M_AUD_WL GENMASK(7, 4)#define REG_HDMI_AUDIO_INFO3 0x6D -#define B_AUD_TYPE BIT(0) +#define M_AUD_TYPE GENMASK(1, 0) +#define AUD_TYPE_LPCM 0#define B_AUD_MS BIT(2)#define B_AUD_3D BIT(3)#define REG_AUDIO_FMT 0x6E -#define B_I2S_WL BIT(0) -#define B_I2S_ALN BIT(2) -#define B_I2S_DLY BIT(3) -#define B_I2S_LR BIT(4) -#define B_I2S_SFT BIT(5) -#define B_AUD_OUT_IF BIT(6) +#define M_I2S_WL GENMASK(1, 0) +#define I2S_WL_16BIT 0 +#define I2S_WL_18BIT 1 +#define I2S_WL_20BIT 2 +#define I2S_WL_24BIT 3 +#define M_AUD_OUT_IF GENMASK(7, 6) +#define AUD_OUT_IF_I2S 0 + +#define AUDIO_INFO_LEN 4#define REG_IF_LATCH_HB 0x6F#define REG_IF_DATA 0x70
@@ -249,6 +258,28 @@ enum it6625_chip_type { IT6626_CHIP = 1, }; +/* decoded 0x6B-0x6E: the HDMI audio stream passed through to the output */ +struct it6625_audio_stream { +u8 fs_code; +u8 channels; +u8 type; +bool multi_stream; +bool is_3d; +u8 i2s_wl; +u8 out_if; +}; + +struct it6625_audio_info { +/* false if any status read failed */ +bool read_ok; +/* REG_RX_STATUS */ +bool vid_stable; +bool present; +bool avmute; +/* only refreshed while present */ +struct it6625_audio_stream stream; +}; +struct it6625 {struct device *dev;struct i2c_client *i2c_client;
@@ -584,61 +615,94 @@ static inline bool no_signal(struct it6625 *it6625)return val <0 ? true : !(val &B_RX_STABLE ); } -static inline bool audio_present (struct it6625 *it6625) +static const struct it6625_audio_rate { +u8 fs_code; +u32 rate; +} it6625_audio_rates[] = { + {AUD32K ,32000 }, + {AUD44K ,44100 }, + {AUD48K ,48000 }, + {AUD64K ,64000 }, + {AUD88K ,88200 }, + {AUD96K ,96000 }, + + {AUD128K ,128000 }, + {AUD176K ,176400 }, + {AUD192K ,192000 }, + {AUD256K ,256000 }, + {AUD352K ,352800 }, + {AUD384K ,384000 }, + + {AUD512K ,512000 }, + {AUD705K ,705600 }, + {AUD768K ,768000 }, + {AUD1024K ,1024000 }, + {AUD1411K ,1411200 }, + {AUD1536K ,1536000 }, +}; + +/* returns 0 for an unknown sampling-frequency code */ +static u32 it6625_audio_fs_to_rate (u8 fs_code) +{ +for (unsigned int i =0 ; i <ARRAY_SIZE (it6625_audio_rates); i++) { +if (it6625_audio_rates[i].fs_code == fs_code) +return it6625_audio_rates[i].rate; + } + +return 0 ; +} + +/* +* Sample the audio status. REG_RX_STATUS is always read; the stream +* description in 0x6B-0x6E is only read while audio is present, otherwise +* info->stream is left untouched. read_ok is false if any read failed. +*/ +static void it6625_read_audio_info (struct it6625 *it6625, +struct it6625_audio_info *info) { +u8 buf[AUDIO_INFO_LEN ];int val; - val =it6625_read_byte (it6625,REG_RX_STATUS ); -return val <0 ? false : val &B_RX_AUD_ON ; -} - -static int get_audio_sampling_rate (struct it6625 *it6625) -{ -static const struct fs_id_map { -u8 fs_id; -u32 freq; - } s_fsid_map[] = { - {AUD32K ,32000 }, - {AUD44K ,44100 }, - {AUD48K ,48000 }, - {AUD64K ,64000 }, - {AUD88K ,88200 }, - {AUD96K ,96000 }, - - {AUD128K ,128000 }, - {AUD176K ,176400 }, - {AUD192K ,192000 }, - {AUD256K ,256000 }, - {AUD352K ,352800 }, - {AUD384K ,384000 }, - - {AUD512K ,512000 }, - {AUD705K ,705600 }, - {AUD768K ,768000 }, - {AUD1024K ,1024000 }, - {AUD1411K ,1411200 }, - {AUD1536K ,1536000 }, - }; -int fs_id; -int i, freq =0 ; +lockdep_assert_held (&it6625->it6625_lock); -if (no_signal (it6625) || !audio_present (it6625)) -return 0 ; + val =it6625_read_byte (it6625,REG_RX_STATUS ); +if (val <0 ) { + info->read_ok = false; + info->vid_stable = false; + info->present = false; + info->avmute = false; +return ; + } -guard (mutex)(&it6625->it6625_lock); + info->read_ok = true; + info->vid_stable = val &B_RX_STABLE ; + info->present = val &B_RX_AUD_ON ; + info->avmute = val &B_RX_AVMUTE ; - fs_id =it6625_read_byte (it6625,REG_HDMI_AUDIO_INFO1 ); -if (fs_id <0 ) -return 0 ; +if (!info->present) +return ; -for (i =0 ; i <ARRAY_SIZE (s_fsid_map); i++) { -if (s_fsid_map[i].fs_id == fs_id) { - freq = s_fsid_map[i].freq; -break ; - } +if (it6625_read_bytes (it6625,REG_HDMI_AUDIO_INFO1 , buf,sizeof (buf))) { + info->read_ok = false; +return ; } -return freq; + info->stream.fs_code =FIELD_GET (M_AUD_FS , buf[0 ]); + info->stream.channels =FIELD_GET (M_AUD_CH , buf[1 ]); + info->stream.type =FIELD_GET (M_AUD_TYPE , buf[2 ]); + info->stream.multi_stream = buf[2 ] &B_AUD_MS ; + info->stream.is_3d = buf[2 ] &B_AUD_3D ; + info->stream.i2s_wl =FIELD_GET (M_I2S_WL , buf[3 ]); + info->stream.out_if =FIELD_GET (M_AUD_OUT_IF , buf[3 ]); +} + +/* sampling rate for the V4L2 control: 0 means unavailable */ +static u32 it6625_audio_info_rate (const struct it6625_audio_info *info) +{ +if (!info->read_ok || !info->vid_stable || !info->present) +return 0 ; + +return it6625_audio_fs_to_rate (info->stream.fs_code); }static u64 it6625_get_pclk (struct it6625 *it6625)
@@ -888,20 +952,21 @@ static int it6625_s_ctrl_detect_hdmi_5v(struct v4l2_subdev *sd) hdmi_5v_power_present(it6625)); } -static int it6625_s_ctrl_audio_sampling_rate (struct v4l2_subdev *sd) +static int it6625_s_ctrl_audio (struct v4l2_subdev *sd) {struct it6625 *it6625 =sd_to_6625 (sd); +struct it6625_audio_info info = {}; +int ret; -return v4l2_ctrl_s_ctrl (it6625->ctrl_audio_sampling_rate, -get_audio_sampling_rate (it6625)); -} + scoped_guard(mutex, &it6625->it6625_lock) +it6625_read_audio_info (it6625, &info); -static int it6625_s_ctrl_audio_present (struct v4l2_subdev *sd) -{ -struct it6625 *it6625 =sd_to_6625 (sd); + ret =v4l2_ctrl_s_ctrl (it6625->ctrl_audio_sampling_rate, +it6625_audio_info_rate (&info)); +if (ret) +return ret; -return v4l2_ctrl_s_ctrl (it6625->ctrl_audio_present, -audio_present (it6625)); +return v4l2_ctrl_s_ctrl (it6625->ctrl_audio_present, info.present); }static int it6625_v4l2_sd_ctrl_update (struct v4l2_subdev *sd)
@@ -912,11 +977,7 @@ static int it6625_v4l2_sd_ctrl_update(struct v4l2_subdev *sd)if (ret)return ret; - ret =it6625_s_ctrl_audio_sampling_rate (sd); -if (ret) -return ret; - -return it6625_s_ctrl_audio_present (sd); +return it6625_s_ctrl_audio (sd); }static int it6625_enable_stream_locked (struct it6625 *it6625,bool enable)
@@ -1165,10 +1226,7 @@ static void it6625_irq_format_change(struct it6625 *it6625)static void it6625_irq_hdmi_audio_change (struct it6625 *it6625) { -struct v4l2_subdev *sd = &it6625->sd; - -it6625_s_ctrl_audio_sampling_rate (sd); -it6625_s_ctrl_audio_present (sd); +it6625_s_ctrl_audio (&it6625->sd); } static void it6625_get_timings(struct it6625 *it6625,
Signature · 1 line
2.34.1
PATCH 4/5 media: i2c: it6625: add I2S audio capture DAI
In reply to Hermes WuIT6625 and IT6626 decode the HDMI audio stream and pass it through to an I2S output. The bridge drives the bit and frame clocks and uses standard I2S framing with 16, 20 or 24 valid bits in 32-bit slots. None of this is host-configurable: 0x6B-0x6E only report the stream being output.
Register an ASoC component with one capture DAI when the device node has '#sound-dai-cells'. The DAI accepts only what the bridge currently
outputs: single-stream, non-3D LPCM at 32 kHz to 192 kHz, S32_LE with the valid bits reported through msbits, and 2 channels per connected I2S data pin (from 'ite,i2s-data-lanes'), up to 8 channels. startup pins these values, and hw_params, prepare and the start and resume triggers check them again against the latest observed status.
The I2S clocks are not guaranteed to keep running at a constant rate when audio is lost, muted or changes format. Any observed change of the audio status, and any status read failure, therefore stops a running capture with an XRUN. A paused stream whose audio changed is still released, and then stopped with an XRUN: refusing the release would leave it paused, where a blocking read waits indefinitely. Changes are observed on the audio-change, video-change, 5V and AV-mute events, and every 200 ms while a capture stream is open, to catch changes that raise no event.
The V4L2 audio controls are updated from the same status sample. The bridge can report audio before the video signal is stable or the sampling-frequency code is valid, and may raise no further event once they are. After an event that leaves audio present without a valid rate, the status is therefore checked again every 200 ms, up to 15 times, also when no capture stream is open.
The component is registered without devm and unregistered first in remove. Unregistering waits for open capture streams to be closed, so no DAI callback can run while the rest of the driver is torn down. Unbind therefore blocks while a capture stream is held open.
The driver still builds without ASoC: the audio code is compiled out when SND_SOC is disabled.
--- drivers/media/i2c/Kconfig | 1 + drivers/media/i2c/it6625.c | 609 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 595 insertions(+), 15 deletions(-)
drivers/media/i2c/Kconfig +1 -0
@@ -1354,6 +1354,7 @@ config VIDEO_IT6625 tristate "IT6625 HDMI to MIPI CSI bridge" depends on VIDEO_DEV && I2C depends on OF + depends on SND_SOC || !SND_SOC select CEC_CORE select HDMI select MEDIA_CONTROLLER
drivers/media/i2c/it6625.c +594 -15
703 lines not on this page · raw message
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH 4/5] media: i2c: it6625: add I2S audio capture DAI
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] media: i2c: it6625: it6625_dai_shutdown() cancels active rate-settle polling - [Medium] media…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] media: i2c: it6625: it6625_dai_shutdown() cancels active rate-settle polling
- [Medium] media: i2c: it6625: it6625_audio_refresh() in DAI ops skips V4L2 ctrl update --
commit 1dfd81c0e8bfaba0b855fe94b881d239f6f65287
Author: Hermes Wu <[email protected]>
media: i2c: it6625: add I2S audio capture DAI
This commit registers an ASoC component and I2S capture DAI for the IT6625 and IT6626 HDMI-to-MIPI bridges when #sound-dai-cells is present in the device tree. It constrains capture streams to the currently observed HDMI audio status, stops active streams on status changes, and polls for audio status updates and rate settling.
Quoted 4 lines
drivers/media/i2c/it6625.c +0
-0
[ ... ]
Quoted 4 lines
drivers/media/i2c/it6625.c +0
-0@@ -2001,6 +2158,369 @@ static int it6625_v4l2_init_controls(struct v4l2_subdev *sd)return 0 ; }
[ ... ]
Quoted 39 lines
drivers/media/i2c/it6625.c +39
-0+static void it6625_audio_refresh_work (struct work_struct *work) +{ +struct it6625 *it6625 =container_of (to_delayed_work (work), + struct it6625, audio_refresh_work); +unsigned long flags; +bool rearm; + +it6625_s_ctrl_audio (&it6625->sd); + +spin_lock_irqsave (&it6625->audio_lock, flags); +/* every run uses up one re-check of a settle budget */ +if (it6625->audio_settle_polls) + it6625->audio_settle_polls--; + rearm = (it6625->audio_substream && !it6625->audio_block) || + (it6625->audio_settle_polls &&it6625_audio_settling (it6625)); +spin_unlock_irqrestore (&it6625->audio_lock, flags); + +if (rearm) +schedule_delayed_work (&it6625->audio_refresh_work, +msecs_to_jiffies (IT6625_AUDIO_REFRESH_MS )); +} + +static struct it6625 *dai_to_6625 (struct snd_soc_dai *dai) +{ +/* the I2C client data is the V4L2 subdev */ +return sd_to_6625 (snd_soc_dai_get_drvdata (dai)); +} + +static int it6625_dai_startup (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +struct it6625 *it6625 =dai_to_6625 (dai); +struct snd_pcm_runtime *runtime = substream->runtime; +struct it6625_audio_info info; +unsigned long flags; +u32 gen; +int ret; + +it6625_audio_refresh (it6625);
[ ... ]
Quoted 10 lines
drivers/media/i2c/it6625.c +10
-0+/* also called on rollback after a successful .startup */ +static void it6625_dai_shutdown (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +struct it6625 *it6625 =dai_to_6625 (dai); +unsigned long flags; + +spin_lock_irqsave (&it6625->audio_lock, flags); + it6625->audio_block = true; +spin_unlock_irqrestore (&it6625->audio_lock, flags);
drivers/media/i2c/it6625.c static int it6625_v4l2_init_controls(struct v4l2_subdev *sd) · line 2364
Quoted 10 lines
drivers/media/i2c/it6625.c +10
-0+ +cancel_delayed_work_sync (&it6625->audio_refresh_work); +cancel_work_sync (&it6625->audio_xrun_work); + +spin_lock_irqsave (&it6625->audio_lock, flags); + it6625->audio_substream =NULL ; + it6625->audio_running = false; + it6625->audio_block = false; +spin_unlock_irqrestore (&it6625->audio_lock, flags); +}
[Severity: Medium]
Can it6625_dai_shutdown() prematurely stop rate-settle polling started by it6625_audio_event()?
If an HDMI format or audio event occurs while a capture stream is running and leaves audio present without a valid sampling rate, it6625_audio_event() performs:
it6625_audio_event()
it6625_s_ctrl_audio()
it6625_audio_refresh()
it6625->audio_gen++;
queue_work(system_wq, &it6625->audio_xrun_work);
if (it6625_audio_settling(it6625)) {
it6625->audio_settle_polls = IT6625_AUDIO_SETTLE_POLLS;
schedule_delayed_work(&it6625->audio_refresh_work, ...);
}Because audio_gen was incremented, subsequent calls to it6625_dai_prepare() or it6625_dai_hw_params() return -EPIPE, so userspace has to close the capture stream to recover.
When userspace closes the stream, it6625_dai_shutdown() runs cancel_delayed_work_sync(&it6625->audio_refresh_work) and does not re-schedule audio_refresh_work after clearing audio_block even when it6625->audio_settle_polls > 0 and it6625_audio_settling(it6625) is still true. If the bridge raises no further interrupt once the rate settles, won't ctrl_audio_sampling_rate and it6625->audio remain stuck at rate 0?
Quoted 40 lines
drivers/media/i2c/it6625.c +40
-0+ +static int it6625_dai_set_fmt (struct snd_soc_dai *dai,unsigned int fmt) +{ +if ((fmt &SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK ) !=SND_SOC_DAIFMT_CBP_CFP || + (fmt &SND_SOC_DAIFMT_FORMAT_MASK ) !=SND_SOC_DAIFMT_I2S || + (fmt &SND_SOC_DAIFMT_INV_MASK ) !=SND_SOC_DAIFMT_NB_NF ) +return -EINVAL ; + +return 0 ; +} + +static int it6625_dai_hw_params (struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params, +struct snd_soc_dai *dai) +{ +struct it6625 *it6625 =dai_to_6625 (dai); +const struct it6625_audio_stream *s; +unsigned long flags; +int ret; + +it6625_audio_refresh (it6625); + +spin_lock_irqsave (&it6625->audio_lock, flags); + ret =it6625_audio_validate_locked (it6625); + s = &it6625->audio_accepted; +if (!ret && + (params_rate (params) !=it6625_audio_fs_to_rate (s->fs_code) || +params_channels (params) != s->channels || +params_format (params) !=SNDRV_PCM_FORMAT_S32_LE )) + ret = -EINVAL ; +spin_unlock_irqrestore (&it6625->audio_lock, flags); + +return ret; +} + +static int it6625_dai_prepare (struct snd_pcm_substream *substream, +struct snd_soc_dai *dai) +{ +struct it6625 *it6625 =dai_to_6625 (dai); +unsigned long flags;
drivers/media/i2c/it6625.c static int it6625_v4l2_init_controls(struct v4l2_subdev *sd) · line 2414
Quoted 10 lines
drivers/media/i2c/it6625.c +10
-0+int ret; + +it6625_audio_refresh (it6625); + +spin_lock_irqsave (&it6625->audio_lock, flags); + ret =it6625_audio_validate_locked (it6625); +spin_unlock_irqrestore (&it6625->audio_lock, flags); + +return ret; +}
[Severity: Medium]
Should it6625_dai_startup(), it6625_dai_hw_params(), and it6625_dai_prepare() call it6625_s_ctrl_audio(&it6625->sd) instead of calling it6625_audio_refresh(it6625) directly?
Calling it6625_audio_refresh() updates it6625->audio and increments it6625->audio_gen when a status change is observed, but skips it6625_audio_update_ctrls().
If an audio change that raised no interrupt is observed by it6625_dai_startup() and causes it6625_audio_check() to fail, startup returns an error without scheduling audio_refresh_work and without updating ctrl_audio_sampling_rate or ctrl_audio_present. Similarly, if it6625_dai_hw_params() or it6625_dai_prepare() observes a change and returns -EPIPE, and userspace closes the substream before audio_refresh_work runs, it6625_dai_shutdown() cancels audio_refresh_work and leaves the v4l2 controls out of sync with the sample stored in it6625->audio.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
PATCH 5/5 media: i2c: it6625: capture compressed and HBR audio, not just LPCM
In reply to Hermes WuThe capture DAI accepts only LPCM. The bridge also outputs compressed IEC 61937 streams (AC-3, DTS, ...) and high bit rate (HBR) streams (Dolby TrueHD/MAT, DTS-HD Master Audio) on the same I2S interface, but these are rejected.
Add it6625_audio_xport(), which derives the I2S frame rate and slot count from the stream's coding type and sampling rate. LPCM is unchanged. A compressed stream is carried in 2 slots at its own sampling rate, except at the HBR rates of 768 kHz and 705.6 kHz, where one IEC 61937 stream is spread over 8 slots on 4 data lines at a quarter of that rate. The bridge firmware also reports the HBR coding type for some compressed streams at ordinary rates, such as 48 kHz DTS, so the sampling rate, not the coding type, selects the layout. A compressed stream at 768 kHz or 705.6 kHz is rejected when fewer than 4 data lines are connected.
Use the derived rate and channel count in the eligibility check, the startup constraints and the hw_params comparison. DSD is still rejected. The driver does not parse the compressed data: userspace receives the IEC 61937 words as they are.
Add a read-only "Audio Type" menu control, V4L2_CID_IT6625_AUDIO_TYPE, so that userspace can tell LPCM, compressed, HBR and DSD streams apart without parsing the audio InfoFrame, and document it.
--- .../userspace-api/media/drivers/it6625.rst | 30 ++++++ drivers/media/i2c/it6625.c | 118 ++++++++++++++++++--- include/uapi/linux/it6625.h | 25 +++++ 3 files changed, 157 insertions(+), 16 deletions(-)
Documentation/userspace-api/media/drivers/it6625.rst +30 -0
@@ -16,3 +16,33 @@ them are read-only and describe the audio of the HDMI input. ``V4L2_CID_IT6625_AUDIO_PRESENT (boolean)`` ------------------------------------------- Whether the bridge currently receives HDMI audio. + +``V4L2_CID_IT6625_AUDIO_TYPE (menu)`` +------------------------------------- + The coding type of the HDMI audio stream, as last read successfully from + the bridge. The value is kept when audio goes away or reading the audio + status fails, so it describes the current stream only while + ``V4L2_CID_IT6625_AUDIO_PRESENT`` is set and + ``V4L2_CID_IT6625_AUDIO_SAMPLING_RATE`` is not 0. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 4 + + * - ``V4L2_IT6625_AUDIO_TYPE_LPCM`` + - Linear PCM. + * - ``V4L2_IT6625_AUDIO_TYPE_NLPCM`` + - Compressed audio in IEC 61937 format. + * - ``V4L2_IT6625_AUDIO_TYPE_HBR`` + - High bit rate compressed audio in IEC 61937 format. The bridge also + reports this type for some compressed streams at ordinary sampling + rates. + * - ``V4L2_IT6625_AUDIO_TYPE_DSD`` + - One-bit audio. It cannot be captured. + +Compressed and high bit rate streams are captured as raw IEC 61937 data. The +capture layout follows the sampling rate, not the coding type: at 768 kHz and +705.6 kHz the stream is captured as 8 channels at a quarter of that rate, +which needs 4 connected I2S data lines; at other rates it is captured as 2 +channels at the sampling rate.
drivers/media/i2c/it6625.c +102 -16
210 lines not on this page · raw message
include/uapi/linux/it6625.h +25 -0
@@ -22,4 +22,29 @@*/ #define V4L2_CID_IT6625_AUDIO_PRESENT (V4L2_CID_USER_IT6625_BASE + 1) +/* +* Coding type of the HDMI audio stream, as last successfully read from the +* bridge. Read-only menu. It is kept, not cleared, when audio goes away or +* a status read fails, so it describes the current stream only while +* V4L2_CID_IT6625_AUDIO_PRESENT is set and +* V4L2_CID_IT6625_AUDIO_SAMPLING_RATE is non-zero. +* +* LPCM: linear PCM, captured as is. +* NLPCM, HBR: IEC 61937 compressed stream, as reported by the bridge +* firmware (which also reports HBR for plain 48 kHz DTS). The +* capture layout follows V4L2_CID_IT6625_AUDIO_SAMPLING_RATE: at +* 768/705.6 kHz (TrueHD/MAT, DTS-HD MA) 8 channels on 4 I2S lanes +* at a quarter of that rate, otherwise (AC-3, DTS, ...) 2 channels +* at that rate. +* DSD: one-bit audio; not capturable. +*/ +#define V4L2_CID_IT6625_AUDIO_TYPE (V4L2_CID_USER_IT6625_BASE + 2) + +enum v4l2_it6625_audio_type { +V4L2_IT6625_AUDIO_TYPE_LPCM =0 , +V4L2_IT6625_AUDIO_TYPE_NLPCM =1 , +V4L2_IT6625_AUDIO_TYPE_HBR =2 , +V4L2_IT6625_AUDIO_TYPE_DSD =3 , +}; +#endif /* _UAPI_LINUX_IT6625_H */
Signature · 1 line
2.34.1
Re: [PATCH 5/5] media: i2c: it6625: capture compressed and HBR audio, not just LPCM
Quoted 56 lines · On 03/11/2026 07:50, Hermes Wu via B4 Relay wrote:
From: Hermes Wu <[email protected]>
The capture DAI accepts only LPCM. The bridge also outputs compressed IEC 61937 streams (AC-3, DTS, ...) and high bit rate (HBR) streams (Dolby TrueHD/MAT, DTS-HD Master Audio) on the same I2S interface, but these are rejected.
Add
it6625_audio_xport(), which derives the I2S frame rate and slot count from the stream's coding type and sampling rate. LPCM is unchanged. A compressed stream is carried in 2 slots at its own sampling rate, except at the HBR rates of 768 kHz and 705.6 kHz, where one IEC 61937 stream is spread over 8 slots on 4 data lines at a quarter of that rate. The bridge firmware also reports the HBR coding type for some compressed streams at ordinary rates, such as 48 kHz DTS, so the sampling rate, not the coding type, selects the layout. A compressed stream at 768 kHz or 705.6 kHz is rejected when fewer than 4 data lines are connected.Use the derived rate and channel count in the eligibility check, the startup constraints and the
hw_paramscomparison. DSD is still rejected. The driver does not parse the compressed data: userspace receives the IEC 61937 words as they are.Add a read-only "Audio Type" menu control,
V4L2_CID_IT6625_AUDIO_TYPE, so that userspace can tell LPCM, compressed, HBR and DSD streams apart without parsing the audio InfoFrame, and document it.Signed-off-by Hermes Wu <[email protected]>--- .../userspace-api/media/drivers/it6625.rst | 30 ++++++ drivers/media/i2c/it6625.c | 118 ++++++++++++++++++--- include/uapi/linux/it6625.h | 25 +++++ 3 files changed, 157 insertions(+), 16 deletions(-)Documentation/userspace-api/media/drivers/it6625.rst +14
-0@@ -16,3 +16,33 @@ them are read-only and describe the audio of the HDMI input. ``V4L2_CID_IT6625_AUDIO_PRESENT (boolean)`` ------------------------------------------- Whether the bridge currently receives HDMI audio. + +``V4L2_CID_IT6625_AUDIO_TYPE (menu)`` +------------------------------------- + The coding type of the HDMI audio stream, as last read successfully from + the bridge. The value is kept when audio goes away or reading the audio + status fails, so it describes the current stream only while + ``V4L2_CID_IT6625_AUDIO_PRESENT`` is set and + ``V4L2_CID_IT6625_AUDIO_SAMPLING_RATE`` is not 0. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 4 +
Documentation/userspace-api/media/drivers/it6625.rst them are read-only and describe the audio of the HDMI input. · line 42
Quoted 10 lines
Documentation/userspace-api/media/drivers/it6625.rst +10
-0+ * - ``V4L2_IT6625_AUDIO_TYPE_LPCM`` + - Linear PCM. + * - ``V4L2_IT6625_AUDIO_TYPE_NLPCM`` + - Compressed audio in IEC 61937 format. + * - ``V4L2_IT6625_AUDIO_TYPE_HBR`` + - High bit rate compressed audio in IEC 61937 format. The bridge also + reports this type for some compressed streams at ordinary sampling + rates. + * - ``V4L2_IT6625_AUDIO_TYPE_DSD`` + - One-bit audio. It cannot be captured.
This too should become a standard DV audio control.
Regards,
Hans
Quoted 266 lines
Documentation/userspace-api/media/drivers/it6625.rst +6
-0+ +Compressed and high bit rate streams are captured as raw IEC 61937 data. The +capture layout follows the sampling rate, not the coding type: at 768 kHz and +705.6 kHz the stream is captured as 8 channels at a quarter of that rate, +which needs 4 connected I2S data lines; at other rates it is captured as 2 +channels at the sampling rate.drivers/media/i2c/it6625.c +102
-16@@ -101,6 +101,9 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");#define REG_HDMI_AUDIO_INFO3 0x6D#define M_AUD_TYPE GENMASK(1, 0)#define AUD_TYPE_LPCM 0 +#define AUD_TYPE_NLPCM 1 +#define AUD_TYPE_HBR 2 +#define AUD_TYPE_DSD 3#define B_AUD_MS BIT(2)#define B_AUD_3D BIT(3)@@ -119,6 +122,9 @@ MODULE_PARM_DESC(debug, "debug level (0-3)");#define IT6625_AUDIO_MAX_LANES 8#define IT6625_AUDIO_MAX_CHANNELS 8#define IT6625_AUDIO_MAX_RATE 192000 +/* HBR: one IEC 61937 stream spread over 4 lanes (8 slots) per frame */ +#define IT6625_AUDIO_HBR_LANES 4 +#define IT6625_AUDIO_HBR_CHANNELS 8/* status re-check period while a capture stream is open */ #define IT6625_AUDIO_REFRESH_MS 200/* re-checks after an event that left present audio without a valid rate */ @@ -322,6 +328,7 @@ struct it6625 {struct v4l2_ctrl *ctrl_5v_detect;struct v4l2_ctrl *ctrl_audio_sampling_rate;struct v4l2_ctrl *ctrl_audio_present; +struct v4l2_ctrl *ctrl_audio_type;struct v4l2_ctrl *ctrl_link_freq;struct delayed_work hpd_delayed_work;@@ -1069,6 +1076,9 @@ static int it6625_audio_update_ctrls(struct it6625 *it6625)if (!ret) ret =__v4l2_ctrl_s_ctrl (it6625->ctrl_audio_present, info.present); +if (!ret) + ret =__v4l2_ctrl_s_ctrl (it6625->ctrl_audio_type, + info.stream.type);v4l2_ctrl_unlock (it6625->ctrl_audio_present);@@ -2124,6 +2134,25 @@ static const struct v4l2_ctrl_config it6625_ctrl_audio_present = { .flags = V4L2_CTRL_FLAG_READ_ONLY, }; +static const char *const it6625_audio_type_menu[] = { + [V4L2_IT6625_AUDIO_TYPE_LPCM ] ="LPCM" , + [V4L2_IT6625_AUDIO_TYPE_NLPCM ] ="NLPCM" , + [V4L2_IT6625_AUDIO_TYPE_HBR ] ="HBR" , + [V4L2_IT6625_AUDIO_TYPE_DSD ] ="DSD" , +NULL , +}; + +static const struct v4l2_ctrl_config it6625_ctrl_audio_type = { + .id =V4L2_CID_IT6625_AUDIO_TYPE , + .name ="Audio Type" , + .type =V4L2_CTRL_TYPE_MENU , + .min =V4L2_IT6625_AUDIO_TYPE_LPCM , + .max =V4L2_IT6625_AUDIO_TYPE_DSD , + .def =V4L2_IT6625_AUDIO_TYPE_LPCM , + .qmenu = it6625_audio_type_menu, + .flags =V4L2_CTRL_FLAG_READ_ONLY , +}; +static int it6625_v4l2_init_controls (struct v4l2_subdev *sd) {struct it6625 *it6625 =sd_to_6625 (sd);@@ -2131,7 +2160,7 @@ static int it6625_v4l2_init_controls(struct v4l2_subdev *sd)bool cphy_3trio = it6625->bus_type ==V4L2_MBUS_CSI2_CPHY && it6625->csi_lanes ==3 ; -v4l2_ctrl_handler_init (hdl,4 ); +v4l2_ctrl_handler_init (hdl,5 ); it6625->ctrl_5v_detect = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_DV_RX_POWER_PRESENT,@@ -2143,6 +2172,8 @@ static int it6625_v4l2_init_controls(struct v4l2_subdev *sd) NULL); it6625->ctrl_audio_present =v4l2_ctrl_new_custom (hdl, &it6625_ctrl_audio_present,NULL ); + it6625->ctrl_audio_type = +v4l2_ctrl_new_custom (hdl, &it6625_ctrl_audio_type,NULL ); it6625->ctrl_link_freq = v4l2_ctrl_new_int_menu(hdl, NULL, V4L2_CID_LINK_FREQ, 0, 0, cphy_3trio ? it6626_cphy_3trio_link_freq :@@ -2186,26 +2217,74 @@ static unsigned int it6625_audio_max_channels(const struct it6625 *it6625)return min (2U * it6625->audio_lanes,IT6625_AUDIO_MAX_CHANNELS ); } +/* +* I2S frame rate and slot count that carry this stream. Pure, callable in +* atomic context; returns -ENODEV for a stream the I2S output can't carry. +* +* LPCM goes out as is. A compressed IEC 61937 stream at up to 192 kHz +* takes 2 slots at its own sampling rate, whatever channel count the +* source signals. An HBR stream (AUD_FS 768 or 705.6 kHz) is one IEC 61937 +* stream at 4x the frame rate spread over 4 lanes: 8 slots at a quarter of +* that rate. +* +* The firmware doesn't keep AUD_TYPE to its documented meaning: it reports +* HBR for a plain 48 kHz DTS stream too. So the rate, not NLPCM vs. HBR, +* selects the layout of a compressed stream. +*/ +static int it6625_audio_xport (const struct it6625 *it6625, +const struct it6625_audio_stream *s, +u32 *rate,unsigned int *channels) +{ +u32 fs =it6625_audio_fs_to_rate (s->fs_code); + +if (!fs) +return -ENODEV ; + +switch (s->type) { +case AUD_TYPE_LPCM : + *rate = fs; + *channels = s->channels; +break ; +case AUD_TYPE_NLPCM : +case AUD_TYPE_HBR : +if (fs ==768000 || fs ==705600 ) { + *rate = fs /IT6625_AUDIO_HBR_LANES ; + *channels =IT6625_AUDIO_HBR_CHANNELS ; + }else { + *rate = fs; + *channels =2 ; + } +break ; +default : +return -ENODEV ; + } + +if (*rate >IT6625_AUDIO_MAX_RATE ) +return -ENODEV ; + +if (*channels <2 || *channels %2 || + *channels >it6625_audio_max_channels (it6625)) +return -ENODEV ; + +return 0 ; +} +/* can this audio status be captured? Pure check, callable in atomic context. */ static int it6625_audio_check (const struct it6625 *it6625,const struct it6625_audio_info *info) {const struct it6625_audio_stream *s = &info->stream; -u32 rate =it6625_audio_fs_to_rate (s->fs_code); +unsigned int channels; +u32 rate;if (!info->read_ok || !info->vid_stable || !info->present || info->avmute)return -ENODEV ; -if (s->out_if !=AUD_OUT_IF_I2S || s->type !=AUD_TYPE_LPCM || - s->multi_stream || s->is_3d) -return -ENODEV ; - -if (!rate || rate >IT6625_AUDIO_MAX_RATE ) +if (s->out_if !=AUD_OUT_IF_I2S || s->multi_stream || s->is_3d)return -ENODEV ; -if (s->channels <2 || s->channels %2 || - s->channels >it6625_audio_max_channels (it6625)) +if (it6625_audio_xport (it6625, s, &rate, &channels))return -ENODEV ;if (!it6625_audio_wl_bits (s->i2s_wl))@@ -2281,8 +2360,9 @@ static int it6625_dai_startup(struct snd_pcm_substream *substream,struct it6625 *it6625 =dai_to_6625 (dai);struct snd_pcm_runtime *runtime = substream->runtime;struct it6625_audio_info info; +unsigned int channels;unsigned long flags; -u32 gen; +u32 gen, rate;int ret;it6625_audio_refresh (it6625);@@ -2298,13 +2378,16 @@ static int it6625_dai_startup(struct snd_pcm_substream *substream,if (ret)return ret; +/* the check above passed, so this can't fail */ +it6625_audio_xport (it6625, &info.stream, &rate, &channels); + ret =snd_pcm_hw_constraint_single (runtime,SNDRV_PCM_HW_PARAM_RATE , -it6625_audio_fs_to_rate (info.stream.fs_code)); + rate);if (ret <0 )return ret; ret =snd_pcm_hw_constraint_single (runtime,SNDRV_PCM_HW_PARAM_CHANNELS , - info.stream.channels); + channels);if (ret <0 )return ret;@@ -2378,18 +2461,21 @@ static int it6625_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct it6625 *it6625 =dai_to_6625 (dai); -const struct it6625_audio_stream *s; +unsigned int channels;unsigned long flags; +u32 rate;int ret;it6625_audio_refresh (it6625);spin_lock_irqsave (&it6625->audio_lock, flags); ret =it6625_audio_validate_locked (it6625); - s = &it6625->audio_accepted; +if (!ret) + ret =it6625_audio_xport (it6625, &it6625->audio_accepted, + &rate, &channels);if (!ret && - (params_rate (params) !=it6625_audio_fs_to_rate (s->fs_code) || -params_channels (params) != s->channels || + (params_rate (params) != rate || +params_channels (params) != channels ||params_format (params) !=SNDRV_PCM_FORMAT_S32_LE )) ret = -EINVAL ;spin_unlock_irqrestore (&it6625->audio_lock, flags);include/uapi/linux/it6625.h +25
-0@@ -22,4 +22,29 @@*/ #define V4L2_CID_IT6625_AUDIO_PRESENT (V4L2_CID_USER_IT6625_BASE + 1) +/* +* Coding type of the HDMI audio stream, as last successfully read from the +* bridge. Read-only menu. It is kept, not cleared, when audio goes away or +* a status read fails, so it describes the current stream only while +* V4L2_CID_IT6625_AUDIO_PRESENT is set and +* V4L2_CID_IT6625_AUDIO_SAMPLING_RATE is non-zero. +* +* LPCM: linear PCM, captured as is. +* NLPCM, HBR: IEC 61937 compressed stream, as reported by the bridge +* firmware (which also reports HBR for plain 48 kHz DTS). The +* capture layout follows V4L2_CID_IT6625_AUDIO_SAMPLING_RATE: at +* 768/705.6 kHz (TrueHD/MAT, DTS-HD MA) 8 channels on 4 I2S lanes +* at a quarter of that rate, otherwise (AC-3, DTS, ...) 2 channels +* at that rate. +* DSD: one-bit audio; not capturable. +*/ +#define V4L2_CID_IT6625_AUDIO_TYPE (V4L2_CID_USER_IT6625_BASE + 2) + +enum v4l2_it6625_audio_type { +V4L2_IT6625_AUDIO_TYPE_LPCM =0 , +V4L2_IT6625_AUDIO_TYPE_NLPCM =1 , +V4L2_IT6625_AUDIO_TYPE_HBR =2 , +V4L2_IT6625_AUDIO_TYPE_DSD =3 , +}; +#endif /* _UAPI_LINUX_IT6625_H */