Devicetree
 help / color / mirror / Atom feed
From: Karl Asseily <karl@asseily.com>
To: broonie@kernel.org, lgirdwood@gmail.com, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, perex@perex.cz,
	tiwai@suse.com
Cc: linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Karl Asseily <karl@asseily.com>
Subject: [PATCH 0/4] ASoC: add ESS Technology ES9039Q2M codec driver
Date: Thu, 20 Aug 2026 09:26:22 +0300	[thread overview]
Message-ID: <20260820062626.39218-1-karl@asseily.com> (raw)

This series adds support for the ESS Technology ES9039Q2M, a 32-bit
two-channel audio DAC with an asynchronous sample rate converter,
controlled over I2C.

The part has two control personalities selected by its MODE pin: hardware
mode, strapped by HW0/HW1/HW2 with no bus at all, and software mode over
I2C or SPI. This driver implements software mode over I2C, which MODE = GND
selects.

Three properties of the part shape the driver:

 - The ASRC in front of the DAC means MCLK need not be synchronous with
   BCLK or LRCK. A board can feed it a fixed oscillator and never touch the
   clock again. In that asynchronous mode the part requires MCLK >= 130 x
   Fs, so the driver installs a startup constraint deriving the maximum
   rate from the MCLK it was given rather than advertising rates the
   hardware cannot honour.

 - Selecting an input format is two registers, not one. Register 57
   INPUT_SEL chooses which port to listen to; register 1 SYS MODE CONFIG
   enables the corresponding decoder, and at reset only ENABLE_TDM_DECODE
   is set. Selecting DoP without also enabling ENABLE_DOP_DECODE leaves the
   part hunting for a marker with the marker decoder switched off; it finds
   no valid DoP and mutes. The driver sets both.

 - Several registers have non-zero reserved defaults - register 88 reads
   0xb8 at reset - so every write is read-modify-write.

Everything the driver exposes has been verified against the silicon on
hardware rather than against the driver's own read-back: each control is
written through ALSA and the chip's register is then read over raw I2C.
That covers the eight filter shapes, the modulator bandwidth, the IIR
bandwidth, the four signed 16-bit THD compensation coefficients at both
extremes of their range, and the automute enable, time, level and off-level
fields including the neighbouring MUTE_RAMP_TO_GND bit that shares a
register with the 11-bit time field.

Two limitations are deliberate and worth stating up front, because both
look like omissions:

 - The programmable FIR coefficient controls are write-only. The part has a
   PROG_COEFF_OUT register described as "Programmable FIR coefficient
   readback", but it is not a RAM read port: it returns the last
   coefficient written, whatever address is selected in PROG_COEFF_ADDR.
   Measured by writing two different coefficients to addresses 0 and 1 and
   reading them back with five different sequences - plain, with a settle
   delay, with PROG_COEFF_EN set, with the address written twice, and with
   a write-enable pulse after the address. All ten reads returned the value
   written to address 1. A get() built on that register would return
   something with the shape of data and none of its meaning, so there is
   none.

 - Coefficient uploads pulse PROG_COEFF_WE per coefficient, as the
   datasheet's sequence specifies. Holding it high across the whole upload
   also works on this silicon, but that is not what the documentation says.

DSD, DoP and S/PDIF input are all implemented. DoP is detected by the part
rather than announced by the host: AUTO_INPUT_SEL is enabled and both the
TDM and DoP decoders run, so a player can simply send DoP-encoded PCM, which
is the only way DoP works in practice. An earlier revision of this driver
required userspace to select DoP through a kcontrol first; no player can do
that, and the result was that DoP-encoded material rendered as the near-
silent hiss the DoP marker design deliberately degrades to. The datasheet
attaches a "data must be provided on the DATA2 pin" condition to automatic
detection; that applies to identifying DSD, whose channels arrive on separate
data lines, and DoP detects correctly on a two-channel I2S link without it.

DoP was verified end to end by generating a DSD64 test tone, carrying it as
32-bit PCM at 176400 Hz with nothing selected by hand, and confirming the
part's own DOP_VALID flag and INPUT_SELECT_OVERRIDE readback while it played.

ESS Technology has no bindings in the tree today, so the series also
introduces the vendor prefix.

Karl Asseily (4):
  dt-bindings: vendor-prefixes: add ESS Technology
  ASoC: dt-bindings: add ESS Technology ES9039Q2M
  ASoC: es9039q2m: add ESS Technology ES9039Q2M codec driver
  MAINTAINERS: add entry for the ES9039Q2M codec driver

 .../bindings/sound/ess,es9039q2m.yaml         |   61 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 MAINTAINERS                                   |    7 +
 sound/soc/codecs/Kconfig                      |   14 +
 sound/soc/codecs/Makefile                     |    2 +
 sound/soc/codecs/es9039q2m.c                  | 1259 +++++++++++++++++
 6 files changed, 1345 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/ess,es9039q2m.yaml
 create mode 100644 sound/soc/codecs/es9039q2m.c

-- 
2.34.1


             reply	other threads:[~2026-08-20  6:26 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-20  6:26 Karl Asseily [this message]
2026-08-20  6:26 ` [PATCH 1/4] dt-bindings: vendor-prefixes: add ESS Technology Karl Asseily
2026-08-20  6:30   ` Krzysztof Kozlowski
2026-08-20  6:48     ` Karl Asseily
2026-08-20  6:26 ` [PATCH 2/4] ASoC: dt-bindings: add ESS Technology ES9039Q2M Karl Asseily
2026-08-20  6:26 ` [PATCH 3/4] ASoC: es9039q2m: add ESS Technology ES9039Q2M codec driver Karl Asseily
2026-08-20  6:38   ` sashiko-bot
2026-08-20  6:26 ` [PATCH 4/4] MAINTAINERS: add entry for the " Karl Asseily

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260820062626.39218-1-karl@asseily.com \
    --to=karl@asseily.com \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=robh@kernel.org \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox