#!/usr/bin/env python3 """Dump TLV320DAC3100 registers and decode their current values. This script uses register names and bitfield descriptions hard-coded from the TLV320DAC3100 datasheet (Rev. C). It does not parse the PDF at runtime. Behavior: - reads implemented TLV320DAC3100 pages over I2C - skips fully reserved registers - decodes non-reserved bitfields where possible - groups coefficient pairs and other multi-register values """ from __future__ import annotations import argparse import re import shlex import shutil import subprocess import sys from typing import Iterable DEFINED_PAGES = [0, 1, 3, 8, 9, 12, 13] class CommandError(RuntimeError): pass SpecEntry = tuple[int, str] | tuple[int, int, str] def parse_int(text: str) -> int: return int(text, 0) def parse_pages(spec: str) -> list[int]: if spec.strip().lower() == "all": return list(DEFINED_PAGES) pages: list[int] = [] for part in spec.split(","): part = part.strip() if not part: continue page = parse_int(part) if page not in DEFINED_PAGES: valid = ", ".join(str(p) for p in DEFINED_PAGES) raise argparse.ArgumentTypeError( f"unsupported page {page}; valid pages: {valid}, or 'all'" ) if page not in pages: pages.append(page) return pages def add_range(target: dict[int, str], start: int, end: int, description: str) -> None: for reg in range(start, end + 1): target[reg] = description def build_page_from_spec(spec: Iterable[SpecEntry], *, default: str = "Reserved") -> dict[int, str]: page: dict[int, str] = {} for entry in spec: if len(entry) == 2: reg, description = entry page[reg] = description else: start, end, description = entry add_range(page, start, end, description) for reg in range(128): page.setdefault(reg, default) return page def build_biquad_page(*, register_1_description: str) -> dict[int, str]: page = { 0: "Page Control Register", 1: register_1_description, 64: "8 MSBs of 3D PGA gain for PRB_P23, PRB_P24 and PRB_P25", 65: "8 LSBs of 3D PGA gain for PRB_P23, PRB_P24 and PRB_P25", } biquad_regs = [ ("N0", "15:8"), ("N0", "7:0"), ("N1", "15:8"), ("N1", "7:0"), ("N2", "15:8"), ("N2", "7:0"), ("D1", "15:8"), ("D1", "7:0"), ("D2", "15:8"), ("D2", "7:0"), ] reg = 2 for biquad in "ABCDEF": for coeff, bits in biquad_regs: page[reg] = f"Coefficient {coeff}({bits}) for left DAC-programmable biquad {biquad}" reg += 1 add_range(page, 62, 63, "Reserved") reg = 66 for biquad in "ABCDEF": for coeff, bits in biquad_regs: page[reg] = f"Coefficient {coeff}({bits}) for right DAC-programmable biquad {biquad}" reg += 1 add_range(page, 126, 127, "Reserved") for reg in range(128): page.setdefault(reg, "Reserved") return page def build_first_order_page() -> dict[int, str]: page = {0: "Page Control Register", 1: "Reserved"} six_regs = [ ("N0", "15:8"), ("N0", "7:0"), ("N1", "15:8"), ("N1", "7:0"), ("D1", "15:8"), ("D1", "7:0"), ] reg = 2 for coeff, bits in six_regs: page[reg] = f"Coefficient {coeff}({bits}) for left DAC-programmable first-order IIR" reg += 1 for coeff, bits in six_regs: page[reg] = f"Coefficient {coeff}({bits}) for right DAC-programmable first-order IIR" reg += 1 for coeff, bits in six_regs: page[reg] = f"Coefficient {coeff}({bits}) for DRC first-order high-pass filter" reg += 1 for coeff, bits in six_regs: page[reg] = f"Coefficient {coeff}({bits}) for DRC first-order low-pass filter" reg += 1 add_range(page, 26, 127, "Reserved") return page PAGE0_SPEC: list[SpecEntry] = [ (0, "Page Control Register"), (1, "Software Reset"), (2, "Reserved"), (3, "OT FLAG"), (4, "Clock-Gen Muxing (1)"), (5, "PLL P and R Values"), (6, "PLL J-Value"), (7, "PLL D-Value MSB (1)"), (8, "PLL D-Value LSB (1)"), (9, 10, "Reserved"), (11, "DAC NDAC_VAL"), (12, "DAC MDAC_VAL"), (13, "DAC DOSR_VAL MSB"), (14, "DAC DOSR_VAL LSB (1) (2)"), (15, 24, "Reserved"), (25, "CLKOUT MUX"), (26, "CLKOUT M_VAL"), (27, "Codec Interface Control 1"), (28, "Data-Slot Offset Programmability"), (29, "Codec Interface Control 2"), (30, "BCLK N_VAL"), (31, "Codec Secondary Interface Control 1"), (32, "Codec Secondary Interface Control 2"), (33, "Codec Secondary Interface Control 3"), (34, "I2C Bus Condition"), (35, 36, "Reserved"), (37, "DAC Flag Register"), (38, "DAC Flag Register"), (39, "Overflow Flags"), (40, 43, "Reserved"), (44, "DAC Interrupt Flags (Sticky Bits)"), (45, "Reserved"), (46, "Interrupt Flags—DAC"), (47, "Reserved"), (48, "INT1 Control Register"), (49, "INT2 Control Register"), (50, "Reserved"), (51, "GPIO1 In/Out Pin Control"), (52, "Reserved"), (53, "Reserved"), (54, "DIN (IN Pin) Control"), (55, 59, "Reserved"), (60, "DAC Processing Block Selection"), (61, 62, "Reserved"), (63, "DAC Data-Path Setup"), (64, "DAC Volume Control"), (65, "DAC Left Volume Control"), (66, "DAC Right Volume Control"), (67, "Headset Detection"), (68, "DRC Control 1"), (69, "DRC Control 2"), (70, "DRC Control 3"), (71, "Left Beep Generator (1)"), (72, "Right Beep Generator"), (73, "Beep Length MSB"), (74, "Beep-Length Middle Bits"), (75, "Beep Length LSB"), (76, "Beep Sin(x) MSB"), (77, "Beep Sin(x) LSB"), (78, "Beep Cos(x) MSB"), (79, "Beep Cos(x) LSB"), (80, 115, "Reserved"), (116, "VOL/MICDET-Pin SAR ADC — Volume Control"), (117, "VOL/MICDET-Pin Gain"), (118, 127, "Reserved"), ] PAGE1_SPEC: list[SpecEntry] = [ (0, "Page Control Register"), (1, 29, "Reserved"), (30, "Headphone and Speaker Amplifier Error Control"), (31, "Headphone Drivers"), (32, "Class-D Speaker Amplifier"), (33, "HP Output Drivers POP Removal Settings"), (34, "Output Driver PGA Ramp-Down Period Control"), (35, "DAC_L and DAC_R Output Mixer Routing"), (36, "Left Analog Volume to HPL"), (37, "Right Analog Volume to HPR"), (38, "Left Analog Volume to SPK"), (39, "Reserved"), (40, "HPL Driver"), (41, "HPR Driver"), (42, "Class-D Speaker (SPK) Driver"), (43, "Reserved"), (44, "HP Driver Control"), (45, "Reserved"), (46, "MICBIAS"), (47, 49, "Reserved / undocumented in Rev. C datasheet"), (50, "Input CM Settings"), (51, 127, "Reserved"), ] PAGE3_SPEC: list[SpecEntry] = [ (0, "Page Control Register"), (1, 15, "Reserved"), (16, "Timer Clock MCLK Divider"), (17, 127, "Reserved"), ] REGISTER_MAP: dict[int, dict[int, str]] = { 0: build_page_from_spec(PAGE0_SPEC), 1: build_page_from_spec(PAGE1_SPEC), 3: build_page_from_spec(PAGE3_SPEC), 8: build_biquad_page(register_1_description="DAC Coefficient RAM Control"), 9: build_first_order_page(), 12: build_biquad_page(register_1_description="Reserved"), 13: build_first_order_page(), } REGISTER_FIELDS = {(0, 0): {'fields': [{'bits': 'D7–D0', 'lines': ['0000 0000: Page 0 selected', '0000 0001: Page 1 selected', '...', '1111 1110: Page 254 selected', '1111 1111: Page 255 selected'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 1): {'fields': [{'bits': 'D7–D1', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '0000 000', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ["0: Don't care", '1: Self-clearing software reset for control register'], 'reset': '0', 'rw': 'R/W'}]}, (0, 3): {'fields': [{'bits': 'D7–D2', 'lines': ['Reserved. Do not write to these bits.'], 'reset': 'XXXX XX', 'rw': 'R'}, {'bits': 'D1', 'lines': ['0: Overtemperature protection flag (active-low). Valid only if speaker amplifier is ' 'powered up', '1: Normal operation'], 'reset': '1', 'rw': 'R'}, {'bits': 'D0', 'lines': ['Reserved. Do not write to these bits.'], 'reset': 'X', 'rw': 'R/W'}]}, (0, 4): {'fields': [{'bits': 'D7–D4', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D3–D2', 'lines': ['00: PLL_CLKIN = MCLK (device pin)', '01: PLL_CLKIN = BCLK (device pin)', '10: PLL_CLKIN = GPIO1 (device pin)', '11: PLL_CLKIN = DIN (can be used for the system where DAC is not used)'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: CODEC_CLKIN = MCLK (device pin)', '01: CODEC_CLKIN = BCLK (device pin)', '10: CODEC_CLKIN = GPIO1 (device pin)', '11: CODEC_CLKIN = PLL_CLK (generated on-chip)', '(1) See Section 6.3.11 for more details on clock generation mutiplexing and ' 'dividers.'], 'reset': '00', 'rw': 'R/W'}]}, (0, 5): {'fields': [{'bits': 'D7', 'lines': ['0: PLL is powered down.', '1: PLL is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D4', 'lines': ['000: PLL divider P = 8', '001: PLL divider P = 1', '010: PLL divider P = 2', '...', '110: PLL divider P = 6', '111: PLL divider P = 7'], 'reset': '001', 'rw': 'R/W'}, {'bits': 'D3–D0', 'lines': ['0000: PLL multiplier R = 16', '0001: PLL multiplier R = 1', '0010: PLL multiplier R = 2', '...', '1110: PLL multiplier R = 14', '1111: PLL multiplier R = 15'], 'reset': '0001', 'rw': 'R/W'}]}, (0, 6): {'fields': [{'bits': 'D7–D6', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D5–D0', 'lines': ['00 0000: Do not use (reserved)', '00 0001: PLL multiplier J = 1', '00 0010: PLL multiplier J = 2', '...', '11 1110: PLL multiplier J = 62', '11 1111: PLL multiplier J = 63'], 'reset': '00 0100', 'rw': 'R/W'}]}, (0, 7): {'fields': [{'bits': 'D7–D6', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D5–D0', 'lines': ['PLL fractional multiplier D-value MSB bits D[13:8]', '(1) Note that this register is updated only when Page 0 / Register 8 is written ' 'immediately after Page 0 / Register 7.'], 'reset': '00 0000', 'rw': 'R/W'}]}, (0, 8): {'fields': [{'bits': 'D7–D0', 'lines': ['PLL fractional multiplier D-value LSB bits D[7:0]', '(1) Note that Page 0 / Register 8 must be written immediately after Page 0 / Register ' '7.'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 11): {'fields': [{'bits': 'D7', 'lines': ['0: DAC NDAC divider is powered down.', '1: DAC NDAC divider is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['000 0000: DAC NDAC divider = 128', '000 0001: DAC NDAC divider = 1', '000 0010: DAC NDAC divider = 2', '...', '111 1110: DAC NDAC divider = 126', '111 1111: DAC NDAC divider = 127'], 'reset': '000 0001', 'rw': 'R/W'}]}, (0, 12): {'fields': [{'bits': 'D7', 'lines': ['0: DAC MDAC divider is powered down.', '1: DAC MDAC divider is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['000 0000: DAC MDAC divider = 128', '000 0001: DAC MDAC divider = 1', '000 0010: DAC MDAC divider = 2', '...', '111 1110: DAC MDAC divider = 126', '111 1111: DAC MDAC divider = 127'], 'reset': '000 0001', 'rw': 'R/W'}]}, (0, 13): {'fields': [{'bits': 'D7–D2', 'lines': ['Reserved'], 'reset': '0000 00', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['DAC OSR value DOSR(9:8)'], 'reset': '00', 'rw': 'R/W'}]}, (0, 14): {'fields': [{'bits': 'D7–D0', 'lines': ['DAC OSR Value DOSR (7:0)', '0000 0000: DAC OSR (7:0) = 1024 (MSB page 0 / register 13, bits D1–D0 = 00)', '0000 0001: Reserved', '0000 0010: DAC OSR (7:0) = 2 (MSB page 0 / register 13, bits D1–D0 = 00)', '...', '1111 1110: DAC OSR (7:0) = 1022 (MSB page 0 / register 13, bits D1–D0 = 11)', '1111 1111: DAC OSR (7:0) = Reserved. Do not Use', '(1) DAC OSR must be an integral multiple of the interpolation in the DAC miniDSP ' 'engine (specified in register 16). When using PRB', 'modes, interpolation ratio is 8 while using Filter-A, 4 while using Filter-B and 2 ' 'while using Filter-C.', '(2) Note that Page 0 / Register 14 must be written to immediately after writing to ' 'Page 0 / Register 13.'], 'reset': '1000 0000', 'rw': 'R/W'}]}, (0, 25): {'fields': [{'bits': 'D7–D3', 'lines': ['Reserved'], 'reset': '0000 0', 'rw': 'R/W'}, {'bits': 'D2–D0', 'lines': ['000: CDIV_CLKIN = MCLK (device pin)', '001: CDIV_CLKIN = BCLK (device pin)', '010: CDIV_CLKIN = DIN (can be used for the systems where DAC is not required)', '011: CDIV_CLKIN = PLL_CLK (generated on-chip)', '100: CDIV_CLKIN = DAC_CLK (DAC DSP clock - generated on-chip)', '101: CDIV_CLKIN = DAC_MOD_CLK (generated on-chip)', '110: Reserved', '111: Reserved'], 'reset': '000', 'rw': 'R/W'}]}, (0, 26): {'fields': [{'bits': 'D7', 'lines': ['0: CLKOUT M divider is powered down.', '1: CLKOUT M divider is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['000 0000: CLKOUT divider M = 128', '000 0001: CLKOUT divider M = 1', '000 0010: CLKOUT divider M = 2', '...', '111 1110: CLKOUT divider M = 126', '111 1111: CLKOUT divider M = 127'], 'reset': '000 0001', 'rw': 'R/W'}]}, (0, 27): {'fields': [{'bits': 'D7–D6', 'lines': ['00: Codec interface = I S', '01: Codec Interface = DSP', '10: Codec interface = RJF', '11: Codec interface = LJF'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D5–D4', 'lines': ['00: Codec interface word length = 16 bits', '01: Codec interface word length = 20 bits', '10: Codec interface word length = 24 bits', '11: Codec interface word length = 32 bits'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: BCLK is input', '1: BCLK is output'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: WCLK is input', '1: WCLK is output'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['Reserved'], 'reset': '0', 'rw': 'R/W'}]}, (0, 28): {'fields': [{'bits': 'D7–D0', 'lines': ['Offset (Measured With Respect to WCLK Rising Edge in DSP Mode)', '0000 0000: Offset = 0 BCLKs', '0000 0001: Offset = 1 BCLK', '0000 0010: Offset = 2 BCLKs', '...', '1111 1110: Offset = 254 BCLKs', '1111 1111: Offset = 255 BCLKs'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 29): {'fields': [{'bits': 'D7–D4', 'lines': ['Reserved'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: BCLK is not inverted (valid for both primary and secondary BCLK)', '1: BCLK is inverted (valid for both primary and secondary BCLK)'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['BCLK and WCLK Active Even With Codec Powered Down (Valid for Both Primary and ' 'Secondary BCLK)', '0: Disabled', '1: Enabled'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: BDIV_CLKIN = DAC_CLK (generated on-chip)', '01: BDIV_CLKIN = DAC_MOD_CLK (generated on-chip)', '10: Reserved', '11: Reserved'], 'reset': '00', 'rw': 'R/W'}]}, (0, 30): {'fields': [{'bits': 'D7', 'lines': ['0: BCLK N-divider is powered down.', '1: BCLK N-divider is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['000 0000: BCLK divider N = 128', '000 0001: BCLK divider N = 1', '000 0010: BCLK divider N = 2', '...', '111 1110: BCLK divider N = 126', '111 1111: BCLK divider N = 127'], 'reset': '000 0001', 'rw': 'R/W'}]}, (0, 31): {'fields': [{'bits': 'D7–D5', 'lines': ['000: Secondary BCLK is obtained from GPIO1 pin.', '001: Secondary BCLK is not obtained from the GPIO1 pin.', '010: Reserved.', '011: Reserved.', '100: Reserved', '101: Reserved.', '110: Reserved.', '111: Reserved'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D4–D2', 'lines': ['000: Secondary WCLK is obtained from GPIO1 pin.', '001: Secondary WCLK is not obtained from the GPIO1 pin.', '010: Reserved.', '011: Reserved.', '100: Reserved', '101: Reserved.', '110: Reserved.', '111: Reserved'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: Secondary DIN is obtained from the GPIO1 pin.', '01: Secondary DIN is not obtained from the GPIO1 pin.', '10: Reserved.', '11: Reserved'], 'reset': '00', 'rw': 'R/W'}]}, (0, 32): {'fields': [{'bits': 'D7–D4', 'lines': ['Reserved'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: Primary BCLK is fed to codec serial-interface and ClockGen blocks.', '1: Secondary BCLK is fed to codec serial-interface and ClockGen blocks.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: Primary WCLK is fed to codec serial-interface block.', '1: Secondary WCLK is fed to codec serial-interface block.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['Reserved.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Primary DIN is fed to codec serial-interface block.', '1: Secondary DIN is fed to codec serial-interface block.'], 'reset': '0', 'rw': 'R/W'}]}, (0, 33): {'fields': [{'bits': 'D7', 'lines': ['0: Primary BCLK output = internally generated BCLK clock', '1: Primary BCLK output = secondary BCLK'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: Secondary BCLK output = primary BCLK', '1: Secondary BCLK output = internally generated BCLK clock'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5–D4', 'lines': ['00: Primary WCLK output = internally generated DAC_fS', '01: Reserved', '10: Primary WCLK output = secondary WCLK', '11: Reserved'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D3–D2', 'lines': ['00: Secondary WCLK output = primary WCLK', '01: Secondary WCLK output = internally generated DAC_fS clock', '10: Reserved', '11: Reserved'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['Reserved'], 'reset': '0', 'rw': 'R/W'}]}, (0, 34): {'fields': [{'bits': 'D7–D6', 'lines': ['Reserved. Write only the reset value to these bits.'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D5', 'lines': ['0: I2C general-call address is ignored.', '1: Device accepts I2C general-call address.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D4–D0', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '0 0000', 'rw': 'R/W'}]}, (0, 37): {'fields': [{'bits': 'D7', 'lines': ['0: Left-channel DAC powered down', '1: Left-channel DAC powered up'], 'reset': '0', 'rw': 'R'}, {'bits': 'D6', 'lines': ['Reserved.'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D5', 'lines': ['0: HPL driver powered down', '1: HPL driver powered up'], 'reset': '0', 'rw': 'R'}, {'bits': 'D4', 'lines': ['0: Left-channel class-D driver powered down', '1: Left-channel class-D driver powered up'], 'reset': '0', 'rw': 'R'}, {'bits': 'D3', 'lines': ['0: Right-channel DAC powered down', '1: Right-channel DAC powered up'], 'reset': '0', 'rw': 'R'}, {'bits': 'D2', 'lines': ['Reserved.'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D1', 'lines': ['0: HPR driver powered down', '1: HPR driver powered up'], 'reset': '0', 'rw': 'R'}, {'bits': 'D0', 'lines': ['0: Right-channel class-D driver powered down', '1: Right-channel class-D driver powered up'], 'reset': '0', 'rw': 'R'}]}, (0, 38): {'fields': [{'bits': 'D7–D5', 'lines': ['Reserved.'], 'reset': 'XXX', 'rw': 'R'}, {'bits': 'D4', 'lines': ['0: Left-channel DAC PGA applied gain ≠ programmed gain', '1: Left-channel DAC PGA applied gain = programmed gain'], 'reset': '0', 'rw': 'R'}, {'bits': 'D3–D1', 'lines': ['Reserved.'], 'reset': 'XXX', 'rw': 'R'}, {'bits': 'D0', 'lines': ['0: Right-channel DAC PGA applied gain ≠ programmed gain', '1: Right-channel DAC PGA applied gain = programmed gain'], 'reset': '0', 'rw': 'R'}]}, (0, 39): {'fields': [{'bits': 'D7 (1)', 'lines': ['Left-Channel DAC Overflow Flag', '0: Overflow has not occurred.', '1: Overflow has occurred.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D6 (1)', 'lines': ['Right-Channel DAC Overflow Flag', '0: Overflow has not occurred.', '1: Overflow has occurred.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D5 (1)', 'lines': ['DAC Barrel Shifter Output Overflow Flag', '0: Overflow has not occurred.', '1: Overflow has occurred.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D4–D0', 'lines': ['Reserved.', '(1) Sticky flag bIt. These is a read-only bit. This bit is automatically cleared ' 'once it is read and is set only if the source trigger occurs again.'], 'reset': '0', 'rw': 'R'}]}, (0, 44): {'fields': [{'bits': 'D7 (1)', 'lines': ['0: No short circuit is detected at HPL / left class-D driver.', '1: Short circuit is detected at HPL / left class-D driver.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D6 (1)', 'lines': ['0: No short circuit is detected at HPR / right class-D driver.', '1: Short circuit is detected at HPR / right class-D driver.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D5 (1)', 'lines': ['0: No headset button pressed.', '1: Headset button pressed.'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D4 (1)', 'lines': ['0: No headset insertion or removal is detected.', '1: Headset insertion or removal is detected.'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D3 (1)', 'lines': ['0: Left DAC signal power is less than or equal to the signal threshold of DRC.', '1: Left DAC signal power is above the signal threshold of DRC.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D2 (1)', 'lines': ['0: Right DAC signal power is less than or equal to the signal threshold of DRC.', '1: Right DAC signal power is above the signal threshold of DRC.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D1–D0', 'lines': ['Reserved.', '(1) Sticky flag bIt. These is a read-only bit. This bit is automatically cleared ' 'once it is read and is set only if the source trigger occurs again.'], 'reset': '0', 'rw': 'R'}]}, (0, 46): {'fields': [{'bits': 'D7', 'lines': ['0: No short circuit detected at HPL / left class-D driver.', '1: Short circuit detected at HPL / left class-D driver.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D6', 'lines': ['0: No short circuit detected at HPR / right class-D driver', '1: Short circuit detected at HPR / right class-D driver'], 'reset': '0', 'rw': 'R'}, {'bits': 'D5', 'lines': ['0: No headset button pressed.', '1: Headset button pressed.'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D4', 'lines': ['0: Headset removal detected.', '1: Headset insertion detected.'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D3', 'lines': ['0: Left DAC signal power is less than or equal to signal threshold of DRC.', '1: Left DAC signal power is greater than signal threshold of DRC.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D2', 'lines': ['0: Right DAC signal power is less than or equal to signal threshold of DRC.', '1: Right DAC signal power is greater than signal threshold of DRC.'], 'reset': '0', 'rw': 'R'}, {'bits': 'D1–D0', 'lines': ['Reserved.'], 'reset': '00', 'rw': 'R'}]}, (0, 48): {'fields': [{'bits': 'D7', 'lines': ['0: Headset-insertion detect interrupt is not used in the generation of INT1 ' 'interrupt.', '1: Headset-insertion detect interrupt is used in the generation of INT1 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: Button-press detect interrupt is not used in the generation of INT1 interrupt.', '1: Button-press detect interrupt is used in the generation of INT1 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5', 'lines': ['0: DAC DRC signal-power interrupt is not used in the generation of INT1 interrupt.', '1: DAC DRC signal-power interrupt is used in the generation of INT1 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D4', 'lines': ['Reserved'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: Short-circuit interrupt is not used in the generation of INT1 interrupt.', '1: Short-circuit interrupt is used in the generation of INT1 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: DAC data overflow does not result in an INT1 interrupt.', '1: DAC data overflow results in an INT1 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['Reserved'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: INT1 is only one pulse (active-high) of typical 2-ms duration.', '1: INT1 is multiple pulses (active-high) of typical 2-ms duration and 4-ms period, ' 'until flag register 44 is', 'read by the user.'], 'reset': '0', 'rw': 'R/W'}]}, (0, 49): {'fields': [{'bits': 'D7', 'lines': ['0: Headset-insertion detect interrupt is not used in the generation of INT2 ' 'interrupt.', '1: Headset-insertion detect interrupt is used in the generation of INT2 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: Button-press detect interrupt is not used in the generation of INT2 interrupt.', '1: Button-press detect interrupt is used in the generation of INT2 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5', 'lines': ['0: DAC DRC signal-power interrupt is not used in the generation of INT2 interrupt.', '1: DAC DRC signal-power interrupt is used in the generation of INT2 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D4', 'lines': ['Reserved'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: Short-circuit interrupt is not used in the generation of INT2 interrupt.', '1: Short-circuit interrupt is used in the generation of INT2 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: DAC data overflow does not result in an INT2 interrupt.', '1: DAC data overflow results in an INT2 interrupt.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['Reserved'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: INT2 is only one pulse (active-high) of typical 2-ms duration.', '1: INT2 is multiple pulses (active-high) of typical 2-ms duration and 4-ms period, ' 'until flag register 44is', 'read by the user.'], 'reset': '0', 'rw': 'R/W'}]}, (0, 51): {'fields': [{'bits': 'D7–D6', 'lines': ['Reserved. Do not write any value other than reset value.'], 'reset': 'XX', 'rw': 'R/W'}, {'bits': 'D5–D2', 'lines': ['0000: GPIO1 disabled (input and output buffers powered down)', '0001: GPIO1 is in input mode (can be used as secondary BCLK input, secondary WCLK ' 'input,', 'secondary DIN input, or in ClockGen block).', '0010: GPIO1 is used as general-purpose input (GPI).', '0011: GPIO1 output = general-purpose output', '0100: GPIO1 output = CLKOUT output', '0101: GPIO1 output = INT1 output', '0110: GPIO1 output = INT2 output', '0111: Reserved', '1000: GPIO1 output = secondary BCLK output for codec interface', '1001: GPIO1 output = secondary WCLK output for codec interface', '1010: Reserved', '1011: Reserved', '1100: Reserved', '1101: Reserved', '1110: Reserved', '1111: Reserved'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['GPIO1 input buffer value'], 'reset': 'X', 'rw': 'R'}, {'bits': 'D0', 'lines': ['0: GPIO1 general-purpose output value = 0', '1: GPIO1 general-purpose output value = 1'], 'reset': '0', 'rw': 'R/W'}]}, (0, 54): {'fields': [{'bits': 'D7–D3', 'lines': ['Reserved'], 'reset': '0000 0', 'rw': 'R/W'}, {'bits': 'D2–D1', 'lines': ['00: DIN disabled (input buffer powered down)', '01: DIN enabled (can be used as DIN for codec interface or into ClockGen block)', '10: DIN is used as general-purpose input (GPI)', '11: Reserved'], 'reset': '01', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['DIN input-buffer value'], 'reset': 'X', 'rw': 'R'}]}, (0, 60): {'fields': [{'bits': 'D7–D5', 'lines': ['Reserved. Write only default value.'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D4–D0', 'lines': ['0 0000: Reserved. Do not use.', '0 0001: DAC signal-processing block PRB_P1', '0 0010: DAC signal-processing block PRB_P2', '0 0011: DAC signal-processing block PRB_P3', '0 0100: DAC signal-processing block PRB_P4', '...', '1 1000: DAC signal-processing block PRB_P24', '1 1001: DAC signal-processing block PRB_P25', '1 1010–1 1111: Reserved. Do not use.'], 'reset': '00 0001', 'rw': 'R/W'}]}, (0, 63): {'fields': [{'bits': 'D7', 'lines': ['0: Left-channel DAC is powered down.', '1: Left-channel DAC is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: Right-channel DAC is powered down.', '1: Right-channel DAC is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5–D4', 'lines': ['00: Left-channel DAC data path = off', '01: Left-channel DAC data path = left data', '10: Left-channel DAC data path = right data', '11: Left-channel DAC data path = left-channel and right-channel data [(L + R) / 2]'], 'reset': '01', 'rw': 'R/W'}, {'bits': 'D3–D2', 'lines': ['00: Right-channel DAC data path = off', '01: Right-channel DAC data path = right data', '10: Right-channel DAC data path = left data', '11: Right-channel DAC data path = left-channel and right-channel data [(L + R) / 2]'], 'reset': '01', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: DAC-channel volume-control soft-stepping is enabled for one step per sample ' 'period.', '01: DAC-channel volume-control soft-stepping is enabled for one step per two sample ' 'periods.', '10: DAC-channel volume-control soft-stepping is disabled.', '11: Reserved. Do not write this sequence to these bits.'], 'reset': '00', 'rw': 'R/W'}]}, (0, 64): {'fields': [{'bits': 'D7–D4', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: Left-channel DAC not muted', '1: Left-channel DAC muted'], 'reset': '1', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: Right-channel DAC not muted', '1: Right-channel DAC muted'], 'reset': '1', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: Left and right channels have independent volume control. (1)', '01: Left-channel volume control Is the programmed value of right-channel volume ' 'control.', '10: Right-channel volume control is the programmed value of left-channel volume ' 'control.', '11: Same as 00', '(1) When DRC is enabled, left and right channel volume controls are always ' 'independent. Program bits D1–D0 to 00.'], 'reset': '00', 'rw': 'R/W'}]}, (0, 65): {'fields': [{'bits': 'D7–D0', 'lines': ['Left DAC Channel Digital Volume Control Setting', '0111 1111–0011 0001: Reserved. Do not use', '0011 0000: Digital volume control = 24 dB', '0010 1111: Digital volume control = 23.5 dB', '0010 1110: Digital volume control = 23 dB', '...', '0000 0001: Digital volume control = 0.5 dB', '0000 0000: Digital volume control = 0 dB', '1111 1111: Digital volume control = –0.5 dB', '...', '1000 0010: Digital volume control = –63 dB', '1000 0001: Digital volume control = –63.5 dB', '1000 0000: Reserved.'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 66): {'fields': [{'bits': 'D7–D0', 'lines': ['Right DAC Channel Digital Volume Control Setting', '0111 1111–0011 0001: Reserved. Do not use', '0011 0000: Digital volume control = 24 dB', '0010 1111: Digital volume control = 23.5 dB', '0010 1110: Digital volume control = 23 dB', '...', '0000 0001: Digital volume control = 0.5 dB', '0000 0000: Digital volume control = 0 dB', '1111 1111: Digital volume control = –0.5 dB', '...', '1000 0010: Digital volume control = –63 dB', '1000 0001: Digital volume control = –63.5 dB', '1000 0000: Reserved.'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 67): {'fields': [{'bits': 'D7', 'lines': ['0: Headset detection disabled', '1: Headset detection enabled'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D5', 'lines': ['00: No headset detected', '01: Headset without microphone is detected', '10: Reserved', '11: Headset with microphone is detected'], 'reset': 'XX', 'rw': 'R'}, {'bits': 'D4–D2', 'lines': ['Debounce Programming for Glitch Rejection During Headset Detection (1)', '000: 16 ms (sampled with 2-ms clock)', '001: 32 ms (sampled with 4-ms clock)', '010: 64 ms (sampled with 8-ms clock)', '011: 128 ms (sampled with 16-ms clock)', '100: 256 ms (sampled with 32-ms clock)', '101: 512 ms (sampled with 64-ms clock)', '110: Reserved', '111: Reserved'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['Debounce programming for glitch rejection during headset button-press detection', '00: 0 ms', '01: 8 ms (sampled with 1-ms clock)', '10: 16 ms (sampled with 2-ms clock)', '11: 32 ms (sampled with 4-ms clock)', '(1) Note that these times are generated using the 1 MHz reference clock which is ' 'defined in Page 3 / Register 16.'], 'reset': '00', 'rw': 'R/W'}]}, (0, 68): {'fields': [{'bits': 'D7', 'lines': ['Reserved. Write only the reset value to these bits.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: DRC disabled for left channel', '1: DRC enabled for left channel'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5', 'lines': ['0: DRC disabled for right channel', '1: DRC enabled for right channel'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D4–D2', 'lines': ['000: DRC threshold = –3 dB', '001: DRC threshold = –6 dB', '010: DRC threshold = –9 dB', '011: DRC threshold = –12 dB', '100: DRC threshold = –15 dB', '101: DRC threshold = –18 dB', '110: DRC threshold = –21 dB', '111: DRC threshold = –24 dB'], 'reset': '011', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: DRC hysteresis = 0 dB', '01: DRC hysteresis = 1 dB', '10: DRC hysteresis = 2 dB', '11: DRC hysteresis = 3 dB'], 'reset': '11', 'rw': 'R/W'}]}, (0, 69): {'fields': [{'bits': 'D7', 'lines': ['Reserved. Write only the reset value to these bits.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D3', 'lines': ['DRC Hold Time', '0000: DRC Hold Disabled', '0001: DRC Hold Time = 32 DAC Word Clocks', '0010: DRC Hold Time = 64 DAC Word Clocks', '0011: DRC Hold Time = 128 DAC Word Clocks', '0100: DRC Hold Time = 256 DAC Word Clocks', '0101: DRC Hold Time = 512 DAC Word Clocks', '0110: DRC Hold Time = 1024 DAC Word Clocks', '0111: DRC Hold Time = 2048 DAC Word Clocks', '1000: DRC Hold Time = 4096 DAC Word Clocks', '1001: DRC Hold Time = 8192 DAC Word Clocks', '1010: DRC Hold Time = 16 384 DAC Word Clocks', '1011: DRC Hold Time = 32 768 DAC Word Clocks', '1100: DRC Hold Time = 65 536 DAC Word Clocks', '1101: DRC Hold Time = 98 304 DAC Word Clocks', '1110: DRC Hold Time = 131 072 DAC Word Clocks', '1111: DRC Hold Time = 163 840 DAC Word Clocks'], 'reset': '0111', 'rw': 'R/W'}, {'bits': 'D2–D0', 'lines': ['Reserved. Write only the reset value to these bits.'], 'reset': '000', 'rw': 'R'}]}, (0, 70): {'fields': [{'bits': 'D7–D4', 'lines': ['0000: DRC attack rate = 4 dB per DAC Word Clock', '0001: DRC attack rate = 2 dB per DAC word clock', '0010: DRC attack rate = 1 dB per DAC word clock', '...', '1110: DRC attack rate = 2.4414e–5 dB per DAC word clock', '1111: DRC attack rate = 1.2207e–5 dB per DAC word clock'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D3–D0', 'lines': ['Decay Rate is defined as DR / 2[bits D3-D0 value] dB per DAC Word Clock, where DR = ' '0.015625 dB', '0000: DRC decay rate (DR) = 0.015625 dB per DAC Word Clock', '0001: DRC decay rate = DR / 2 dB per DAC Word Clock', '0010: DRC decay rate = DR / 22 dB per DAC Word Clock', '0011: DRC decay rate = DR / 23 dB per DAC Word Clock', '0100: DRC decay rate = DR / 24 dB per DAC Word Clock', '0101: DRC decay rate = DR / 25 dB per DAC Word Clock', '0110: DRC decay rate = DR / 26 dB per DAC Word Clock', '0111: DRC decay rate = DR / 27 dB per DAC Word Clock', '1000: DRC decay rate = DR / 28 dB per DAC Word Clock', '1001: DRC decay rate = DR / 29 dB per DAC Word Clock', '1010: DRC decay rate = DR / 210 dB per DAC Word Clock', '1011: DRC decay rate = DR / 211 dB per DAC Word Clock', '1100: DRC decay rate = DR / 212 dB per DAC Word Clock', '1101: DRC decay rate = DR / 213 dB per DAC Word Clock', '1110: DRC decay rate = DR / 214 dB per DAC Word Clock', '1111: DRC decay rate = DR / 215 dB per DAC Word Clock'], 'reset': '0000', 'rw': 'R/W'}]}, (0, 71): {'fields': [{'bits': 'D7', 'lines': ['0: Beep generator is disabled.', '1: Beep generator is enabled (self-clearing based on beep duration).'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['Reserved. Write only reset value.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5–D0', 'lines': ['00 0000: Left-channel beep volume control = 2 dB', '00 0001: Left-channel beep volume control = 1 dB', '00 0010: Left-channel beep volume control = 0 dB', '00 0011: Left-channel beep volume control = –1 dB', '...', '11 1110: Left-channel beep volume control = –60 dB', '11 1111: Left-channel beep volume control = –61 dB', '(1) The beep generator is only available in PRB_P25 DAC processing mode.'], 'reset': '00 0000', 'rw': 'R/W'}]}, (0, 72): {'fields': [{'bits': 'D7–D6', 'lines': ['00: Left and right channels have independent beep volume control.', '01: Left-channel beep volume control is the programmed value of right-channel beep ' 'volume control.', '10: Right-channel beep volume control is the programmed value of left-channel beep ' 'volume control.', '11: Same as 00'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D5–D0', 'lines': ['00 0000: Right-channel beep volume control = 2 dB', '00 0001: Right-channel beep volume control = 1 dB', '00 0010: Right-channel beep volume control = 0 dB', '00 0011: Right-channel beep volume control = –1 dB', '...', '11 1110: Right-channel beep volume control = –60 dB', '11 1111: Right-channel beep volume control = –61 dB'], 'reset': '00 0000', 'rw': 'R/W'}]}, (0, 73): {'fields': [{'bits': 'D7–D0', 'lines': ['8 MSBs out of 24 bits for the number of samples for which the beep must be ' 'generated.'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 74): {'fields': [{'bits': 'D7–D0', 'lines': ['8 middle bits out of 24 bits for the number of samples for which the beep must be ' 'generated.'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (0, 75): {'fields': [{'bits': 'D7–D0', 'lines': ['8 LSBs out of 24 bits for the number of samples for which beep must be generated.'], 'reset': '1110 1110', 'rw': 'R/W'}]}, (0, 76): {'fields': [{'bits': 'D7–D0', 'lines': ['8 MSBs out of 16 bits for sin(2π × fin / fS), where fin is the beep frequency and fS ' 'is the DAC sample rate.'], 'reset': '0001 0000', 'rw': 'R/W'}]}, (0, 77): {'fields': [{'bits': 'D7–D0', 'lines': ['8 LSBs out of 16 bits for sin(2π × fin / fS), where fin is the beep frequency and fS ' 'is the DAC sample rate.'], 'reset': '1101 1000', 'rw': 'R/W'}]}, (0, 78): {'fields': [{'bits': 'D7–D0', 'lines': ['8 MSBs out of 16 bits for cos(2π × fin / fS), where fin is the beep frequency and fS ' 'is the DAC sample', 'rate.'], 'reset': '0111 1110', 'rw': 'R/W'}]}, (0, 79): {'fields': [{'bits': 'D7–D0', 'lines': ['8 LSBs out of 16 bits for cos(2π × fin / fS), where fin is the beep frequency and fS ' 'is the DAC sample rate.'], 'reset': '1110 0011', 'rw': 'R/W'}]}, (0, 116): {'fields': [{'bits': 'D7', 'lines': ['0: DAC volume control is controlled by control register. (7-bit Vol ADC is powered ' 'down)', '1: DAC volume control is controlled by pin.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: Internal on-chip RC oscillator is used for the 7-bit Vol ADC for pin volume ' 'control.', '1: MCLK is used for the 7-bit Vol ADC for pin volume control.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5–D4', 'lines': ['00: No hysteresis for volume control ADC output', '01: Hysteresis of ±1 bit', '10: Hysteresis of ±2 bits', '11: Reserved. Do not write this sequence to these bits.'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['Reserved. Write only reset value.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2–D0', 'lines': ['Throughput of the 7-bit Vol ADC for pin volume control, frequency based on MCLK or ' 'internal oscillator.', 'MCLK = 12 MHz Internal Oscillator Source', '000: Throughput = 15.625 Hz 10.68 Hz', '001: Throughput = 31.25 Hz 21.35 Hz', '010: Throughput = 62.5 Hz 42.71 Hz', '011: Throughput = 125 Hz 8.2 Hz', '100: Throughput = 250 Hz 170 Hz', '101: Throughput = 500 Hz 340 Hz', '110: Throughput = 1 kHz 680 Hz', '111: Throughput = 2 kHz 1.37 kHz', 'Note: These values are based on a nominal oscillator', 'frequency of 8.2 MHz. The values scale to the actual', 'oscillator frequency.'], 'reset': '000', 'rw': 'R/W'}]}, (0, 117): {'fields': [{'bits': 'D7', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['000 0000: Gain applied by pin volume control = 18 dB', '000 0001: Gain applied by pin volume control = 17.5 dB', '000 0010: Gain applied by pin volume control = 17 dB', '...', '010 0011: Gain applied by pin volume control = 0.5 dB', '010 0100: Gain applied by pin volume control = 0 dB', '010 0101: Gain applied by pin volume control = –0.5 dB', '...', '101 1001: Gain applied by pin volume control = –26.5 dB', '101 1010: Gain applied by pin volume control = –27 dB', '101 1011: Gain applied by pin volume control = –28 dB', '...', '111 1101: Gain applied by pin volume control = –62 dB', '111 1110: Gain applied by pin volume control = –63 dB', '111 1111: Reserved.'], 'reset': 'XXX XXXX', 'rw': 'R'}]}, (1, 0): {'fields': [{'bits': 'D7–D0', 'lines': ['0000 0000: Page 0 selected', '0000 0001: Page 1 selected', '...', '1111 1110: Page 254 selected', '1111 1111: Page 255 selected'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (1, 30): {'fields': [{'bits': 'D7–D2', 'lines': ['Reserved'], 'reset': '0000 00', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['0: Reset SPK power-up control bits on short-circuit detection.', '1: SPK power-up control bits remain unchanged on short-circuit detection.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Reset HPL and HPR power-up control bits on short-circuit detection if page 1 / ' 'register 31, D1 = 1.', '1: HPL and HPR power-up control bits remain unchanged on short-circuit detection.'], 'reset': '0', 'rw': 'R/W'}]}, (1, 31): {'fields': [{'bits': 'D7', 'lines': ['0: HPL output driver is powered down.', '1: HPL output driver is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: HPR output driver is powered down.', '1: HPR output driver is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D4–D3', 'lines': ['00: Output common-mode voltage = 1.35 V', '01: Output common-mode voltage = 1.5 V', '10: Output common-mode voltage = 1.65 V', '11: Output common-mode voltage = 1.8 V'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['Reserved. Write only 1 to this bit.'], 'reset': '1', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['0: If short-circuit protection is enabled for headphone driver and short circuit ' 'detected, device limits the', 'maximum current to the load.', '1: If short-circuit protection is enabled for headphone driver and short circuit ' 'detected, device powers', 'down the output driver.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Short circuit is not detected on the headphone driver.', '1: Short circuit is detected on the headphone driver.'], 'reset': '0', 'rw': 'R'}]}, (1, 32): {'fields': [{'bits': 'D7', 'lines': ['0: Class-D output driver is powered down.', '1: Class-D output driver is powered up.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D1', 'lines': ['Reserved. Write only the reset value to this bit.'], 'reset': '000 011', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Short circuit is not detected on the class-D driver. Valid only if class-D ' 'amplifier is powered up. For', 'short-circuit flag sticky bit, see page 0 / register 44.', '1: Short circuit is detected on the class-D driver. Valid only if class-D amp is ' 'powered-up. For short-', 'circuit flag sticky bit, see page 0 / register 44.'], 'reset': '0', 'rw': 'R'}]}, (1, 33): {'fields': [{'bits': 'D7', 'lines': ['0: If the power down sequence is activated by device software, power down using page ' '1 / register 46,', 'bit D7, then power down the DAC simultaneously with the HP and SP amplifiers.', '1: If the power down sequence is activated by device software, power down using page ' '1 / register 46,', 'bit D7, then power down DAC only after HP and SP amplifiers are completely powered ' 'down. This is to', 'optimize power-down POP.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D3', 'lines': ['0000: Driver power-on time = 0 μs', '0001: Driver power-on time = 15.3 μs', '0010: Driver power-on time = 153 μs', '0011: Driver power-on time = 1.53 ms', '0100: Driver power-on time = 15.3 ms', '0101: Driver power-on time = 76.2 ms', '0110: Driver power-on time = 153 ms', '0111: Driver power-on time = 304 ms', '1000: Driver power-on time = 610 ms', '1001: Driver power-on time = 1.22 s', '1010: Driver power-on time = 3.04 s', '1011: Driver power-on time = 6.1 s', '1100–1111: Reserved. Do not write these sequences to these bits.', 'Note: These values are based on typical oscillator frequency of 8.2 MHz. Scale ' 'according to the actual', 'oscillator frequency.'], 'reset': '0111', 'rw': 'R/W'}, {'bits': 'D2–D1', 'lines': ['00: Driver ramp-up step time = 0 ms', '01: Driver ramp-up step time = 0.98 ms', '10: Driver ramp-up step time = 1.95 ms', '11: Driver ramp-up step time = 3.9 ms', 'Note: These values are based on typical oscillator frequency of 8.2 MHz. Scale ' 'according to the actual', 'oscillator frequency.'], 'reset': '11', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Weakly driven output common-mode voltage is generated from resistor divider of ' 'the AVDD supply.', '1: Reserved'], 'reset': '0', 'rw': 'R/W'}]}, (1, 34): {'fields': [{'bits': 'D7', 'lines': ['Reserved. Write only the reset value to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D4', 'lines': ['Speaker power-up wait time (duration based on using internal oscillator)', '000: Wait time = 0 ms', '001: Wait time = 3.04 ms', '010: Wait time = 7.62 ms', '011: Wait time = 12.2 ms', '100: Wait time = 15.3 ms', '101: Wait time = 19.8 ms', '110: Wait time = 24.4 ms', '111: Wait time = 30.5 ms', 'Note: These values are based on typical oscillator frequency of 8.2 MHz. Scale ' 'according to the actual', 'oscillator frequency.'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D3–D0', 'lines': ['Reserved. Write only the reset value to these bits.'], 'reset': '0000', 'rw': 'R/W'}]}, (1, 35): {'fields': [{'bits': 'D7–D6', 'lines': ['00: DAC_L is not routed anywhere.', '01: DAC_L is routed to the left-channel mixer amplifier.', '10: DAC_L is routed directly to the HPL driver.', '11: Reserved'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D5', 'lines': ['0: AIN1 input is not routed to the left-channel mixer amplifier.', '1: AIN1 input is routed to the left-channel mixer amplifier.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D4', 'lines': ['0: AIN2 input is not routed to the left-channel mixer amplifier.', '1: AIN2 input is routed to the left-channel mixer amplifier.'], 'reset': '0', 'rw': ''}, {'bits': 'D3–D2', 'lines': ['00: DAC_R is not routed anywhere.', '01: DAC_R is routed to the right-channel mixer amplifier.', '10: DAC_R is routed directly to the HPR driver.', '11: Reserved'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['0: AIN2 input is not routed to the right-channel mixer amplifier.', '1: AIN2 input is routed to the right-channel mixer amplifier.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: HPL driver output is not routed to the HPR driver.', '1: HPL driver output is routed to the HPR driver input (used for differential output ' 'mode).'], 'reset': '0', 'rw': 'R/W'}]}, (1, 36): {'fields': [{'bits': 'D7', 'lines': ['0: Left-channel analog volume control is not routed to HPL output driver.', '1: Left-channel analog volume control is routed to HPL output driver.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['Left-channel analog volume control gain (non-linear) for the HPL output driver, 0 dB ' 'to –78 dB. See'], 'reset': '111 1111', 'rw': 'R/W'}]}, (1, 37): {'fields': [{'bits': 'D7', 'lines': ['0: Right-channel analog volume control is not routed to HPR output driver.', '1: Right-channel analog volume control is routed to HPR output driver.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['Right-channel analog volume control gain (non-linear) for the HPR output driver, 0 ' 'dB to –78 dB. See'], 'reset': '111 1111', 'rw': 'R/W'}]}, (1, 38): {'fields': [{'bits': 'D7', 'lines': ['0: Left-channel analog volume control output is not routed to class-D output driver.', '1: Left-channel analog volume control output is routed to class-D output driver.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['Left-channel analog volume control output gain (non-linear) for the class-D output ' 'driver, 0 dB to –78', 'dB. See Table 6-24.'], 'reset': '111 1111', 'rw': 'R/W'}]}, (1, 40): {'fields': [{'bits': 'D7', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D3', 'lines': ['0000: HPL driver PGA = 0 dB', '0001: HPL driver PGA = 1 dB', '0010: HPL driver PGA = 2 dB', '...', '1000: HPL driver PGA = 8 dB', '1001: HPL driver PGA = 9 dB', '1010–1111: Reserved. Do not write these sequences to these bits.'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: HPL driver is muted.', '1: HPL driver is not muted.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['Reserved'], 'reset': '1', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Not all programmed gains to HPL have been applied yet.', '1: All programmed gains to HPL have been applied.'], 'reset': '0', 'rw': 'R'}]}, (1, 41): {'fields': [{'bits': 'D7', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D3', 'lines': ['0000: HPR driver PGA = 0 dB', '0001: HPR driver PGA = 1 dB', '0010: HPR driver PGA = 2 dB', '...', '1000: HPR driver PGA = 8 dB', '1001: HPR driver PGA = 9 dB', '1010–1111: Reserved. Do not write these sequences to these bits.'], 'reset': '0000', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: HPR driver is muted.', '1: HPR driver is not muted.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ["Reserved. Write only '1' to this bit."], 'reset': '1', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Not all programmed gains to HPR have been applied yet.', '1: All programmed gains to HPR have been applied.'], 'reset': '0', 'rw': 'R'}]}, (1, 42): {'fields': [{'bits': 'D7–D5', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D4–D3', 'lines': ['00: Class-D driver output stage gain = 6 dB', '01: Class-D driver output stage gain = 12 dB', '10: Class-D driver output stage gain = 18 dB', '11: Class-D driver output stage gain = 24 dB'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: Class-D driver is muted.', '1: Class-D driver is not muted.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['0: Not all programmed gains to the Class-D driver have been applied yet.', '1: All programmed gains to the Class-D driver have been applied.'], 'reset': '0', 'rw': 'R'}]}, (1, 44): {'fields': [{'bits': 'D7–D5', 'lines': ['Debounce time for the headset short-circuit detection', 'MCLK/DIV (Page 3 /', '(1)', 'register 16) = 1-MHz Internal Oscillator Source', 'Source', '000: Debounce time = 0 μs 0 μs', '001: Debounce time = 8 μs 7.8 μs', '010: Debounce time = 16 μs 15.6 μs', '011: Debounce time = 32 μs 31.2 μs', '100: Debounce time = 64 μs 62.4 μs', '101: Debounce time = 128 μs 124.9 μs', '110: Debounce time = 256 μs 250 μs', '111: Debounce time = 512 μs 500 μs', 'Note: These values are based on a nominal oscillator', 'frequency of 8.2 MHz. The values scale to the actual', 'oscillator frequency.'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D4–D3', 'lines': ['00: Default mode for the DAC', '01: DAC performance increased by increasing the current', '10: Reserved', '11: DAC performance increased further by increasing the current again', '(1) The clock used for the debounce has a clock period = debounce duration / 8.'], 'reset': '00', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['0: HPL output driver is programmed as headphone driver.', '1: HPL output driver is programmed as lineout driver.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1', 'lines': ['0: HPR output driver is programmed as headphone driver.', '1: HPR output driver is programmed as lineout driver.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D0', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}]}, (1, 46): {'fields': [{'bits': 'D7', 'lines': ['0: Device software power down is not enabled.', '1: Device software power down is enabled.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6–D4', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '000', 'rw': 'R/W'}, {'bits': 'D3', 'lines': ['0: Programmed MICBIAS is not powered up if headset detection is enabled but headset ' 'is not inserted.', '1: Programmed MICBIAS is powered up even if headset is not inserted.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D2', 'lines': ['Reserved. Write only zero to this bit.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D1–D0', 'lines': ['00: MICBIAS output is powered down.', '01: MICBIAS output is powered to 2 V.', '10: MICBIAS output is powered to 2.5 V.', '11: MICBIAS output is powered to AVDD.'], 'reset': '00', 'rw': 'R/W'}]}, (1, 50): {'fields': [{'bits': 'D7', 'lines': ['0: AIN1 input is floating, if it is not used for the analog bypass.', '1: AIN1 input is connected to CM internally, if it is not used for the analog ' 'bypass.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D6', 'lines': ['0: AIN2 input is floating, if it is not used for the analog bypass.', '1: AIN2 input is connected to CM internally, if it is not used for the analog ' 'bypass.'], 'reset': '0', 'rw': 'R/W'}, {'bits': 'D5–D0', 'lines': ['Reserved. Write only zeros to these bits.'], 'reset': '00 0000', 'rw': 'R/W'}]}, (3, 0): {'fields': [{'bits': 'D7–D0', 'lines': ['0000 0000: Page 0 selected', '0000 0001: Page 1 selected', '...', '1111 1110: Page 254 selected', '1111 1111: Page 255 selected', 'The only register used in page 3 is register 16. The remaining page-3 registers are ' 'reserved and must not', 'be written to.'], 'reset': '0000 0000', 'rw': 'R/W'}]}, (3, 16): {'fields': [{'bits': 'D7', 'lines': ['0: Internal oscillator is used for programmable delay timer.', '1: External MCLK (1) is used for programmable delay timer.'], 'reset': '1', 'rw': 'R/W'}, {'bits': 'D6–D0', 'lines': ['MCLK Divider to Generate 1-MHz Clock for the Programmable Delay Timer', '000 0000: MCLK divider = 128', '000 0001: MCLK divider = 1', '000 0010: MCLK divider = 2', '...', '111 1110: MCLK divider = 126', '111 1111: MCLK divider = 127', '(1) External clock is used only to control the delay programmed between the ' 'conversions and not used for doing the actual conversion. This', 'feature is provided in case a more accurate delay is desired because the internal ' 'oscillator frequency varies from device to device.', 'Default values shown for this page only become valid 100 μs following a hardware or ' 'software reset.'], 'reset': '000 0001', 'rw': 'R/W'}]}} ANALOG_VOLUME_DB = [0.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, -3.5, -4.0, -4.5, -5.0, -5.5, -6.0, -6.5, -7.0, -7.5, -8.0, -8.5, -9.0, -9.5, -10.0, -10.5, -11.0, -11.5, -12.0, -12.5, -13.0, -13.5, -14.0, -14.5, -15.0, -15.5, -16.0, -16.5, -17.0, -17.5, -18.1, -18.6, -19.1, -19.6, -20.1, -20.6, -21.1, -21.6, -22.1, -22.6, -23.1, -23.6, -24.1, -24.6, -25.1, -25.6, -26.1, -26.6, -27.1, -27.6, -28.1, -28.6, -29.1, -29.6, -30.1, -30.6, -31.1, -31.6, -32.1, -32.6, -33.1, -33.6, -34.1, -34.6, -35.2, -35.7, -36.2, -36.7, -37.2, -37.7, -38.2, -38.7, -39.2, -39.7, -40.2, -40.7, -41.2, -41.7, -42.1, -42.7, -43.2, -43.8, -44.3, -44.8, -45.2, -45.8, -46.2, -46.7, -47.4, -47.9, -48.2, -48.7, -49.3, -50.0, -50.3, -51.0, -51.4, -51.8, -52.2, -52.7, -53.7, -54.2, -55.3, -56.7, -58.3, -60.2, -62.7, -64.3, -66.2, -68.7, -72.2, -78.3, -78.3, -78.3, -78.3, -78.3, -78.3, -78.3, -78.3, -78.3, -78.3, -78.3] PAGE_CONTROL_FIELDS = [ { "bits": "D7–D0", "rw": "R/W", "reset": "0000 0000", "lines": [ "0000 0000: Page 0 selected", "0000 0001: Page 1 selected", "...", "1111 1110: Page 254 selected", "1111 1111: Page 255 selected", ], } ] for page in (8, 9, 12, 13): REGISTER_FIELDS[(page, 0)] = {"fields": PAGE_CONTROL_FIELDS} REGISTER_FIELDS[(8, 1)] = { "fields": [ { "bits": "D7–D3", "rw": "R/W", "reset": "0000 0", "lines": ["Reserved. Write only the reset value."], }, { "bits": "D2", "rw": "R/W", "reset": "0", "lines": [ "0: Adaptive filtering disabled in DAC processing block", "1: Adaptive filtering enabled in DAC processing block", ], }, { "bits": "D1", "rw": "R", "reset": "0", "lines": [ "0: In adaptive filter mode, DAC processing block accesses DAC coefficient Buffer A and the external control interface accesses DAC coefficient Buffer B", "1: In adaptive filter mode, DAC processing block accesses DAC coefficient Buffer B and the external control interface accesses DAC coefficient Buffer A", ], }, { "bits": "D0", "rw": "R/W", "reset": "0", "lines": [ "0: DAC coefficient buffers are not switched at the next frame boundary.", "1: DAC coefficient buffers are switched at the next frame boundary, if adaptive filtering mode is enabled. This bit self-clears on switching.", ], }, ] } PAGE0_GROUPS = { 7: {"registers": (7, 8), "name": "PLL fractional multiplier D-value", "kind": "pll_d"}, 13: {"registers": (13, 14), "name": "DAC DOSR value", "kind": "dosr"}, 73: {"registers": (73, 74, 75), "name": "Beep length", "kind": "beep_length"}, 76: {"registers": (76, 77), "name": "Beep sin(x)", "kind": "s16"}, 78: {"registers": (78, 79), "name": "Beep cos(x)", "kind": "s16"}, } PAGE0_GROUPED_REGS = {reg for group in PAGE0_GROUPS.values() for reg in group["registers"]} BINARY_ENUM_RANGE_RE = re.compile(r"^([01 ]+)[–-]([01 ]+):\s*(.+)$") BINARY_ENUM_EXACT_RE = re.compile(r"^([01 ]+):\s*(.+)$") PAIR_COEFF_MSB_RE = re.compile(r"^Coefficient ([A-Z0-9]+)\(15:8\) for (.+)$") PAIR_COEFF_LSB_RE = re.compile(r"^Coefficient ([A-Z0-9]+)\(7:0\) for (.+)$") PAIR_MSB_RE = re.compile(r"^8 MSBs of (.+)$") PAIR_LSB_RE = re.compile(r"^8 LSBs of (.+)$") def run_command(argv: list[str], *, check: bool = True) -> subprocess.CompletedProcess[str]: proc = subprocess.run(argv, capture_output=True, text=True) if check and proc.returncode != 0: stderr = proc.stderr.strip() stdout = proc.stdout.strip() detail = stderr or stdout or f"exit status {proc.returncode}" raise CommandError(f"{shlex.join(argv)} failed: {detail}") return proc def select_page(bus: int, addr: int, page: int) -> None: run_command([ "i2cset", "-y", "-f", str(bus), f"0x{addr:02x}", "0x00", f"0x{page:02x}", ]) def read_register(bus: int, addr: int, reg: int) -> int: proc = run_command([ "i2cget", "-y", "-f", str(bus), f"0x{addr:02x}", f"0x{reg:02x}", ]) match = re.search(r"0x([0-9A-Fa-f]{1,2})(?:\s|$)", proc.stdout) if not match: raise CommandError(f"unexpected i2cget output: {proc.stdout.strip()!r}") return int(match.group(1), 16) def read_page(bus: int, addr: int) -> list[int]: i2ctransfer = shutil.which("i2ctransfer") if i2ctransfer: values: list[int] = [] for start in range(0, 128, 32): proc = run_command([ i2ctransfer, "-y", "-f", str(bus), f"w1@0x{addr:02x}", f"0x{start:02x}", "r32", ]) tokens = re.findall(r"0x([0-9A-Fa-f]{2})(?:\s|$)", proc.stdout) if len(tokens) != 32: raise CommandError( "unexpected i2ctransfer output while reading a page: " f"{proc.stdout.strip()!r}" ) values.extend(int(token, 16) for token in tokens) return values return [read_register(bus, addr, reg) for reg in range(128)] def is_reserved_register(page: int, reg: int) -> bool: return REGISTER_MAP[page][reg].startswith("Reserved") def normalize_bits(bits: str) -> str: return bits.replace("-", "–") def bit_range(bits: str) -> tuple[int, int]: cleaned = re.sub(r"\s*\(\d+\)", "", normalize_bits(bits)) match = re.match(r"^D(\d+)(?:[–-]D?(\d+))?$", cleaned) if not match: raise ValueError(f"unsupported bit spec: {bits!r}") hi = int(match.group(1)) lo = int(match.group(2) or match.group(1)) if hi < lo: hi, lo = lo, hi return hi, lo def bit_width(bits: str) -> int: hi, lo = bit_range(bits) return hi - lo + 1 def extract_bits(value: int, bits: str) -> int: hi, lo = bit_range(bits) return (value >> lo) & ((1 << (hi - lo + 1)) - 1) def format_bit_value(value: int, width: int) -> str: return format(value, f"0{width}b") def to_signed16(value: int) -> int: return value - 0x10000 if value & 0x8000 else value def format_db(value: float) -> str: return f"{value:g} dB" def field_is_reserved(field: dict[str, object]) -> bool: lines = field.get("lines", []) if not lines: return False first = str(lines[0]).strip() return first.startswith("Reserved") def decode_special_field(page: int, reg: int, bits: str, raw: int) -> str | None: key = (page, reg, normalize_bits(bits)) if reg == 0 and normalize_bits(bits) == "D7–D0": return f"Page {raw} selected" if key == (0, 5, "D6–D4"): return f"PLL divider P = {8 if raw == 0 else raw}" if key == (0, 5, "D3–D0"): return f"PLL multiplier R = {16 if raw == 0 else raw}" if key == (0, 6, "D5–D0"): return "Reserved. Do not use" if raw == 0 else f"PLL multiplier J = {raw}" if key == (0, 11, "D6–D0"): return f"DAC NDAC divider = {128 if raw == 0 else raw}" if key == (0, 12, "D6–D0"): return f"DAC MDAC divider = {128 if raw == 0 else raw}" if key == (0, 26, "D6–D0"): return f"CLKOUT divider M = {128 if raw == 0 else raw}" if key == (0, 28, "D7–D0"): suffix = "" if raw == 1 else "s" return f"Offset = {raw} BCLK{suffix}" if key == (0, 30, "D6–D0"): return f"BCLK divider N = {128 if raw == 0 else raw}" if key == (0, 60, "D4–D0"): if 1 <= raw <= 25: return f"DAC signal-processing block PRB_P{raw}" return "Reserved. Do not use" if key in {(0, 65, "D7–D0"), (0, 66, "D7–D0")}: if raw == 0x80: return "Reserved" if 0x00 <= raw <= 0x30: return f"Digital volume control = {format_db(raw * 0.5)}" if 0x81 <= raw <= 0xFF: return f"Digital volume control = {format_db(-0.5 * (0x100 - raw))}" return "Reserved. Do not use" if key == (0, 70, "D7–D4"): return f"DRC attack rate = {4 / (2 ** raw):g} dB per DAC word clock" if key == (0, 71, "D5–D0"): return f"Left-channel beep volume control = {format_db(2 - raw)}" if key == (0, 72, "D5–D0"): return f"Right-channel beep volume control = {format_db(2 - raw)}" if key == (0, 117, "D6–D0"): return "Reserved" if raw == 0x7F else f"Gain applied by pin volume control = {format_db(18 - 0.5 * raw)}" if key == (1, 36, "D6–D0"): return f"Left-channel analog gain to HPL = {format_db(ANALOG_VOLUME_DB[raw])}" if key == (1, 37, "D6–D0"): return f"Right-channel analog gain to HPR = {format_db(ANALOG_VOLUME_DB[raw])}" if key == (1, 38, "D6–D0"): return f"Left-channel analog gain to SPK = {format_db(ANALOG_VOLUME_DB[raw])}" if key == (1, 40, "D6–D3"): return "Reserved. Do not write this sequence" if raw > 9 else f"HPL driver PGA = {format_db(raw)}" if key == (1, 41, "D6–D3"): return "Reserved. Do not write this sequence" if raw > 9 else f"HPR driver PGA = {format_db(raw)}" if key == (3, 16, "D6–D0"): return f"MCLK divider = {128 if raw == 0 else raw}" return None def parse_enum_lines(lines: list[str]) -> tuple[list[str], list[tuple[int, int, str]]]: intros: list[str] = [] enums_mutable: list[list[object]] = [] for line in lines: cleaned = " ".join(str(line).split()) if not cleaned or cleaned == "...": continue if cleaned.startswith("(") or cleaned.startswith("Note:") or re.match(r"^6\.\d", cleaned): continue if cleaned.startswith("The only register used") or cleaned.startswith("The remaining"): continue if cleaned.startswith("Default values shown"): continue match = BINARY_ENUM_RANGE_RE.match(cleaned) if match: start = int(match.group(1).replace(" ", ""), 2) end = int(match.group(2).replace(" ", ""), 2) enums_mutable.append([start, end, match.group(3)]) continue match = BINARY_ENUM_EXACT_RE.match(cleaned) if match: code = int(match.group(1).replace(" ", ""), 2) enums_mutable.append([code, code, match.group(2)]) continue if enums_mutable: enums_mutable[-1][2] = f"{enums_mutable[-1][2]} {cleaned}".strip() else: intros.append(cleaned) enums = [(int(start), int(end), str(text)) for start, end, text in enums_mutable] return intros, enums def decode_field(page: int, reg: int, field: dict[str, object], value: int) -> str | None: bits = str(field["bits"]) raw = extract_bits(value, bits) special = decode_special_field(page, reg, bits, raw) if special is not None: return special intros, enums = parse_enum_lines(list(field.get("lines", []))) for start, end, text in enums: if start <= raw <= end: return text if intros: return "; ".join(intros) return None def print_register_value(page: int, reg: int, value: int) -> None: name = REGISTER_MAP[page][reg] print(f"P{page:02d} R{reg:03d} (0x{reg:02X}) = 0x{value:02X} {name}") info = REGISTER_FIELDS.get((page, reg)) if not info: return for field in info.get("fields", []): if field_is_reserved(field): continue bits = str(field["bits"]) raw = extract_bits(value, bits) width = bit_width(bits) meaning = decode_field(page, reg, field, value) if meaning is None: continue print(f" {bits} = {format_bit_value(raw, width)} -> {meaning}") def print_register_description(page: int, reg: int) -> None: print(f"P{page:02d} R{reg:03d} (0x{reg:02X}) {REGISTER_MAP[page][reg]}") def print_page0_group_value(start_reg: int, values: list[int]) -> None: group = PAGE0_GROUPS[start_reg] regs = group["registers"] kind = group["kind"] name = group["name"] if kind == "pll_d": raw = ((values[7] & 0x3F) << 8) | values[8] print(f"P00 R007/R008 (0x07/0x08) = 0x{raw:04X} ({raw}) {name}") return if kind == "dosr": raw = ((values[13] & 0x03) << 8) | values[14] if raw == 0: meaning = "effective DOSR = 1024" elif raw in (1, 0x3FF): meaning = "Reserved / invalid DOSR value" else: meaning = f"effective DOSR = {raw}" print(f"P00 R013/R014 (0x0D/0x0E) = 0x{raw:03X} ({raw}) {name}; {meaning}") return if kind == "beep_length": raw = (values[73] << 16) | (values[74] << 8) | values[75] print(f"P00 R073/R074/R075 (0x49/0x4A/0x4B) = 0x{raw:06X} ({raw}) {name} in DAC samples") return if kind == "s16": msb, lsb = regs raw = (values[msb] << 8) | values[lsb] signed = to_signed16(raw) print( f"P00 R{msb:03d}/R{lsb:03d} (0x{msb:02X}/0x{lsb:02X}) = 0x{raw:04X} ({signed:+d}) {name}" ) return raise AssertionError(f"unknown page-0 group kind: {kind}") def print_page0_group_description(start_reg: int) -> None: group = PAGE0_GROUPS[start_reg] regs = group["registers"] joined_regs = "/".join(f"R{reg:03d}" for reg in regs) joined_hex = "/".join(f"0x{reg:02X}" for reg in regs) print(f"P00 {joined_regs} ({joined_hex}) {group['name']}") def pair_label(desc1: str, desc2: str) -> str | None: msb_match = PAIR_COEFF_MSB_RE.match(desc1) lsb_match = PAIR_COEFF_LSB_RE.match(desc2) if msb_match and lsb_match: if msb_match.group(1) == lsb_match.group(1) and msb_match.group(2) == lsb_match.group(2): return f"Coefficient {msb_match.group(1)} for {msb_match.group(2)}" msb_match = PAIR_MSB_RE.match(desc1) lsb_match = PAIR_LSB_RE.match(desc2) if msb_match and lsb_match and msb_match.group(1) == lsb_match.group(1): return msb_match.group(1) return None def print_coeff_page_values(page: int, values: list[int]) -> None: reg = 0 while reg < 128: if is_reserved_register(page, reg): reg += 1 continue if (page, reg) in REGISTER_FIELDS: print_register_value(page, reg, values[reg]) reg += 1 continue if reg + 1 < 128 and not is_reserved_register(page, reg + 1): label = pair_label(REGISTER_MAP[page][reg], REGISTER_MAP[page][reg + 1]) if label is not None: raw = (values[reg] << 8) | values[reg + 1] signed = to_signed16(raw) print( f"P{page:02d} R{reg:03d}/R{reg + 1:03d} (0x{reg:02X}/0x{reg + 1:02X}) = 0x{raw:04X} ({signed:+d}) {label}" ) reg += 2 continue print_register_value(page, reg, values[reg]) reg += 1 def print_coeff_page_descriptions(page: int) -> None: reg = 0 while reg < 128: if is_reserved_register(page, reg): reg += 1 continue if (page, reg) in REGISTER_FIELDS: print_register_description(page, reg) reg += 1 continue if reg + 1 < 128 and not is_reserved_register(page, reg + 1): label = pair_label(REGISTER_MAP[page][reg], REGISTER_MAP[page][reg + 1]) if label is not None: print( f"P{page:02d} R{reg:03d}/R{reg + 1:03d} (0x{reg:02X}/0x{reg + 1:02X}) {label}" ) reg += 2 continue print_register_description(page, reg) reg += 1 def print_page_values(page: int, values: list[int]) -> None: if page in (8, 9, 12, 13): print_coeff_page_values(page, values) return for reg in range(128): if is_reserved_register(page, reg): continue if page == 0 and reg in PAGE0_GROUPED_REGS: if reg in PAGE0_GROUPS: print_page0_group_value(reg, values) continue print_register_value(page, reg, values[reg]) def print_page_descriptions(page: int) -> None: if page in (8, 9, 12, 13): print_coeff_page_descriptions(page) return for reg in range(128): if is_reserved_register(page, reg): continue if page == 0 and reg in PAGE0_GROUPED_REGS: if reg in PAGE0_GROUPS: print_page0_group_description(reg) continue print_register_description(page, reg) def make_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Dump TLV320DAC3100 registers and decode their meanings.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument("--bus", type=parse_int, default=1, help="I2C bus number") parser.add_argument( "--addr", type=parse_int, default=0x18, help="7-bit TLV320DAC3100 I2C address", ) parser.add_argument( "--pages", type=parse_pages, default=list(DEFINED_PAGES), help="comma-separated page list, or 'all'", ) parser.add_argument( "--descriptions-only", action="store_true", help="do not touch I2C; print only non-reserved registers and grouped fields", ) return parser def main() -> int: parser = make_parser() args = parser.parse_args() try: print("# TLV320DAC3100 register dump") print("# source: hard-coded from tlv320dac3100.pdf (Rev. C)") if args.descriptions_only: print("# mode: descriptions only (reserved registers omitted)") else: print( f"# mode: live I2C read on bus {args.bus}, addr 0x{args.addr:02x} " "(reserved registers omitted)" ) for page in args.pages: print() print(f"[page {page}]") if args.descriptions_only: print_page_descriptions(page) continue select_page(args.bus, args.addr, page) values = read_page(args.bus, args.addr) print_page_values(page, values) if not args.descriptions_only: try: select_page(args.bus, args.addr, 0) except CommandError: pass return 0 except (CommandError, argparse.ArgumentTypeError, ValueError) as exc: print(f"error: {exc}", file=sys.stderr) return 1 except KeyboardInterrupt: print("interrupted", file=sys.stderr) return 130 if __name__ == "__main__": sys.exit(main())