Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH RFC 06/10] arm64: dts: qcom: msm8939-asus-z00t: add Venus
From: André Apitzsch @ 2026-04-19 20:26 UTC (permalink / raw)
  To: Dmitry Baryshkov, Erikas Bitovtas
  Cc: Konrad Dybcio, Bryan O'Donoghue, Vikash Garodia,
	Dikshita Agarwal, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
	Michael Turquette, Stephen Boyd, linux-media, linux-arm-msm,
	devicetree, linux-kernel, linux-clk, ~postmarketos/upstreaming,
	phone-devel
In-Reply-To: <37poakqgqhsuavvrm2dyzwk36syyq44o4cfdsylkzwsupbh2yt@ycdvyrxgnrcs>

Hi Dmitry,

Am Samstag, dem 18.04.2026 um 02:40 +0300 schrieb Dmitry Baryshkov:
> On Thu, Apr 16, 2026 at 07:57:30PM +0300, Erikas Bitovtas wrote:
> > 
> > 
> > On 4/16/26 6:17 PM, Konrad Dybcio wrote:
> > > On 4/16/26 3:43 PM, Erikas Bitovtas wrote:
> > > > Enable Venus video encoder/decoder for Asus ZenFone 2
> > > > Laser/Selfie.
> > > > 
> > > > Signed-off-by: Erikas Bitovtas <xerikasxx@gmail.com>
> > > > ---
> > > >  arch/arm64/boot/dts/qcom/msm8939-asus-z00t.dts | 8 ++++++++
> > > >  1 file changed, 8 insertions(+)
> > > > 
> > > > diff --git a/arch/arm64/boot/dts/qcom/msm8939-asus-z00t.dts
> > > > b/arch/arm64/boot/dts/qcom/msm8939-asus-z00t.dts
> > > > index 90e966242720..231a3e9c1929 100644
> > > > --- a/arch/arm64/boot/dts/qcom/msm8939-asus-z00t.dts
> > > > +++ b/arch/arm64/boot/dts/qcom/msm8939-asus-z00t.dts
> > > > @@ -267,6 +267,14 @@ &usb_hs_phy {
> > > >  	extcon = <&usb_id>;
> > > >  };
> > > >  
> > > > +&venus {
> > > > +	status = "okay";
> > > 
> > > You need a firmware path here
> > 
> > When I tested Venus on my device, it loaded without one specified -
> > msm-firmware-loader creates a symbolic link from modem partition
> > for firmware. Additionally, none of the MSM8916 devices seem to
> > include a firmware name. Has something changed since then?
> 
> Us becoming more strict? Or more caring? The default file paths are
> supposed to be used for unfused devices. So if they don't work with
> yours (most likely they don't), please add firmware-name:
> 
> firmware-name = "qcom/msm8916/Asus/z00t/venus.mbn";

For BQ M5 (msm8939-longcheer-l9100), venus works with the firmware
provided by linux-firmware [1] and the default path (here "qcom/venus-
1.8/venus.mbn").

Just to be clear, should the firmware-name still be added in this case,
even if it is the default one?

Best regards,
André


[1] https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/qcom/venus-1.8

^ permalink raw reply

* Re: [PATCH 0/4] Add hstimer support for H616 and T113-S3
From: Andre Przywara @ 2026-04-19 20:55 UTC (permalink / raw)
  To: Michal Piekos
  Cc: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
	Maxime Ripard, linux-kernel, devicetree, linux-arm-kernel,
	linux-sunxi
In-Reply-To: <20260419-h616-t113s-hstimer-v1-0-1af74ebef7c5@mmpsystems.pl>

On Sun, 19 Apr 2026 14:46:06 +0200
Michal Piekos <michal.piekos@mmpsystems.pl> wrote:

Hi Michal,

> Add support for Allwinner H616 high speed timer in sun5i hstimer driver
> and describe corresponding nodes in dts for H616 and T113-S3.
> 
> H616 uses same model as existing driver except register shift compared
> to older variants. 
> 
> Added register layout abstraction in the driver, extended the binding
> with new compatibles and wired up dts nodes for H616 and T113-S3 which
> uses H616 as fallback compatible.

Can you say *why* we need this? IIUC Linux only ever uses one clock
source, and selects the (non-optional) Generic Timer (aka arch timer)
for that? So can you say what this hstimer clock source adds? I guess
higher resolution, but what is your use case, so why would you need the
200 MHz? And does this offset the higher access cost of an MMIO
access, compared to the arch timer's sysreg based access? Also, IIUC,
people would need to manually select this as the clocksource, why and
when would they do so? (Given they even know about it in the first
place).
Also the hstimer hasn't been used since the A20, so nobody seemed to
have missed it meanwhile?

Cheers,
Andre

> 
> Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
> ---
> Michal Piekos (4):
>       dt-bindings: timer: allwinner,sun5i-a13-hstimer: add H616 and T113-S3
>       clocksource/drivers/sun5i: add H616 hstimer support
>       arm64: dts: allwinner: h616: add hstimer node
>       arm: dts: allwinner: t113s: add hstimer node
> 
>  .../timer/allwinner,sun5i-a13-hstimer.yaml         |  8 +++-
>  arch/arm/boot/dts/allwinner/sun8i-t113s.dtsi       | 12 +++++
>  arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi     |  9 ++++
>  drivers/clocksource/timer-sun5i.c                  | 56 +++++++++++++++++++---
>  4 files changed, 78 insertions(+), 7 deletions(-)
> ---
> base-commit: faeab166167f5787719eb8683661fd41a3bb1514
> change-id: 20260413-h616-t113s-hstimer-62939948f91c
> 
> Best regards,


^ permalink raw reply

* Re: [PATCH v2 3/4] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
From: Linus Walleij @ 2026-04-19 21:19 UTC (permalink / raw)
  To: Yu-Chun Lin [林祐君], Michael Walle
  Cc: Bartosz Golaszewski, linux-gpio@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-realtek-soc@lists.infradead.org,
	CY_Huang[黃鉦晏],
	Stanley Chang[昌育德],
	James Tai [戴志峰], robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, afaerber@suse.com,
	TY_Chang[張子逸]
In-Reply-To: <52bf9ce2b7754af8af69b0afee0d07b2@realtek.com>

Hi Yu-Chun,

On Fri, Apr 10, 2026 at 11:39 AM Yu-Chun Lin [林祐君]
<eleanor.lin@realtek.com> wrote:

> We did look into gpio-mmio and gpio-regmap, but they are not quite suitable for
> our platform due to the specific hardware design:
>
> 1. Per-GPIO Dedicated Registers: Unlike typical GPIO controllers that pack 32 pins
> into a single 32-bit register (1 bit per pin), our hardware uses a dedicated 32-bit
> register for each individual GPIO. This single register controls the
> input/output state, direction, and interrupt trigger type for that specific pin.

Isn't that attainable by:

- setting .ngpio_per_reg to 1 in struct gpio_regmap_config

- extend .reg_mask_xlate callback with an enum for each operation
  (need to change all users of the .reg_mask_xlate callback but
  who cares, they are not many):

e.g.

enum gpio_regmap_operation {
    GPIO_REGMAP_GET_OP,
    GPIO_REGMAP_SET_OP,
    GPIO_REGMAP_SET_WITH_CLEAR_OP,
    GPIO_REGMAP_GET_DIR_OP,
    GPIO_REGMAP_SET_DIR_OP,
};

 int (*reg_mask_xlate)(struct gpio_regmap *gpio,
                              enum_gpio_regmap_operation op,
                              unsigned int base,
                              unsigned int offset, unsigned int *reg,
                              unsigned int *mask);

This way .reg_mask_xlate() can hit different bits in the returned
*mask depending on operation and it will be find to pack all of
the bits into one 32bit register.

Added Michael Walle to the the thread, he will know if this is a
good idea.

> 2. Write-Enable (WREN) Mask Mechanism: Our hardware requires a specific Write-Enable
> mask to be written simultaneously when updating the register values.

Which is to just set bit 31.

With the above scheme your .reg_mask_xlate callback can just set bit 31
no matter what operating you're doing. Piece of cake.

> 3. Hardware Debounce: We also need to support hardware debounce settings per pin,
> which requires custom configuration via set_config mapped to these specific per-pin
> registers.

Just add a version of an optional .set_config() call to gpio-regmap.c
to handle this using .reg_mask_xlate() per above and add a new
GPIO_REGMAP_CONFIG_OP to the above enum, problem solved.

If it seems too hard I can write patch 1 & 2 adding this infrastructure
but I bet you can easily see what can be done with gpio-regmap.c
here provided Michael W approves the idea.

Yours,
Linus Walleij

^ permalink raw reply

* Re: [PATCH 1/4] dt-bindings: timer: allwinner,sun5i-a13-hstimer: add H616 and T113-S3
From: Andre Przywara @ 2026-04-19 21:21 UTC (permalink / raw)
  To: Michal Piekos
  Cc: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
	Maxime Ripard, linux-kernel, devicetree, linux-arm-kernel,
	linux-sunxi
In-Reply-To: <20260419-h616-t113s-hstimer-v1-1-1af74ebef7c5@mmpsystems.pl>

On Sun, 19 Apr 2026 14:46:07 +0200
Michal Piekos <michal.piekos@mmpsystems.pl> wrote:

> H616 is compatible with the existing sun5i binding, but
> require its own compatible string to differentiate register offsets.

Just a nit: if the register offsets are different, then it's not
compatible, not even with the binding. So just say something like "they
are similar, but with different register offsets".

> T113-S3 uses same offsets as H616.

So it looks like (somewhat naturally) this is true for D1 as well? And
since that SoC was the first, we use "sun20i-d1" as the compatible
string prefix for this SoC's devices. I think we should follow suit
here and name that similarly.

> 
> Add allwinner,sun50i-h616-hstimer
> Add allwinner,sun8i-t113s-hstimer with fallback to
> allwinner,sun50i-h616-hstimer
> Extend schema condition for interrupts to cover H616 compatible variant.
> 
> Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
> ---
>  .../devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml    | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml
> index f1853daec2f9..bb60a85dc34b 100644
> --- a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml
> +++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml
> @@ -15,9 +15,13 @@ properties:
>      oneOf:
>        - const: allwinner,sun5i-a13-hstimer
>        - const: allwinner,sun7i-a20-hstimer
> +      - const: allwinner,sun50i-h616-hstimer
>        - items:
>            - const: allwinner,sun6i-a31-hstimer
>            - const: allwinner,sun7i-a20-hstimer
> +      - items:
> +          - const: allwinner,sun8i-t113s-hstimer
> +          - const: allwinner,sun50i-h616-hstimer
>  
>    reg:
>      maxItems: 1
> @@ -45,7 +49,9 @@ required:
>  if:
>    properties:
>      compatible:
> -      const: allwinner,sun5i-a13-hstimer
> +      enum:
> +        - allwinner,sun5i-a13-hstimer
> +        - allwinner,sun50i-h616-hstimer

IIUC this just matches the H616, but wouldn't match the T113/D1? And
there is some construct with "contains" to match for fallback
compatibles?

Cheers,
Andre
>  
>  then:
>    properties:
> 


^ permalink raw reply

* [PATCH v3 0/5] iio: magnetometer: add driver for QST QMC5883P
From: Hardik Phalet @ 2026-04-19 22:32 UTC (permalink / raw)
  To: gregkh, jic23
  Cc: andy, conor+dt, devicetree, dlechner, krzk+dt, linux-iio,
	linux-kernel, linux-staging, me, nuno.sa, robh, skhan,
	Hardik Phalet, Hardik Phalet

This series adds an IIO driver for the QST QMC5883P, a 3-axis
anisotropic magneto-resistive (AMR) magnetometer with a 16-bit ADC,
communicating over I2C. To my knowledge there is no existing
upstream driver for this device (see "Prior-art register-map check"
below).

The driver supports:
  - Raw magnetic field readings on X, Y and Z axes
  - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G),
    selectable via IIO_CHAN_INFO_SCALE
  - Four output data rates (10, 50, 100, 200 Hz), selectable via
    IIO_CHAN_INFO_SAMP_FREQ
  - Four oversampling ratios (1, 2, 4, 8), selectable via
    IIO_CHAN_INFO_OVERSAMPLING_RATIO
  - Runtime PM with a 2 s autosuspend delay
  - System suspend/resume delegated to the runtime callbacks

Regmap with an rbtree cache is used throughout. CTRL_1 and CTRL_2
bit fields are accessed via regmap_field to avoid read-modify-write
races. The STATUS register is marked precious so regmap never reads
it speculatively and clears the DRDY/OVFL bits unexpectedly.

The probe-time init sequence is: soft reset, wait 300 us for POR
to complete, deassert reset, drop the register cache so subsequent
RMW writes read fresh values, then enter normal mode. 300 us
comfortably covers the 250 us POR time given in the datasheet.

Patches:
  1/5 - dt-bindings: vendor-prefixes: Add QST Corporation
  2/5 - dt-bindings: iio: magnetometer: QSTCORP QMC5883P
  3/5 - iio: magnetometer: add driver for QST QMC5883P
  4/5 - iio: magnetometer: qmc5883p: add oversampling ratio support
  5/5 - iio: magnetometer: qmc5883p: add PM support

Patches 4 and 5 are split out from the main driver so that the core
(1-3) can be reviewed and picked independently, per review feedback
on v2. 4/5 exposes the CTRL_1 OSR field via
IIO_CHAN_INFO_OVERSAMPLING_RATIO. 5/5 adds runtime PM that puts the
chip into MODE_SUSPEND when idle and wakes it to MODE_NORMAL on
demand.

Changes in v3
=============
Addressing review feedback on v2:

  - Moved the driver out of staging and into drivers/iio/magnetometer/
    (Greg Kroah-Hartman).

  - Changed the vendor prefix from "qst" to "qstcorp" to match the
    manufacturer's domain (qstcorp.com) (Krzysztof Kozlowski).

  - Subject of the binding patch no longer says "Add binding for";
    "dt-bindings:" already conveys that (Krzysztof Kozlowski).

  - Dropped the redundant last sentence of the binding commit message
    (Krzysztof Kozlowski).

  - VDD supply is now made required (Krzysztof Kozlowski).

  - Split runtime PM + system sleep handling out of the core driver
    patch into its own patch (5/5), so the core driver can be reviewed
    independently (David Lechner).

  - Split oversampling-ratio support out into its own patch (4/5)
    (David Lechner).

  - Dropped the custom downsampling_ratio sysfs attribute entirely.
    The datasheet describes OSR2 only as "another filter ... depth can
    be adjusted through OSR2", with no further characterisation, and
    no application note clarifying it. Without a precise definition
    of what the filter actually does it is not possible to map OSR2
    to any existing IIO ABI, so support for it is dropped from this
    series (David Lechner).

  - qmc5883p_verify_chip_id() -> qmc5883p_read_chip_id() no longer
    treats an ID mismatch as a probe failure; the chip-ID check is
    informational only (David Lechner).

  - qmc5883p_chip_init() no longer programs driver-chosen defaults
    for RNG/OSR/DSR/ODR. The hardware defaults are sufficient and the
    explicit writes were a development artifact (David Lechner).

  - Post-reset delay in qmc5883p_chip_init() uses fsleep() with a
    comment citing the 250 us POR time from the datasheet
    (David Lechner).

  - Timeout in regmap_read_poll_timeout() written as
    150 * (MICRO / MILLI) instead of 150000 (David Lechner).

  - Channel spec duplication collapsed behind a QMC5883P_CHAN(ch)
    macro (David Lechner).

  - qmc5883p_rf_init() moved up in probe, before the regulator and
    chip-ID reads, so the regmap fields are available by the time
    they are needed (David Lechner).

  - Trailing comma and extra whitespace in the of_device_id and
    i2c_device_id sentinel entries cleaned up (David Lechner).

  - Verified that there is no existing driver in drivers/iio/,
    drivers/hwmon/, drivers/input/, drivers/staging/iio/ or
    drivers/misc/ that matches the QMC5883P register map. Summary
    of candidates inspected is included in the "Testing" section
    below (Andy Shevchenko).

  - Waited ~10 days before sending v3 to allow time for review
    (Andy Shevchenko).

Additional v3 changes not directly from review:

  - Scale encoding changed from IIO_VAL_FRACTIONAL to
    IIO_VAL_INT_PLUS_NANO with a matching write_raw_get_fmt(),
    because the IIO core defaults sysfs writes to
    IIO_VAL_INT_PLUS_MICRO and was silently truncating nano-precision
    writes. The truncation on the 8 G and 2 G entries is documented
    in a comment above the scale table.

  - STATUS register marked precious (in addition to volatile) so
    regmap never reads it speculatively and clears DRDY/OVFL.

  - Added regcache_drop_region() after the soft-reset deassert, so
    subsequent RMW writes read fresh values rather than cached
    pre-reset values.

Changes in v2
=============
  - Use get_unaligned_le16() from <linux/unaligned.h> instead of
    manual byte-shifting for deserialising axis data (review feedback).
  - Fix pm_runtime_* calls in downsampling_ratio_store() to use
    data->dev (the i2c parent device) instead of dev (the iio
    device), avoiding PM refcount imbalances (review feedback).
  - Replace manual pm_runtime_disable() devm action with
    devm_pm_runtime_enable(), which avoids a kcfi-violating function
    pointer cast (review feedback).
  - Move chip suspend into a devm action (qmc5883p_suspend_action)
    registered before devm_iio_device_register() so that devres LIFO
    ordering guarantees the IIO interface is fully unregistered
    before the hardware is put to sleep, closing a race window on
    removal (review feedback).
  - Drop qmc5883p_remove() and the .remove hook entirely, as the
    above devm action subsumes it (review feedback).
  - Remove the empty qmc5883p_runtime_idle() stub; passing NULL in
    RUNTIME_PM_OPS already provides the correct default behaviour.
  - Add regulator support: use devm_regulator_get_enable_optional()
    for the vdd-supply documented in the dt-binding, with a 50 ms
    post-enable delay per datasheet section 5.3 (PSUP ramp + POR
    time) (review feedback).
  - Reinitialise the chip in qmc5883p_system_resume() via
    qmc5883p_chip_init() followed by regcache_mark_dirty() +
    regcache_sync(), so that the driver recovers correctly if the
    regulator was physically cut during system suspend and POR
    reset all registers (review feedback).

Links
=====
  v1: https://lore.kernel.org/all/20260409162308.2590385-1-hardik.phalet@pm.me/
  v2: https://lore.kernel.org/all/20260409210639.3197576-1-hardik.phalet@pm.me/

Testing
=======
Hardware
  A GY-271 HM-246 breakout (this board is a QMC5883P, not a QMC5883L,
  despite what some vendors put on the silkscreen), connected over
  I2C bus 1 to a Raspberry Pi 4B running a mainline aarch64 kernel.
  The chip enumerates at address 0x2C via i2cdetect, and CHIP_ID
  (register 0x00) reads back 0x80 as expected.

Prior-art register-map check (for Andy)
  I grepped drivers/iio/magnetometer/, drivers/hwmon/,
  drivers/input/misc/, drivers/staging/iio/ and drivers/misc/ for
  the distinctive offsets 0x09 (STATUS) and 0x0A (CTRL_1), narrowed
  to files containing both, and manually compared each candidate's
  register layout and control-bit encoding against the QMC5883P.

  Closest candidates:
    ak8975.c    - four register offsets coincide (0x00, 0x09, 0x0A,
                  0x0B) but the data registers sit at 0x03-0x08
                  (shifted +2 vs QMC5883P's 0x01-0x06), DRDY is in
                  ST1 at 0x02 rather than STATUS at 0x09, and CNTL
                  encodes a 4-bit mode only - no packed ODR/OSR/range
                  fields.
    hmc5843.c   - STATUS matches at 0x09, but 0x0A is a read-only ID
                  register, configuration spans 0x00-0x02 rather than
                  a single CTRL_1 byte, and data is MSB-first at 0x03
                  in X/Z/Y order.
    af8133j.c   - 0x0A and 0x0B carry mode and range, but STATUS is
                  at 0x02, data starts at 0x03, and the mode field is
                  2-valued (standby/work) rather than 4-valued.
    mmc35240.c  - data at 0x00-0x05 overlaps, but STATUS and control
                  land at 0x06-0x08.

  No overlap worth discussing: mmc5633, mag3110, tlv493d, tmag5273,
  bmc150_magn, rm3100, yamaha-yas530, st_magn, si7210, als31300. No
  magnetometer driver under drivers/hwmon/, drivers/input/misc/ or
  drivers/staging/.

  Conclusion: no existing driver can be extended to cover the
  QMC5883P without restructuring its register addressing and
  control-bit model. A new driver is warranted.

Functional testing on v3
  - Chip ID read: 0x80 (matches datasheet).
  - Raw axis reads: in_magn_{x,y,z}_raw return stable s16 values
    and track manual reorientation of the board.
  - Scale: all four ranges (+/-2/8/12/30 G) selectable via
    in_magn_scale; in_magn_scale_available lists all four; sysfs
    write-back round-trips cleanly at nano precision.
  - Sampling frequency: 10/50/100/200 Hz all selectable via
    in_magn_sampling_frequency; _available lists all four.
  - Oversampling ratio (patch 4): 1/2/4/8 selectable via
    in_magn_oversampling_ratio; _available lists all four.
  - DRDY polling: verified STATUS.DRDY asserts and clears on read,
    and that OVFL is captured in the same read as DRDY.
  - Soft reset: register state after qmc5883p_chip_init() matches
    the datasheet defaults; regcache_drop_region() confirmed by
    observing fresh values being read on the first post-reset RMW.
  - Runtime PM (patch 5): power/runtime_status transitions to
    "suspended" after the 2 s autosuspend delay (MODE_SUSPEND on
    the wire, verified by i2cdump); next sysfs read resumes the
    device and returns valid data.
  - System sleep: echo mem > /sys/power/state (s2idle on the Pi)
    followed by wake; readings are valid after resume.
  - Unbind: echo <dev> > /sys/bus/i2c/drivers/qmc5883p/unbind
    leaves the chip in MODE_SUSPEND, confirming the devm LIFO
    teardown order.
  - Build: CONFIG_QMC5883P=y and =m both clean; W=1 clean on
    aarch64; sparse clean; checkpatch --strict clean.
  - dt_binding_check: passes for patch 2/5.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
Hardik Phalet (5):
      dt-bindings: vendor-prefixes: Add QST Corporation
      dt-bindings: iio: magnetometer: QSTCORP QMC5883P
      iio: magnetometer: add driver for QST QMC5883P
      iio: magnetometer: qmc5883p: add oversampling ratio support
      iio: magnetometer: qmc5883p: add PM support

 .../iio/magnetometer/qstcorp,qmc5883p.yaml         |  48 ++
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 MAINTAINERS                                        |   7 +
 drivers/iio/magnetometer/Kconfig                   |  11 +
 drivers/iio/magnetometer/Makefile                  |   2 +
 drivers/iio/magnetometer/qmc5883p.c                | 673 +++++++++++++++++++++
 6 files changed, 743 insertions(+)
---
base-commit: d2a4ec19d2a2e54c23b5180e939994d3da4a6b91
change-id: 20260418-qmc5883p-driver-dcc74bd4a789

Best regards,
--  
Hardik Phalet <hardik.phalet@pm.me>


^ permalink raw reply

* [PATCH v3 1/5] dt-bindings: vendor-prefixes: Add QST Corporation
From: Hardik Phalet @ 2026-04-19 22:32 UTC (permalink / raw)
  To: gregkh, jic23
  Cc: andy, conor+dt, devicetree, dlechner, krzk+dt, linux-iio,
	linux-kernel, linux-staging, me, nuno.sa, robh, skhan,
	Hardik Phalet, Hardik Phalet
In-Reply-To: <20260420-qmc5883p-driver-v3-0-da1e97088f8b@pm.me>

Add the vendor prefix 'qstcorp' for QST Corporation, a manufacturer of
MEMS sensors.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ee7fd3cfe203..4ecf438f1a4a 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1337,6 +1337,8 @@ patternProperties:
     description: Shenzhen QiShenglong Industrialist Co., Ltd.
   "^qnap,.*":
     description: QNAP Systems, Inc.
+  "^qstcorp,.*":
+    description: QST Corporation
   "^quanta,.*":
     description: Quanta Computer Inc.
   "^radxa,.*":

-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 2/5] dt-bindings: iio: magnetometer: QSTCORP QMC5883P
From: Hardik Phalet @ 2026-04-19 22:32 UTC (permalink / raw)
  To: gregkh, jic23
  Cc: andy, conor+dt, devicetree, dlechner, krzk+dt, linux-iio,
	linux-kernel, linux-staging, me, nuno.sa, robh, skhan,
	Hardik Phalet, Hardik Phalet
In-Reply-To: <20260420-qmc5883p-driver-v3-0-da1e97088f8b@pm.me>

Add the device tree binding document for the QST QMC5883P, a 3-axis
anisotropic magneto-resistive (AMR) sensor with a 16-bit ADC that
communicates over I2C.

Add a MAINTAINERS entry for the QSTCORP QMC5883P devicetree binding.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
 .../iio/magnetometer/qstcorp,qmc5883p.yaml         | 48 ++++++++++++++++++++++
 MAINTAINERS                                        |  6 +++
 2 files changed, 54 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883p.yaml b/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883p.yaml
new file mode 100644
index 000000000000..72cc3fef2226
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883p.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/magnetometer/qstcorp,qmc5883p.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: QSTCORP QMC5883P 3-axis magnetometer
+
+maintainers:
+  - Hardik Phalet <hardik.phalet@pm.me>
+
+description:
+  The QMC5883P is a 3-axis anisotropic magneto-resistive (AMR) sensor with a
+  16-bit ADC. It communicates over I2C (standard and fast modes) and is
+  targeted at compass, navigation, and industrial applications.
+
+properties:
+  compatible:
+    const: qstcorp,qmc5883p
+
+  reg:
+    maxItems: 1
+    description: I2C address of the device; the default address is 0x2c
+
+  vdd-supply:
+    description:
+      VDD power supply (2.5 V to 3.6 V). Powers all internal analog and
+      digital functional blocks.
+
+required:
+  - compatible
+  - reg
+  - vdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        magnetometer@2c {
+            compatible = "qstcorp,qmc5883p";
+            reg = <0x2c>;
+            vdd-supply = <&vdd_3v3>;
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 48fda1f8332e..d41f6b33d0e5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21554,6 +21554,12 @@ F:	Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
 F:	drivers/bus/fsl-mc/
 F:	include/uapi/linux/fsl_mc.h
 
+QSTCORP QMC5883P MAGNETOMETER DRIVER
+M:	Hardik Phalet <hardik.phalet@pm.me>
+L:	linux-iio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883p.yaml
+
 QT1010 MEDIA DRIVER
 L:	linux-media@vger.kernel.org
 S:	Orphan

-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 3/5] iio: magnetometer: add driver for QST QMC5883P
From: Hardik Phalet @ 2026-04-19 22:32 UTC (permalink / raw)
  To: gregkh, jic23
  Cc: andy, conor+dt, devicetree, dlechner, krzk+dt, linux-iio,
	linux-kernel, linux-staging, me, nuno.sa, robh, skhan,
	Hardik Phalet, Hardik Phalet
In-Reply-To: <20260420-qmc5883p-driver-v3-0-da1e97088f8b@pm.me>

Add an IIO driver for the QST QMC5883P, a 3-axis anisotropic
magneto-resistive (AMR) magnetometer with a 16-bit ADC, communicating
over I2C. There is no existing upstream driver for this device.

The driver supports:
 - Raw magnetic field readings on X, Y and Z axes
 - Four full-scale ranges (+/-2 G, +/-8 G, +/-12 G, +/-30 G) selectable
   via IIO_CHAN_INFO_SCALE
 - Output data rate configurable via IIO_CHAN_INFO_SAMP_FREQ (10, 50,
   100, 200 Hz)
 - vdd-supply regulator management

Regmap with an rbtree cache is used throughout. CTRL_1 and CTRL_2 bit
fields are accessed via regmap_field to avoid read-modify-write races.
The STATUS register is marked precious so regmap never reads it
speculatively and clears the DRDY/OVFL bits unexpectedly.

The probe-time init sequence is: soft reset, wait 300 us for POR
completion, deassert reset, then drop the register cache so subsequent
RMW writes read fresh values from the device. After reset the chip is in
MODE_SUSPEND per datasheet §6.2.4, and is left there; the first
userspace access will wake it via runtime PM (added in a follow-up
patch).

Cleanup is fully devm-managed via devm_regulator_get_enable() and
devm_iio_device_register().

Oversampling ratio and runtime PM are added in follow-up patches.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
 MAINTAINERS                         |   1 +
 drivers/iio/magnetometer/Kconfig    |  11 +
 drivers/iio/magnetometer/Makefile   |   2 +
 drivers/iio/magnetometer/qmc5883p.c | 574 ++++++++++++++++++++++++++++++++++++
 4 files changed, 588 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d41f6b33d0e5..2fbbe8831a7c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21559,6 +21559,7 @@ M:	Hardik Phalet <hardik.phalet@pm.me>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/iio/magnetometer/qstcorp,qmc5883p.yaml
+F:	drivers/iio/magnetometer/qmc5883p.c
 
 QT1010 MEDIA DRIVER
 L:	linux-media@vger.kernel.org
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index fb313e591e85..333c5e6f231d 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -298,4 +298,15 @@ config YAMAHA_YAS530
 	  To compile this driver as a module, choose M here: the module
 	  will be called yamaha-yas.
 
+config QMC5883P
+	tristate "QMC5883P 3-Axis Magnetometer"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Say yes here to build support for QMC5883P I2C-based
+	  3-axis magnetometer chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qmc5883p.
+
 endmenu
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 5bd227f8c120..ff519a055d77 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -39,3 +39,5 @@ obj-$(CONFIG_SI7210)			+= si7210.o
 obj-$(CONFIG_TI_TMAG5273)		+= tmag5273.o
 
 obj-$(CONFIG_YAMAHA_YAS530)		+= yamaha-yas530.o
+
+obj-$(CONFIG_QMC5883P) += qmc5883p.o
diff --git a/drivers/iio/magnetometer/qmc5883p.c b/drivers/iio/magnetometer/qmc5883p.c
new file mode 100644
index 000000000000..e4a76ae7c2cf
--- /dev/null
+++ b/drivers/iio/magnetometer/qmc5883p.c
@@ -0,0 +1,574 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * qmc5883p.c - QMC5883P magnetometer driver
+ *
+ * Copyright 2026 Hardik Phalet <hardik.phalet@pm.me>
+ *
+ * TODO: add triggered buffer support, PM, OSR, DSR
+ *
+ */
+
+#include <linux/array_size.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+#include <linux/unaligned.h>
+
+/*
+ * Register definition
+ */
+#define QMC5883P_REG_CHIP_ID 0x00
+#define QMC5883P_REG_X_LSB 0x01
+#define QMC5883P_REG_X_MSB 0x02
+#define QMC5883P_REG_Y_LSB 0x03
+#define QMC5883P_REG_Y_MSB 0x04
+#define QMC5883P_REG_Z_LSB 0x05
+#define QMC5883P_REG_Z_MSB 0x06
+#define QMC5883P_REG_STATUS 0x09
+#define QMC5883P_REG_CTRL_1 0x0A
+#define QMC5883P_REG_CTRL_2 0x0B
+
+/*
+ * Value definition
+ */
+#define QMC5883P_MODE_SUSPEND 0x00
+#define QMC5883P_MODE_NORMAL 0x01
+#define QMC5883P_MODE_SINGLE 0x02
+#define QMC5883P_MODE_CONTINUOUS 0x03
+
+/*
+ * Output data rate
+ */
+#define QMC5883P_ODR_10 0x00
+#define QMC5883P_ODR_50 0x01
+#define QMC5883P_ODR_100 0x02
+#define QMC5883P_ODR_200 0x03
+
+/*
+ * Oversampling rate
+ */
+#define QMC5883P_OSR_8 0x00
+#define QMC5883P_OSR_4 0x01
+#define QMC5883P_OSR_2 0x02
+#define QMC5883P_OSR_1 0x03
+
+#define QMC5883P_RNG_30G 0x00
+#define QMC5883P_RNG_12G 0x01
+#define QMC5883P_RNG_08G 0x02
+#define QMC5883P_RNG_02G 0x03
+
+#define QMC5883P_DRDY_POLL_US 1000
+
+#define QMC5883P_CHIP_ID 0x80
+
+#define QMC5883P_STATUS_DRDY BIT(0)
+#define QMC5883P_STATUS_OVFL BIT(1)
+
+struct qmc5883p_rf {
+	struct regmap_field *osr;
+	struct regmap_field *odr;
+	struct regmap_field *mode;
+	struct regmap_field *rng;
+	struct regmap_field *sftrst;
+	struct regmap_field *chip_id;
+};
+
+struct qmc5883p_data {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex mutex; /* protects regmap and rf field accesses */
+	struct qmc5883p_rf rf;
+};
+
+enum qmc5883p_channels {
+	AXIS_X = 0,
+	AXIS_Y,
+	AXIS_Z,
+};
+
+/*
+ * Scale factors in nT/LSB for IIO_VAL_INT_PLUS_NANO, derived from datasheet
+ * Table 2 sensitivities (LSB/G) converted to LSB/T (1 G = 1e-4 T):
+ *   sensitivity_T = sensitivity_G * 10000
+ *   scale_nT     = 1e9 / sensitivity_T
+ *
+ * The 8G and 2G entries truncate 26.666... and 6.666... nT/LSB respectively;
+ * IIO_VAL_INT_PLUS_NANO cannot carry the exact rationals, but the chosen
+ * values match what IIO_VAL_FRACTIONAL would have rendered and therefore
+ * round-trip cleanly through sysfs write back.
+ *
+ * Index matches register value: RNG<1:0> = 0b00..0b11
+ */
+static const int qmc5883p_scale[][2] = {
+	[QMC5883P_RNG_30G] = { 0, 100 },
+	[QMC5883P_RNG_12G] = { 0, 40 },
+	[QMC5883P_RNG_08G] = { 0, 26 },
+	[QMC5883P_RNG_02G] = { 0, 6 },
+};
+
+static const int qmc5883p_odr[] = {
+	[QMC5883P_ODR_10] = 10,
+	[QMC5883P_ODR_50] = 50,
+	[QMC5883P_ODR_100] = 100,
+	[QMC5883P_ODR_200] = 200,
+};
+
+static const struct regmap_range qmc5883p_readable_ranges[] = {
+	regmap_reg_range(QMC5883P_REG_CHIP_ID, QMC5883P_REG_Z_MSB),
+	regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_CTRL_2),
+};
+
+static const struct regmap_range qmc5883p_writable_ranges[] = {
+	regmap_reg_range(QMC5883P_REG_CTRL_1, QMC5883P_REG_CTRL_2),
+};
+
+/*
+ * Volatile registers: hardware updates these independently of the driver.
+ * regmap will never serve these from cache.
+ */
+static const struct regmap_range qmc5883p_volatile_ranges[] = {
+	regmap_reg_range(QMC5883P_REG_X_LSB, QMC5883P_REG_Z_MSB),
+	regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS),
+	regmap_reg_range(QMC5883P_REG_CTRL_2, QMC5883P_REG_CTRL_2),
+};
+
+/*
+ * Precious registers: reading has a side effect (clears DRDY/OVFL bits).
+ * regmap will never read these speculatively.
+ */
+static const struct regmap_range qmc5883p_precious_ranges[] = {
+	regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_STATUS),
+};
+
+static const struct regmap_access_table qmc5883p_readable_table = {
+	.yes_ranges = qmc5883p_readable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(qmc5883p_readable_ranges),
+};
+
+static const struct regmap_access_table qmc5883p_writable_table = {
+	.yes_ranges = qmc5883p_writable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(qmc5883p_writable_ranges),
+};
+
+static const struct regmap_access_table qmc5883p_volatile_table = {
+	.yes_ranges = qmc5883p_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(qmc5883p_volatile_ranges),
+};
+
+static const struct regmap_access_table qmc5883p_precious_table = {
+	.yes_ranges = qmc5883p_precious_ranges,
+	.n_yes_ranges = ARRAY_SIZE(qmc5883p_precious_ranges),
+};
+
+static const struct regmap_config qmc5883p_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x0B,
+	.cache_type = REGCACHE_RBTREE,
+	.rd_table = &qmc5883p_readable_table,
+	.wr_table = &qmc5883p_writable_table,
+	.volatile_table = &qmc5883p_volatile_table,
+	.precious_table = &qmc5883p_precious_table,
+};
+
+static const struct reg_field qmc5883p_rf_osr =
+	REG_FIELD(QMC5883P_REG_CTRL_1, 4, 5);
+static const struct reg_field qmc5883p_rf_odr =
+	REG_FIELD(QMC5883P_REG_CTRL_1, 2, 3);
+static const struct reg_field qmc5883p_rf_mode =
+	REG_FIELD(QMC5883P_REG_CTRL_1, 0, 1);
+static const struct reg_field qmc5883p_rf_rng =
+	REG_FIELD(QMC5883P_REG_CTRL_2, 2, 3);
+static const struct reg_field qmc5883p_rf_sftrst =
+	REG_FIELD(QMC5883P_REG_CTRL_2, 7, 7);
+static const struct reg_field qmc5883p_rf_chip_id =
+	REG_FIELD(QMC5883P_REG_CHIP_ID, 0, 7);
+
+/*
+ * qmc5883p_get_measure - read all three axes.
+ * Must be called with data->mutex held.
+ */
+static int qmc5883p_get_measure(struct qmc5883p_data *data, s16 *x, s16 *y,
+				s16 *z)
+{
+	int ret;
+	u8 reg_data[6];
+	unsigned int status;
+
+	/*
+	 * Poll the status register until DRDY is set or timeout.
+	 * Read the whole register in one shot so that OVFL is captured from
+	 * the same read: reading 0x09 clears both DRDY and OVFL, so a second
+	 * read would always see OVFL=0.
+	 * At ODR=10Hz one period is 100ms; use 150ms as a safe upper bound.
+	 */
+	ret = regmap_read_poll_timeout(data->regmap, QMC5883P_REG_STATUS,
+				       status, status & QMC5883P_STATUS_DRDY,
+				       QMC5883P_DRDY_POLL_US,
+				       150 * (MICRO / MILLI));
+	if (ret)
+		return ret;
+
+	if (status & QMC5883P_STATUS_OVFL) {
+		dev_warn_ratelimited(data->dev,
+			"data overflow, consider reducing field range\n");
+		ret = -ERANGE;
+		return ret;
+	}
+
+	ret = regmap_bulk_read(data->regmap, QMC5883P_REG_X_LSB, reg_data,
+			       ARRAY_SIZE(reg_data));
+	if (ret)
+		return ret;
+
+	*x = (s16)get_unaligned_le16(&reg_data[0]);
+	*y = (s16)get_unaligned_le16(&reg_data[2]);
+	*z = (s16)get_unaligned_le16(&reg_data[4]);
+
+	return ret;
+}
+
+static int qmc5883p_read_raw(struct iio_dev *indio_dev,
+			     const struct iio_chan_spec *chan, int *val,
+			     int *val2, long mask)
+{
+	s16 x, y, z;
+	struct qmc5883p_data *data = iio_priv(indio_dev);
+	int ret;
+	unsigned int regval;
+
+	guard(mutex)(&data->mutex);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = qmc5883p_get_measure(data, &x, &y, &z);
+		if (ret < 0)
+			return ret;
+		switch (chan->address) {
+		case AXIS_X:
+			*val = x;
+			break;
+		case AXIS_Y:
+			*val = y;
+			break;
+		case AXIS_Z:
+			*val = z;
+			break;
+		}
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = regmap_field_read(data->rf.rng, &regval);
+		if (ret < 0)
+			return ret;
+		*val = qmc5883p_scale[regval][0];
+		*val2 = qmc5883p_scale[regval][1];
+		return IIO_VAL_INT_PLUS_NANO;
+
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = regmap_field_read(data->rf.odr, &regval);
+		if (ret < 0)
+			return ret;
+		*val = qmc5883p_odr[regval];
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static int qmc5883p_write_scale(struct qmc5883p_data *data, int val, int val2)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(qmc5883p_scale); i++) {
+		if (qmc5883p_scale[i][0] == val && qmc5883p_scale[i][1] == val2)
+			return regmap_field_write(data->rf.rng, i);
+	}
+
+	return -EINVAL;
+}
+
+static int qmc5883p_write_odr(struct qmc5883p_data *data, int val)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(qmc5883p_odr); i++) {
+		if (qmc5883p_odr[i] == val)
+			return regmap_field_write(data->rf.odr, i);
+	}
+
+	return -EINVAL;
+}
+
+static int qmc5883p_write_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan, int val,
+			      int val2, long mask)
+{
+	struct qmc5883p_data *data = iio_priv(indio_dev);
+	int ret, restore;
+
+	guard(mutex)(&data->mutex);
+
+	ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+	if (ret)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = qmc5883p_write_odr(data, val);
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		ret = qmc5883p_write_scale(data, val, val2);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	restore = regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
+	if (restore && !ret)
+		ret = restore;
+
+	return ret;
+}
+
+/*
+ * qmc5883p_read_avail - expose available values to userspace.
+ *
+ * Creates the _available sysfs attributes automatically:
+ *   in_magn_sampling_frequency_available
+ *   in_magn_scale_available
+ */
+static int qmc5883p_read_avail(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       const int **vals, int *type, int *length,
+			       long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = qmc5883p_odr;
+		*type = IIO_VAL_INT;
+		*length = ARRAY_SIZE(qmc5883p_odr);
+		return IIO_AVAIL_LIST;
+
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)qmc5883p_scale;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(qmc5883p_scale) * 2;
+		return IIO_AVAIL_LIST;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * Tell the IIO core how to parse sysfs writes. Without this, the core
+ * defaults to IIO_VAL_INT_PLUS_MICRO (6 fractional digits), which would
+ * silently truncate nano-scale writes like "0.000000040" to 0.
+ */
+static int qmc5883p_write_raw_get_fmt(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan,
+				      long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info qmc5883p_info = {
+	.read_raw = qmc5883p_read_raw,
+	.write_raw = qmc5883p_write_raw,
+	.write_raw_get_fmt = qmc5883p_write_raw_get_fmt,
+	.read_avail = qmc5883p_read_avail,
+};
+
+static int qmc5883p_rf_init(struct qmc5883p_data *data)
+{
+	struct regmap *regmap = data->regmap;
+	struct device *dev = data->dev;
+	struct qmc5883p_rf *rf = &data->rf;
+
+	rf->osr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_osr);
+	if (IS_ERR(rf->osr))
+		return PTR_ERR(rf->osr);
+
+	rf->odr = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_odr);
+	if (IS_ERR(rf->odr))
+		return PTR_ERR(rf->odr);
+
+	rf->mode = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_mode);
+	if (IS_ERR(rf->mode))
+		return PTR_ERR(rf->mode);
+
+	rf->rng = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_rng);
+	if (IS_ERR(rf->rng))
+		return PTR_ERR(rf->rng);
+
+	rf->sftrst = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_sftrst);
+	if (IS_ERR(rf->sftrst))
+		return PTR_ERR(rf->sftrst);
+
+	rf->chip_id = devm_regmap_field_alloc(dev, regmap, qmc5883p_rf_chip_id);
+	if (IS_ERR(rf->chip_id))
+		return PTR_ERR(rf->chip_id);
+
+	return 0;
+}
+
+static int qmc5883p_read_chip_id(struct qmc5883p_data *data)
+{
+	int ret, regval;
+
+	ret = regmap_field_read(data->rf.chip_id, &regval);
+	if (ret)
+		return dev_err_probe(data->dev, ret,
+				     "failed to read chip ID\n");
+
+	if (regval != QMC5883P_CHIP_ID)
+		dev_info(data->dev, "unexpected chip ID %#x, expected %#x\n",
+			regval, QMC5883P_CHIP_ID);
+
+	return 0;
+}
+
+#define QMC5883P_CHAN(ch)                                                 \
+	{                                                                 \
+		.type = IIO_MAGN,                                         \
+		.channel2 = IIO_MOD_##ch,                                 \
+		.modified = 1,                                            \
+		.address = AXIS_##ch,                                     \
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |            \
+				      BIT(IIO_CHAN_INFO_SCALE),           \
+		.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), \
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+		.info_mask_shared_by_type_available =                     \
+			BIT(IIO_CHAN_INFO_SAMP_FREQ),                     \
+	}
+
+static const struct iio_chan_spec qmc5883p_channels[] = {
+	QMC5883P_CHAN(X),
+	QMC5883P_CHAN(Y),
+	QMC5883P_CHAN(Z),
+};
+
+static int qmc5883p_chip_init(struct qmc5883p_data *data)
+{
+	int ret;
+
+	ret = regmap_field_write(data->rf.sftrst, 1);
+	if (ret)
+		return ret;
+
+	/*
+	 * The datasheet does not specify a post-reset delay, but POR
+	 * completion takes up to 250 microseconds. Use 300 microseconds
+	 * to be safe.
+	 */
+	fsleep(300);
+
+	ret = regmap_field_write(data->rf.sftrst, 0);
+	if (ret)
+		return ret;
+
+	/*
+	 * Soft reset restored every register to its default. Drop the cache
+	 * so subsequent RMW writes read fresh values from the device.
+	 */
+	regcache_drop_region(data->regmap, QMC5883P_REG_CHIP_ID,
+			     QMC5883P_REG_CTRL_2);
+
+	/* Chip is now in MODE_SUSPEND per datasheet §6.2.4. Leave it there. */
+	return 0;
+}
+
+static int qmc5883p_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct qmc5883p_data *data;
+	struct iio_dev *indio_dev;
+	struct regmap *regmap;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	regmap = devm_regmap_init_i2c(client, &qmc5883p_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "regmap initialization failed\n");
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->dev = dev;
+	data->regmap = regmap;
+
+	mutex_init(&data->mutex);
+
+	ret = qmc5883p_rf_init(data);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to initialize regmap fields\n");
+
+	indio_dev->name = "qmc5883p";
+	indio_dev->info = &qmc5883p_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = qmc5883p_channels;
+	indio_dev->num_channels = ARRAY_SIZE(qmc5883p_channels);
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to initialize vdd regulator\n");
+
+	/* Datasheet specifies up to 50 ms supply ramp + 250 us POR time. */
+	fsleep(50 * (MICRO / MILLI) + 250);
+
+	ret = qmc5883p_read_chip_id(data);
+	if (ret)
+		return ret;
+
+	ret = qmc5883p_chip_init(data);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to initialize chip\n");
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id qmc5883p_of_match[] = {
+	{ .compatible = "qstcorp,qmc5883p" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, qmc5883p_of_match);
+
+static const struct i2c_device_id qmc5883p_id[] = {
+	{ "qmc5883p", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, qmc5883p_id);
+
+static struct i2c_driver qmc5883p_driver = {
+	.driver = {
+		.name = "qmc5883p",
+		.of_match_table = qmc5883p_of_match,
+	},
+	.probe = qmc5883p_probe,
+	.id_table = qmc5883p_id,
+};
+module_i2c_driver(qmc5883p_driver);
+
+MODULE_AUTHOR("Hardik Phalet <hardik.phalet@pm.me>");
+MODULE_DESCRIPTION("QST QMC5883P 3-axis magnetometer driver");
+MODULE_LICENSE("GPL");

-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 4/5] iio: magnetometer: qmc5883p: add oversampling ratio support
From: Hardik Phalet @ 2026-04-19 22:32 UTC (permalink / raw)
  To: gregkh, jic23
  Cc: andy, conor+dt, devicetree, dlechner, krzk+dt, linux-iio,
	linux-kernel, linux-staging, me, nuno.sa, robh, skhan,
	Hardik Phalet, Hardik Phalet
In-Reply-To: <20260420-qmc5883p-driver-v3-0-da1e97088f8b@pm.me>

Expose the CTRL_1 OSR field through IIO_CHAN_INFO_OVERSAMPLING_RATIO so
userspace can select among the four oversampling settings (1, 2, 4, 8)
supported by the device. Read, write and available handlers mirror the
existing SAMP_FREQ plumbing and use the already-present rf.osr regmap
field.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
 drivers/iio/magnetometer/qmc5883p.c | 46 ++++++++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/magnetometer/qmc5883p.c b/drivers/iio/magnetometer/qmc5883p.c
index e4a76ae7c2cf..d0e4a1a600b6 100644
--- a/drivers/iio/magnetometer/qmc5883p.c
+++ b/drivers/iio/magnetometer/qmc5883p.c
@@ -4,7 +4,7 @@
  *
  * Copyright 2026 Hardik Phalet <hardik.phalet@pm.me>
  *
- * TODO: add triggered buffer support, PM, OSR, DSR
+ * TODO: add triggered buffer support, PM, DSR
  *
  */
 
@@ -119,6 +119,13 @@ static const int qmc5883p_odr[] = {
 	[QMC5883P_ODR_200] = 200,
 };
 
+static const int qmc5883p_osr[] = {
+	[QMC5883P_OSR_1] = 1,
+	[QMC5883P_OSR_2] = 2,
+	[QMC5883P_OSR_4] = 4,
+	[QMC5883P_OSR_8] = 8,
+};
+
 static const struct regmap_range qmc5883p_readable_ranges[] = {
 	regmap_reg_range(QMC5883P_REG_CHIP_ID, QMC5883P_REG_Z_MSB),
 	regmap_reg_range(QMC5883P_REG_STATUS, QMC5883P_REG_CTRL_2),
@@ -277,6 +284,13 @@ static int qmc5883p_read_raw(struct iio_dev *indio_dev,
 			return ret;
 		*val = qmc5883p_odr[regval];
 		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		ret = regmap_field_read(data->rf.osr, &regval);
+		if (ret < 0)
+			return ret;
+		*val = qmc5883p_osr[regval];
+		return IIO_VAL_INT;
 	}
 
 	return -EINVAL;
@@ -306,6 +320,18 @@ static int qmc5883p_write_odr(struct qmc5883p_data *data, int val)
 	return -EINVAL;
 }
 
+static int qmc5883p_write_osr(struct qmc5883p_data *data, int val)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(qmc5883p_osr); i++) {
+		if (qmc5883p_osr[i] == val)
+			return regmap_field_write(data->rf.osr, i);
+	}
+
+	return -EINVAL;
+}
+
 static int qmc5883p_write_raw(struct iio_dev *indio_dev,
 			      struct iio_chan_spec const *chan, int val,
 			      int val2, long mask)
@@ -323,6 +349,9 @@ static int qmc5883p_write_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		ret = qmc5883p_write_odr(data, val);
 		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		ret = qmc5883p_write_osr(data, val);
+		break;
 	case IIO_CHAN_INFO_SCALE:
 		ret = qmc5883p_write_scale(data, val, val2);
 		break;
@@ -357,6 +386,12 @@ static int qmc5883p_read_avail(struct iio_dev *indio_dev,
 		*length = ARRAY_SIZE(qmc5883p_odr);
 		return IIO_AVAIL_LIST;
 
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		*vals = qmc5883p_osr;
+		*type = IIO_VAL_INT;
+		*length = ARRAY_SIZE(qmc5883p_osr);
+		return IIO_AVAIL_LIST;
+
 	case IIO_CHAN_INFO_SCALE:
 		*vals = (const int *)qmc5883p_scale;
 		*type = IIO_VAL_INT_PLUS_NANO;
@@ -382,6 +417,8 @@ static int qmc5883p_write_raw_get_fmt(struct iio_dev *indio_dev,
 		return IIO_VAL_INT_PLUS_NANO;
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		return IIO_VAL_INT;
 	default:
 		return -EINVAL;
 	}
@@ -452,9 +489,12 @@ static int qmc5883p_read_chip_id(struct qmc5883p_data *data)
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |            \
 				      BIT(IIO_CHAN_INFO_SCALE),           \
 		.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), \
-		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+		.info_mask_shared_by_type =                               \
+			BIT(IIO_CHAN_INFO_SAMP_FREQ) |                    \
+			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),            \
 		.info_mask_shared_by_type_available =                     \
-			BIT(IIO_CHAN_INFO_SAMP_FREQ),                     \
+			BIT(IIO_CHAN_INFO_SAMP_FREQ) |                    \
+			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),            \
 	}
 
 static const struct iio_chan_spec qmc5883p_channels[] = {

-- 
2.53.0


^ permalink raw reply related

* [PATCH v3 5/5] iio: magnetometer: qmc5883p: add PM support
From: Hardik Phalet @ 2026-04-19 22:33 UTC (permalink / raw)
  To: gregkh, jic23
  Cc: andy, conor+dt, devicetree, dlechner, krzk+dt, linux-iio,
	linux-kernel, linux-staging, me, nuno.sa, robh, skhan,
	Hardik Phalet, Hardik Phalet
In-Reply-To: <20260420-qmc5883p-driver-v3-0-da1e97088f8b@pm.me>

Add runtime PM with a 2 s autosuspend delay. Per datasheet §6.2.1
the chip continuously samples in MODE_NORMAL; putting it into
MODE_SUSPEND when idle drops current from up to 1180 uA to ~22 uA
(datasheet Table 2).

Wrap qmc5883p_get_measure() and qmc5883p_write_raw() with
pm_runtime_resume_and_get() / pm_runtime_put_autosuspend(), converting
early returns to a goto so the put is always paired.

System sleep is delegated to the runtime callbacks via
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume).

A devm action is registered before devm_pm_runtime_enable() so that
LIFO teardown on unbind runs pm_runtime_disable() first (freezing PM
state) and then suspends the hardware via MODE_SUSPEND.

Signed-off-by: Hardik Phalet <hardik.phalet@pm.me>
---
 drivers/iio/magnetometer/qmc5883p.c | 69 ++++++++++++++++++++++++++++++++++---
 1 file changed, 64 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/magnetometer/qmc5883p.c b/drivers/iio/magnetometer/qmc5883p.c
index d0e4a1a600b6..0ff635924abf 100644
--- a/drivers/iio/magnetometer/qmc5883p.c
+++ b/drivers/iio/magnetometer/qmc5883p.c
@@ -4,7 +4,7 @@
  *
  * Copyright 2026 Hardik Phalet <hardik.phalet@pm.me>
  *
- * TODO: add triggered buffer support, PM, DSR
+ * TODO: add triggered buffer support, DSR
  *
  */
 
@@ -15,6 +15,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/units.h>
@@ -208,6 +209,10 @@ static int qmc5883p_get_measure(struct qmc5883p_data *data, s16 *x, s16 *y,
 	u8 reg_data[6];
 	unsigned int status;
 
+	ret = pm_runtime_resume_and_get(data->dev);
+	if (ret < 0)
+		return ret;
+
 	/*
 	 * Poll the status register until DRDY is set or timeout.
 	 * Read the whole register in one shot so that OVFL is captured from
@@ -220,24 +225,26 @@ static int qmc5883p_get_measure(struct qmc5883p_data *data, s16 *x, s16 *y,
 				       QMC5883P_DRDY_POLL_US,
 				       150 * (MICRO / MILLI));
 	if (ret)
-		return ret;
+		goto out;
 
 	if (status & QMC5883P_STATUS_OVFL) {
 		dev_warn_ratelimited(data->dev,
 			"data overflow, consider reducing field range\n");
 		ret = -ERANGE;
-		return ret;
+		goto out;
 	}
 
 	ret = regmap_bulk_read(data->regmap, QMC5883P_REG_X_LSB, reg_data,
 			       ARRAY_SIZE(reg_data));
 	if (ret)
-		return ret;
+		goto out;
 
 	*x = (s16)get_unaligned_le16(&reg_data[0]);
 	*y = (s16)get_unaligned_le16(&reg_data[2]);
 	*z = (s16)get_unaligned_le16(&reg_data[4]);
 
+out:
+	pm_runtime_put_autosuspend(data->dev);
 	return ret;
 }
 
@@ -341,10 +348,14 @@ static int qmc5883p_write_raw(struct iio_dev *indio_dev,
 
 	guard(mutex)(&data->mutex);
 
-	ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+	ret = pm_runtime_resume_and_get(data->dev);
 	if (ret)
 		return ret;
 
+	ret = regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+	if (ret)
+		goto out;
+
 	switch (mask) {
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		ret = qmc5883p_write_odr(data, val);
@@ -364,6 +375,8 @@ static int qmc5883p_write_raw(struct iio_dev *indio_dev,
 	if (restore && !ret)
 		ret = restore;
 
+out:
+	pm_runtime_put_autosuspend(data->dev);
 	return ret;
 }
 
@@ -533,6 +546,18 @@ static int qmc5883p_chip_init(struct qmc5883p_data *data)
 	return 0;
 }
 
+static void qmc5883p_suspend_action(void *arg)
+{
+	struct qmc5883p_data *data = arg;
+
+	/*
+	 * PM is already disabled at this point (devm LIFO); put the hardware
+	 * into MODE_SUSPEND directly so the chip is not left sampling after
+	 * unbind.
+	 */
+	regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+}
+
 static int qmc5883p_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@@ -584,9 +609,42 @@ static int qmc5883p_probe(struct i2c_client *client)
 	if (ret)
 		return dev_err_probe(dev, ret, "failed to initialize chip\n");
 
+	ret = devm_add_action_or_reset(dev, qmc5883p_suspend_action, data);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(dev, 2000);
+	pm_runtime_use_autosuspend(dev);
+
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
 	return devm_iio_device_register(dev, indio_dev);
 }
 
+static int qmc5883p_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct qmc5883p_data *data = iio_priv(indio_dev);
+
+	return regmap_field_write(data->rf.mode, QMC5883P_MODE_SUSPEND);
+}
+
+static int qmc5883p_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct qmc5883p_data *data = iio_priv(indio_dev);
+
+	return regmap_field_write(data->rf.mode, QMC5883P_MODE_NORMAL);
+}
+
+static const struct dev_pm_ops qmc5883p_dev_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+		RUNTIME_PM_OPS(qmc5883p_runtime_suspend,
+			       qmc5883p_runtime_resume, NULL)
+};
+
 static const struct of_device_id qmc5883p_of_match[] = {
 	{ .compatible = "qstcorp,qmc5883p" },
 	{ }
@@ -603,6 +661,7 @@ static struct i2c_driver qmc5883p_driver = {
 	.driver = {
 		.name = "qmc5883p",
 		.of_match_table = qmc5883p_of_match,
+		.pm = pm_ptr(&qmc5883p_dev_pm_ops),
 	},
 	.probe = qmc5883p_probe,
 	.id_table = qmc5883p_id,

-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v4 1/4] arm64: dts: qcom: ipq9574: Add gpio details for eMMC
From: Alex G. @ 2026-04-19 22:38 UTC (permalink / raw)
  To: andersson, konradybcio, robh, krzk+dt, conor+dt, linux-arm-msm,
	devicetree, linux-kernel, Varadarajan Narayanan
  Cc: sumit.garg, dmitry.baryshkov, Varadarajan Narayanan,
	Konrad Dybcio
In-Reply-To: <20260202073322.259534-2-varadarajan.narayanan@oss.qualcomm.com>

On Monday, February 2, 2026 1:33:19 AM Central Daylight Time Varadarajan 
Narayanan wrote:

Hi Varadarajan,

> The RDP433 has NAND and eMMC variants. Presently, only NAND variant is
> supported. To enable support for eMMC variant, add the relevant GPIO
> related information.
> 
> Do not enable NAND by default here. Enable it in board specific DTS.
> 

This commit references sdc_default_state in the .dtsi file, without defining it. 
It creates a silent dependency on the board .dts, who must now define the pins. 
This makes no sense to me for boards that don't have eMMC. As an example, it 
breaks most downstream OpenWRT boards.

Was this new dependency accidental?

Alex

> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> Signed-off-by: Varadarajan Narayanan
> <varadarajan.narayanan@oss.qualcomm.com> ---
> v4: Move sdhc properties from emmc dts to SoC dtsi
> 
> v3: Disable nand in ipq9574-rdp-common.dtsi and enable it where required.
>     Add 'Reviewed-by: Konrad Dybcio'
> ---
>  .../boot/dts/qcom/ipq9574-rdp-common.dtsi     | 32 +++++++++++++++++++
>  arch/arm64/boot/dts/qcom/ipq9574.dtsi         |  9 ++++++
>  2 files changed, 41 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi
> b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi index
> bdb396afb992..e4ae79b2fcd9 100644
> --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi
> +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi
> @@ -169,6 +169,38 @@ data-pins {
>  			bias-disable;
>  		};
>  	};
> +
> +	sdc_default_state: sdc-default-state {
> +		clk-pins {
> +			pins = "gpio5";
> +			function = "sdc_clk";
> +			drive-strength = <8>;
> +			bias-disable;
> +		};
> +
> +		cmd-pins {
> +			pins = "gpio4";
> +			function = "sdc_cmd";
> +			drive-strength = <8>;
> +			bias-pull-up;
> +		};
> +
> +		data-pins {
> +			pins = "gpio0", "gpio1", "gpio2",
> +			       "gpio3", "gpio6", "gpio7",
> +			       "gpio8", "gpio9";
> +			function = "sdc_data";
> +			drive-strength = <8>;
> +			bias-pull-up;
> +		};
> +
> +		rclk-pins {
> +			pins = "gpio10";
> +			function = "sdc_rclk";
> +			drive-strength = <8>;
> +			bias-pull-down;
> +		};
> +	};
>  };
> 
>  &qpic_bam {
> diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi
> b/arch/arm64/boot/dts/qcom/ipq9574.dtsi index 86c9cb9fffc9..4b8c58982869
> 100644
> --- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi
> +++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi
> @@ -467,6 +467,15 @@ sdhc_1: mmc@7804000 {
>  			clock-names = "iface", "core", "xo", "ice";
>  			non-removable;
>  			supports-cqe;
> +			pinctrl-0 = <&sdc_default_state>;
> +			pinctrl-names = "default";
> +			mmc-ddr-1_8v;
> +			mmc-hs200-1_8v;
> +			mmc-hs400-1_8v;
> +			mmc-hs400-enhanced-strobe;
> +			max-frequency = <384000000>;
> +			bus-width = <8>;
> +
>  			status = "disabled";
>  		};





^ permalink raw reply

* Re: [PATCH 2/4] clocksource/drivers/sun5i: add H616 hstimer support
From: Andre Przywara @ 2026-04-19 22:39 UTC (permalink / raw)
  To: Michal Piekos
  Cc: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
	Maxime Ripard, linux-kernel, devicetree, linux-arm-kernel,
	linux-sunxi
In-Reply-To: <20260419-h616-t113s-hstimer-v1-2-1af74ebef7c5@mmpsystems.pl>

On Sun, 19 Apr 2026 14:46:08 +0200
Michal Piekos <michal.piekos@mmpsystems.pl> wrote:

Hi,

> H616 high speed timer differs from existing timer-sun5i by register base
> offset.
> 
> Add selectable register layout structures.
> Add H616 compatible string to OF match table.
> 
> Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
> ---
>  drivers/clocksource/timer-sun5i.c | 56 ++++++++++++++++++++++++++++++++++-----
>  1 file changed, 50 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c
> index f827d3f98f60..125abc11c3c3 100644
> --- a/drivers/clocksource/timer-sun5i.c
> +++ b/drivers/clocksource/timer-sun5i.c
> @@ -21,18 +21,52 @@
>  #define TIMER_IRQ_EN_REG		0x00
>  #define TIMER_IRQ_EN(val)			BIT(val)
>  #define TIMER_IRQ_ST_REG		0x04
> -#define TIMER_CTL_REG(val)		(0x20 * (val) + 0x10)
>  #define TIMER_CTL_ENABLE			BIT(0)
>  #define TIMER_CTL_RELOAD			BIT(1)
> -#define TIMER_CTL_CLK_PRES(val)			(((val) & 0x7) << 4)
>  #define TIMER_CTL_ONESHOT			BIT(7)
> -#define TIMER_INTVAL_LO_REG(val)	(0x20 * (val) + 0x14)
> -#define TIMER_INTVAL_HI_REG(val)	(0x20 * (val) + 0x18)
> -#define TIMER_CNTVAL_LO_REG(val)	(0x20 * (val) + 0x1c)
> -#define TIMER_CNTVAL_HI_REG(val)	(0x20 * (val) + 0x20)
> +#define TIMER_CTL_CLK_PRES(val)		(((val) & 0x7) << 4)
> +#define TIMER_CTL_REG(val)		\
> +	(soc_base->stride * (val) + soc_base->ctl_base)
> +#define TIMER_INTVAL_LO_REG(val)	\
> +	(soc_base->stride * (val) + soc_base->intval_lo_base)
> +#define TIMER_INTVAL_HI_REG(val)	\
> +	(soc_base->stride * (val) + soc_base->intval_hi_base)
> +#define TIMER_CNTVAL_LO_REG(val)	\
> +	(soc_base->stride * (val) + soc_base->cntval_lo_base)
> +#define TIMER_CNTVAL_HI_REG(val)	\
> +	(soc_base->stride * (val) + soc_base->cntval_hi_base)
>  
>  #define TIMER_SYNC_TICKS	3
>  
> +struct sunxi_timer_base {
> +	u32 ctl_base;
> +	u32 intval_lo_base;
> +	u32 intval_hi_base;
> +	u32 cntval_lo_base;
> +	u32 cntval_hi_base;
> +	u32 stride;
> +};
> +
> +static const struct sunxi_timer_base sun5i_base = {
> +	.ctl_base = 0x10,
> +	.intval_lo_base = 0x14,
> +	.intval_hi_base = 0x18,
> +	.cntval_lo_base = 0x1c,
> +	.cntval_hi_base = 0x20,

Mmmh, why all these members? Aren't those all the same, just offset by
0x10? So we just need a single value reg_offs, being either 0x0 or 0x10?

> +	.stride = 0x20

What it this about? It's the same stride for both versions, so why is
this a field?

> +};
> +
> +static const struct sunxi_timer_base sun50i_base = {
> +	.ctl_base = 0x20,
> +	.intval_lo_base = 0x24,
> +	.intval_hi_base = 0x28,
> +	.cntval_lo_base = 0x2c,
> +	.cntval_hi_base = 0x30,
> +	.stride = 0x20
> +};
> +
> +static const struct sunxi_timer_base *soc_base;

This doesn't look right. Differentiating between slightly different
hardware revision via the compatible string is a common pattern, look
at for instance drivers/media/rc/sunxi-cir.c and its usage of quirks for
an example how to handle this more nicely.

Cheers,
Andre

> +
>  struct sun5i_timer {
>  	void __iomem		*base;
>  	struct clk		*clk;
> @@ -238,6 +272,7 @@ static int sun5i_setup_clockevent(struct platform_device *pdev,
>  static int sun5i_timer_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> +	struct device_node *node = dev_of_node(&pdev->dev);
>  	struct sun5i_timer *st;
>  	struct reset_control *rstc;
>  	void __iomem *timer_base;
> @@ -251,6 +286,14 @@ static int sun5i_timer_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, st);
>  
> +	if (!node)
> +		return -EINVAL;
> +
> +	if (of_device_is_compatible(node, "allwinner,sun50i-h616-hstimer"))
> +		soc_base = &sun50i_base;
> +	else
> +		soc_base = &sun5i_base;
> +
>  	timer_base = devm_platform_ioremap_resource(pdev, 0);
>  	if (IS_ERR(timer_base)) {
>  		dev_err(dev, "Can't map registers\n");
> @@ -314,6 +357,7 @@ static void sun5i_timer_remove(struct platform_device *pdev)
>  static const struct of_device_id sun5i_timer_of_match[] = {
>  	{ .compatible = "allwinner,sun5i-a13-hstimer" },
>  	{ .compatible = "allwinner,sun7i-a20-hstimer" },
> +	{ .compatible = "allwinner,sun50i-h616-hstimer" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, sun5i_timer_of_match);
> 


^ permalink raw reply

* Re: [PATCH RFC v2 02/11] ASoC: meson: aiu-encoder-i2s: use gx_iface and gx_stream structures
From: Valerio Setti @ 2026-04-19 23:17 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Mark Brown, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
	Neil Armstrong, Kevin Hilman, Martin Blumenstingl, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-kernel, linux-sound,
	linux-arm-kernel, linux-amlogic, devicetree
In-Reply-To: <1jy0ios3f9.fsf@starbuckisacylon.baylibre.com>


On 4/15/26 16:28, Jerome Brunet wrote:

> 
> Huh interresting, I had not thought of that. Valerio and I discussed the
> clock part a lot for this rework. It is the crux since since the
> interface and clock setting lives in the AIU subsys but serves both the
> AIU and AUDIN subsys.
> 
> Valerio maybe you could keep function above just to set the rate, but
> enabling the clocks through a DAPM supply widget ? This is kind of what
> the AXG is doing.
> 
> what do you think ?
> 
> (actually in the AXG the each formatter widget call CCF
> clk_prepare_enable() but a supply widget poking the register would do
> the same thing)
> 

Hi Jerome,

thanks for your review and suggestion.
I took some time to investigate it and I think I have a different 
proposal that reduces the amount of changes compared to the current 
implementation, but gets to the same result.

The thing is in "axg-tdm-interface.c" MCLK is enabled/disabled using 
"set_bias_level()" callback which works fine because in that case the 
interface driver is also a standalone component. On the GX platform the 
interface is a DAI which is part of the AIU component, so this callback 
isn't available. To get the same behavior I would need to add a new DAPM 
widget in "aiu_cpu_dapm_widgets[]" and then add it to both 
"aiu_cpu_dapm_routes[]" both in "aiu.c" and in the device-tree for AUDIN.

What if instead I add the "prepare()" callback to 
"aiu_encoder_i2s_dai_ops" and enable MCLK and I2S clock divider there? 
This would match "hw_free()" calls and it would be a change only 
internal to "aiu-encoder-i2s.c".
To support this I will:
- remove calls to "gx_stream_set_cont_clocks" which are arguably not 
very useful for the GX platform;
- use the "clk_enabled" field of "struct gx_stream" (unused after 
removal of "gx_stream_set_cont_clocks" calls) to track the status of 
MCLK and enable/disable it only when necessary (ex: prevent multiple 
calls to "prepare" to enable MCLK multiple times, etc);
- keep using "snd_soc_dai_active" in "hw_free" to know when to disable 
the I2S clock divider. Or perhaps I can rely on "clk_enabled" also for 
this one so that I can manage these 2 clocks uniformly.

Is this an acceptable alternative approach for you?

-- 
Valerio


^ permalink raw reply

* [PATCHv2 1/2] dt-bindings: arm: altera: document the Agilex7-M devkit
From: Dinh Nguyen @ 2026-04-19 23:24 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt; +Cc: dinguyen, devicetree

The Agilex7-M is a rebranded version of the original Agilex SoC. The
Agilex7-M SoC has the same core peripherals as the Agilex device.

This change is to document the Agilex7m devkit which has the Agilex7-M
device. The Agilex7-M SoC supports DDR4, DDR5, LPDDR5, PCIE 5.0(x16), but
not QSPI.

Also, now that Altera has separated from Intel, use the "altr" company
prefix.

Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
v2: use a specific binding, "altr,socfpga-agilex7m" for the Agilex7-M SoC
---
 Documentation/devicetree/bindings/arm/altera.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/altera.yaml b/Documentation/devicetree/bindings/arm/altera.yaml
index 13a3a9696821..550f484c06ff 100644
--- a/Documentation/devicetree/bindings/arm/altera.yaml
+++ b/Documentation/devicetree/bindings/arm/altera.yaml
@@ -108,6 +108,12 @@ properties:
               - intel,socfpga-agilex5-socdk-nand
           - const: intel,socfpga-agilex5
 
+      - description: Agilex7m boards
+        items:
+          - enum:
+              - altr,socfpga-agilex7m-socdk
+          - const: altr,socfpga-agilex7m
+
       - description: SoCFPGA VT
         items:
           - const: altr,socfpga-vt
-- 
2.42.0.411.g813d9a9188


^ permalink raw reply related

* [PATCHv2 2/2] arm64: dts: socfpga: agilex7m: Add SoCFPGA Agilex7-M devkit
From: Dinh Nguyen @ 2026-04-19 23:24 UTC (permalink / raw)
  To: robh, krzk+dt, conor+dt; +Cc: dinguyen, devicetree
In-Reply-To: <20260419232416.68331-1-dinguyen@kernel.org>

The Agilex7-M devkit contains an Agilex7M SoC, which is a newly branded
version of the original Agilex SoC. The Agilex7M core peripherals are
identical to the Agilex SoC.

We can re-use the socfpga_agilex.dtsi for this devkit. The Agilex7-M
devkit supports PCIE 5.0(x16), DDR4, DDR5, LPDDR5 and does not have QSPI.

Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
v2: use the updated "altr,socfpga-agilex7m" and
    "altr,socfpga-agilex7m-socdk"
---
 arch/arm64/boot/dts/intel/Makefile            |   1 +
 .../boot/dts/intel/socfpga_agilex7m_socdk.dts | 104 ++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 arch/arm64/boot/dts/intel/socfpga_agilex7m_socdk.dts

diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile
index 33fcc55d0cb9..088a03b89c99 100644
--- a/arch/arm64/boot/dts/intel/Makefile
+++ b/arch/arm64/boot/dts/intel/Makefile
@@ -8,5 +8,6 @@ dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_n6000.dtb \
 				socfpga_agilex5_socdk_013b.dtb \
 				socfpga_agilex5_socdk_modular.dtb \
 				socfpga_agilex5_socdk_nand.dtb \
+				socfpga_agilex7m_socdk.dtb \
 				socfpga_n5x_socdk.dtb
 dtb-$(CONFIG_ARCH_KEEMBAY) += keembay-evm.dtb
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex7m_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_agilex7m_socdk.dts
new file mode 100644
index 000000000000..952987cf3fd4
--- /dev/null
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex7m_socdk.dts
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2026 Altera Corporation
+
+#include "socfpga_agilex.dtsi"
+
+/ {
+	model = "Altera SoCFPGA Agilex7-M SoCDK";
+	compatible = "altr,socfpga-agilex7m-socdk",
+		     "altr,socfpga-agilex7m";
+
+	aliases {
+		serial0 = &uart0;
+		ethernet0 = &gmac0;
+		ethernet1 = &gmac1;
+		ethernet2 = &gmac2;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		led0 {
+			label = "hps_led0";
+			gpios = <&portb 20 GPIO_ACTIVE_HIGH>;
+		};
+
+		led1 {
+			label = "hps_led1";
+			gpios = <&portb 19 GPIO_ACTIVE_HIGH>;
+		};
+
+		led2 {
+			label = "hps_led2";
+			gpios = <&portb 21 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		/* We expect the bootloader to fill in the reg */
+		reg = <0 0x80000000 0 0>;
+	};
+};
+
+&gpio1 {
+	status = "okay";
+};
+
+&gmac0 {
+	status = "okay";
+	phy-mode = "rgmii-id";
+	phy-handle = <&phy0>;
+
+	max-frame-size = <9000>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+		phy0: ethernet-phy@4 {
+			reg = <4>;
+
+			txd0-skew-ps = <0>; /* -420ps */
+			txd1-skew-ps = <0>; /* -420ps */
+			txd2-skew-ps = <0>; /* -420ps */
+			txd3-skew-ps = <0>; /* -420ps */
+			rxd0-skew-ps = <420>; /* 0ps */
+			rxd1-skew-ps = <420>; /* 0ps */
+			rxd2-skew-ps = <420>; /* 0ps */
+			rxd3-skew-ps = <420>; /* 0ps */
+			txen-skew-ps = <0>; /* -420ps */
+			txc-skew-ps = <900>; /* 0ps */
+			rxdv-skew-ps = <420>; /* 0ps */
+			rxc-skew-ps = <1680>; /* 780ps */
+		};
+	};
+};
+
+&mmc {
+	status = "okay";
+	cap-sd-highspeed;
+	broken-cd;
+	bus-width = <4>;
+	clk-phase-sd-hs = <0>, <135>;
+};
+
+&osc1 {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&usb0 {
+	status = "okay";
+	disable-over-current;
+};
+
+&watchdog0 {
+	status = "okay";
+};
-- 
2.42.0.411.g813d9a9188


^ permalink raw reply related

* Re: [PATCH 1/2] mailmap: Update Sasha Finkelstein's email address
From: Neal Gompa @ 2026-04-20  1:10 UTC (permalink / raw)
  To: Sasha Finkelstein
  Cc: Janne Grunau, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sven Peter, asahi, linux-kernel, devicetree
In-Reply-To: <20260411-mailmap-v1-1-5a519f7b00b5@chaosmail.tech>

On Sat, Apr 11, 2026 at 10:36 AM Sasha Finkelstein <k@chaosmail.tech> wrote:
>
> Add mailmap entry
>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---

Acked-by: Neal Gompa <neal@gompa.dev>


-- 
真実はいつも一つ!/ Always, there's only one truth!

^ permalink raw reply

* [PATCH v2 0/9] ASoC: mediatek: mt2701: HDMI audio support
From: Daniel Golle @ 2026-04-20  1:12 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek

This series wires up on-chip HDMI audio on MT2701 and MT7623N, from the
DRM bridge down through the AFE into a small machine driver that binds
the AFE HDMI BE to the HDMI TX codec already exposed by the
mediatek-drm-hdmi driver. Bindings, DT and a BananaPi R2 board node
are included.

In order to survive vblank or late hotplug of the monitor, the fix
submitted separately [1] is required as well.

Everything here was developed for and tested on a BananaPi R2
(MT7623N), which turns ten years old this year -- a nice occasion to
finally land HDMI audio for a SoC which was truly ahead of its time.

[1]: https://patchwork.kernel.org/project/linux-mediatek/patch/a3e22cbae528c9a38d854a586d1736b860998d41.1776265222.git.daniel@makrotopia.org/

Changes since v1:
 * Restrict the four HDMI clocks to mediatek,mt2701-audio only
   using an allOf/if/then conditional; MT7622 is capped at 34
   clocks (Krzysztof Kozlowski)
 * Fix subject prefix to use schema filename (Krzysztof Kozlowski)
 * Rewrite title and description to describe hardware, not driver
   (Krzysztof Kozlowski)
 * Clarify in commit message why this is a separate binding from
   mediatek,mt2701-audio (Krzysztof Kozlowski)
 * use named masks and explicitly set BIT_WIDTH_16 when
   programming AFE_HDMI_OUT_CON0 channel count (Mark Brown)
 * add AUDIO_TOP_CON3, AFE_HDMI_OUT_CON0, AFE_HDMI_CONN0,
   AFE_8CH_I2S_OUT_CON to suspend/resume backup list
   (Mark Brown)

Daniel Golle (9):
  ASoC: dt-bindings: mt2701-afe-pcm: add HDMI audio path clocks
  ASoC: dt-bindings: mediatek,mt2701-hdmi-audio: add HDMI audio output
    binding
  ASoC: mediatek: mt2701: add AFE HDMI register definitions
  ASoC: mediatek: mt2701: add optional HDMI audio path clocks
  ASoC: mediatek: mt2701: add HDMI audio memif, FE and BE DAIs
  ASoC: mediatek: mt2701: add machine driver for on-chip HDMI codec
  ARM: dts: mediatek: mt2701: wire HDMI audio path clocks into AFE
  ARM: dts: mediatek: mt7623: wire HDMI audio path clocks into AFE
  ARM: dts: mediatek: mt7623n-bananapi-bpi-r2: add HDMI audio machine
    node

 .../bindings/sound/mediatek,mt2701-audio.yaml |  23 ++
 .../sound/mediatek,mt2701-hdmi-audio.yaml     |  48 +++
 arch/arm/boot/dts/mediatek/mt2701.dtsi        |  21 +-
 arch/arm/boot/dts/mediatek/mt7623.dtsi        |  21 +-
 .../dts/mediatek/mt7623n-bananapi-bpi-r2.dts  |   7 +
 sound/soc/mediatek/Kconfig                    |  10 +
 sound/soc/mediatek/mt2701/Makefile            |   1 +
 .../mediatek/mt2701/mt2701-afe-clock-ctrl.c   |  22 ++
 sound/soc/mediatek/mt2701/mt2701-afe-common.h |   6 +
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c    | 293 +++++++++++++++++-
 sound/soc/mediatek/mt2701/mt2701-hdmi.c       | 114 +++++++
 sound/soc/mediatek/mt2701/mt2701-reg.h        |  35 +++
 12 files changed, 590 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt2701-hdmi-audio.yaml
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-hdmi.c

-- 
2.53.0

^ permalink raw reply

* [PATCH v2 1/9] ASoC: dt-bindings: mt2701-afe-pcm: add HDMI audio path clocks
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Document four additional optional clocks feeding the HDMI audio
output path on MT2701: the HADDS2 PLL (root of the HDMI audio
clock tree), the HDMI audio and S/PDIF interface power gates,
and the audio APLL root gate. Older device trees that do not
wire these up remain valid via minItems. MT7622 does not have
HDMI audio hardware, so its compatible is restricted to the
base set of 34 clocks.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2:
 * Restrict the four HDMI clocks to mediatek,mt2701-audio only
   using an allOf/if/then conditional; MT7622 is capped at 34
   clocks (Krzysztof Kozlowski)

 .../bindings/sound/mediatek,mt2701-audio.yaml | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml
index 45382c4d86aa3..871bf197650b5 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml
@@ -32,6 +32,7 @@ properties:
     maxItems: 1
 
   clocks:
+    minItems: 34
     items:
       - description: audio infra sys clock
       - description: top audio mux 1
@@ -67,8 +68,13 @@ properties:
       - description: top audio a1 sys pd
       - description: top audio a2 sys pd
       - description: audio merge interface pd
+      - description: HADDS2 PLL 294 MHz (HDMI audio path root)
+      - description: HDMI audio interface pd
+      - description: S/PDIF interface pd
+      - description: audio APLL root pd
 
   clock-names:
+    minItems: 34
     items:
       - const: infra_sys_audio_clk
       - const: top_audio_mux1_sel
@@ -104,6 +110,10 @@ properties:
       - const: audio_a1sys_pd
       - const: audio_a2sys_pd
       - const: audio_mrgif_pd
+      - const: hadds2pll_294m
+      - const: audio_hdmi_pd
+      - const: audio_spdf_pd
+      - const: audio_apll_pd
 
 required:
   - compatible
@@ -114,3 +124,16 @@ required:
   - clock-names
 
 additionalProperties: false
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt7622-audio
+    then:
+      properties:
+        clocks:
+          maxItems: 34
+        clock-names:
+          maxItems: 34
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 2/9] ASoC: dt-bindings: mediatek,mt2701-hdmi-audio: add MT2701 HDMI audio
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Describe the sound card node that routes the MT2701/MT7623N AFE
HDMI playback path to the on-chip HDMI transmitter. This is
separate from the AFE platform binding (mediatek,mt2701-audio)
because it represents board-level audio routing between the AFE
and the HDMI codec, not an additional IP block. MT7623N boards
carry the same IP and use the mt7623n- compatible as a fallback
to mt2701-.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2:
 * Fix subject prefix to use schema filename (Krzysztof Kozlowski)
 * Rewrite title and description to describe hardware, not driver
   (Krzysztof Kozlowski)
 * Clarify in commit message why this is a separate binding from
   mediatek,mt2701-audio (Krzysztof Kozlowski)

 .../sound/mediatek,mt2701-hdmi-audio.yaml     | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mt2701-hdmi-audio.yaml

diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt2701-hdmi-audio.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt2701-hdmi-audio.yaml
new file mode 100644
index 0000000000000..9d5a8166e51ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt2701-hdmi-audio.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt2701-hdmi-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT2701/MT7623N HDMI audio output
+
+maintainers:
+  - Daniel Golle <daniel@makrotopia.org>
+
+description:
+  Sound card routing the MT2701/MT7623N Audio Front End HDMI
+  playback path to the on-chip HDMI transmitter. The AFE
+  provides the DMA memif and internal I2S engine; the HDMI
+  transmitter acts as the audio codec on the serialised link.
+
+properties:
+  compatible:
+    oneOf:
+      - const: mediatek,mt2701-hdmi-audio
+      - items:
+          - const: mediatek,mt7623n-hdmi-audio
+          - const: mediatek,mt2701-hdmi-audio
+
+  mediatek,platform:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle of the MT2701/MT7623N AFE platform node.
+
+  mediatek,audio-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle of the HDMI transmitter acting as audio codec.
+
+required:
+  - compatible
+  - mediatek,platform
+  - mediatek,audio-codec
+
+additionalProperties: false
+
+examples:
+  - |
+    sound-hdmi {
+        compatible = "mediatek,mt7623n-hdmi-audio",
+                     "mediatek,mt2701-hdmi-audio";
+        mediatek,platform = <&afe>;
+        mediatek,audio-codec = <&hdmi0>;
+    };
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 3/9] ASoC: mediatek: mt2701: add AFE HDMI register definitions
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Add register offsets and bit defines for the MT2701/MT7623N AFE
HDMI audio output path: the HDMI BCK divider in AUDIO_TOP_CON3,
the HDMI output memif control and descriptor registers, the 8-bit
AFE_HDMI_CONN0 interconnect, and the AFE_8CH_I2S_OUT_CON engine
that drives the HDMI TX serial link. These are a prerequisite for
adding an HDMI playback path to the mt2701 AFE driver and have no
behavioural effect on their own.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2: no changes

 sound/soc/mediatek/mt2701/mt2701-reg.h | 35 ++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h
index c84d14cdd7ae8..b7a25bfb58662 100644
--- a/sound/soc/mediatek/mt2701/mt2701-reg.h
+++ b/sound/soc/mediatek/mt2701/mt2701-reg.h
@@ -10,10 +10,17 @@
 #define _MT2701_REG_H_
 
 #define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON3 0x000c
 #define AUDIO_TOP_CON4 0x0010
 #define AUDIO_TOP_CON5 0x0014
 #define AFE_DAIBT_CON0 0x001c
 #define AFE_MRGIF_CON 0x003c
+#define AFE_HDMI_OUT_CON0 0x0370
+#define AFE_HDMI_OUT_BASE 0x0374
+#define AFE_HDMI_OUT_CUR  0x0378
+#define AFE_HDMI_OUT_END  0x037c
+#define AFE_HDMI_CONN0    0x0390
+#define AFE_8CH_I2S_OUT_CON 0x0394
 #define ASMI_TIMING_CON1 0x0100
 #define ASMO_TIMING_CON1 0x0104
 #define PWR1_ASM_CON1 0x0108
@@ -125,6 +132,34 @@
 #define AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK	(0x3 << 12)
 #define AFE_MEMIF_PBUF_SIZE_DLM_32BYTES		(0x1 << 12)
 
+/* AUDIO_TOP_CON0 (0x0000) -- HDMI audio clock gating */
+#define AUDIO_TOP_CON0_PDN_HDMI_CK		(0x1 << 20)
+#define AUDIO_TOP_CON0_PDN_SPDIF_CK		(0x1 << 21)
+#define AUDIO_TOP_CON0_PDN_SPDIF2_CK		(0x1 << 22)
+#define AUDIO_TOP_CON0_PDN_APLL_CK		(0x1 << 23)
+
+/* AUDIO_TOP_CON3 (0x000c) -- HDMI BCK divider */
+#define AUDIO_TOP_CON3_HDMI_BCK_DIV_MASK	(0x3f << 8)
+#define AUDIO_TOP_CON3_HDMI_BCK_DIV(x)		(((x) & 0x3f) << 8)
+
+/* AFE_HDMI_OUT_CON0 (0x0370) */
+#define AFE_HDMI_OUT_CON0_OUT_ON		(0x1 << 0)
+#define AFE_HDMI_OUT_CON0_BIT_WIDTH_MASK	(0x1 << 1)
+#define AFE_HDMI_OUT_CON0_BIT_WIDTH_16		(0x0 << 1)
+#define AFE_HDMI_OUT_CON0_BIT_WIDTH_32		(0x1 << 1)
+#define AFE_HDMI_OUT_CON0_CH_NUM_MASK		(0xf << 4)
+#define AFE_HDMI_OUT_CON0_CH_NUM(x)		(((x) & 0xf) << 4)
+
+/* AFE_8CH_I2S_OUT_CON (0x0394) -- on-SoC 8-channel I2S that feeds HDMI TX */
+#define AFE_8CH_I2S_OUT_CON_EN			(0x1 << 0)
+#define AFE_8CH_I2S_OUT_CON_BCK_INV		(0x1 << 1)
+#define AFE_8CH_I2S_OUT_CON_LRCK_INV		(0x1 << 2)
+#define AFE_8CH_I2S_OUT_CON_I2S_DELAY		(0x1 << 3)
+#define AFE_8CH_I2S_OUT_CON_WLEN_MASK		(0x3 << 4)
+#define AFE_8CH_I2S_OUT_CON_WLEN_16BIT		(0x1 << 4)
+#define AFE_8CH_I2S_OUT_CON_WLEN_24BIT		(0x2 << 4)
+#define AFE_8CH_I2S_OUT_CON_WLEN_32BIT		(0x3 << 4)
+
 /* I2S in/out register bit control */
 #define ASYS_I2S_CON_FS			(0x1f << 8)
 #define ASYS_I2S_CON_FS_SET(x)		((x) << 8)
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 4/9] ASoC: mediatek: mt2701: add optional HDMI audio path clocks
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

The HDMI audio output path on MT2701/MT7623N is rooted in HADDS2PLL
and gated by the audio_hdmi, audio_spdf and audio_apll power gates.
Acquire these four clocks from device tree using devm_clk_get_optional
so that existing platforms which do not wire up HDMI audio keep
probing unchanged. Actual clock enable/prepare is deferred to the
upcoming HDMI DAI startup path.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2: no changes

 .../mediatek/mt2701/mt2701-afe-clock-ctrl.c   | 22 +++++++++++++++++++
 sound/soc/mediatek/mt2701/mt2701-afe-common.h |  4 ++++
 2 files changed, 26 insertions(+)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
index ae620890bb3ac..5a2bcf027b4fb 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -95,6 +95,28 @@ int mt2701_init_clock(struct mtk_base_afe *afe)
 		afe_priv->mrgif_ck = NULL;
 	}
 
+	/*
+	 * Optional HDMI audio clocks. Platforms that do not wire up the
+	 * HDMI output (e.g. MT2701 devkits using only the I2S BE DAIs)
+	 * may omit these; in that case the HDMI BE DAI simply cannot be
+	 * enabled, but the rest of the AFE still probes.
+	 */
+	afe_priv->hadds2pll_ck = devm_clk_get_optional(afe->dev, "hadds2pll_294m");
+	if (IS_ERR(afe_priv->hadds2pll_ck))
+		return PTR_ERR(afe_priv->hadds2pll_ck);
+
+	afe_priv->audio_hdmi_ck = devm_clk_get_optional(afe->dev, "audio_hdmi_pd");
+	if (IS_ERR(afe_priv->audio_hdmi_ck))
+		return PTR_ERR(afe_priv->audio_hdmi_ck);
+
+	afe_priv->audio_spdf_ck = devm_clk_get_optional(afe->dev, "audio_spdf_pd");
+	if (IS_ERR(afe_priv->audio_spdf_ck))
+		return PTR_ERR(afe_priv->audio_spdf_ck);
+
+	afe_priv->audio_apll_ck = devm_clk_get_optional(afe->dev, "audio_apll_pd");
+	if (IS_ERR(afe_priv->audio_apll_ck))
+		return PTR_ERR(afe_priv->audio_apll_ck);
+
 	return 0;
 }
 
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
index 32bef5e2a56d9..7b15283d6351e 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -90,6 +90,10 @@ struct mt2701_afe_private {
 	struct mt2701_i2s_path *i2s_path;
 	struct clk *base_ck[MT2701_BASE_CLK_NUM];
 	struct clk *mrgif_ck;
+	struct clk *hadds2pll_ck;
+	struct clk *audio_hdmi_ck;
+	struct clk *audio_spdf_ck;
+	struct clk *audio_apll_ck;
 	bool mrg_enable[MTK_STREAM_NUM];
 
 	const struct mt2701_soc_variants *soc;
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 5/9] ASoC: mediatek: mt2701: add HDMI audio memif, FE and BE DAIs
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Extend the MT2701/MT7623N AFE driver with the HDMI playback path:

  - a new HDMI DMA memif (MT2701_MEMIF_HDMI) mapped to the
    AFE_HDMI_OUT_{CON0,BASE,CUR,END} registers;
  - a PCM_HDMI front-end DAI (S16_LE only, 44.1k/48k) which feeds
    the memif via DPCM;
  - an HDMI BE DAI wrapping the AFE_8CH_I2S_OUT_CON engine that
    serialises L/R samples towards the on-chip HDMI transmitter.

Sample-rate programming uses the empirically determined
HDMI_BCK_DIV = 45 * 48000 / rate - 1 formula in AUDIO_TOP_CON3,
which covers 44.1 kHz and 48 kHz within the 6-bit divider range.
The AFE_HDMI_CONN0 interconnect is programmed to route memif
output pairs to the serializer inputs with L/R in the right order
for hdmi-audio-codec.

The existing I2S engine helpers (mt2701_mclk_configuration,
mt2701_i2s_path_enable, mt2701_afe_i2s_path_disable) are reused
for the HDMI BE so that MCLK at 128*fs and the ASYS I2S3 FS field
are programmed and cleanly released across open/close cycles.

Only S16_LE and 44.1k/48k are exposed to userspace. Other rates
fall outside the 6-bit BCK divider range, and wider sample
formats require DMA BIT_WIDTH programming that the current memif
setup does not handle. These limits match what the MT8173 AFE
driver exposes for its HDMI path.

The HDMI-related AFE registers (AUDIO_TOP_CON3, AFE_HDMI_OUT_CON0,
AFE_HDMI_CONN0, AFE_8CH_I2S_OUT_CON) are added to the suspend
backup list so that the existing mtk_afe_suspend/resume framework
saves and restores them across system sleep cycles.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2:
 * use named masks and explicitly set BIT_WIDTH_16 when
   programming AFE_HDMI_OUT_CON0 channel count (Mark Brown)
 * add AUDIO_TOP_CON3, AFE_HDMI_OUT_CON0, AFE_HDMI_CONN0,
   AFE_8CH_I2S_OUT_CON to suspend/resume backup list
   (Mark Brown)

 sound/soc/mediatek/mt2701/mt2701-afe-common.h |   2 +
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c    | 293 +++++++++++++++++-
 2 files changed, 294 insertions(+), 1 deletion(-)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
index 7b15283d6351e..8b6f3a200048a 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -33,6 +33,7 @@ enum {
 	MT2701_MEMIF_UL5,
 	MT2701_MEMIF_DLBT,
 	MT2701_MEMIF_ULBT,
+	MT2701_MEMIF_HDMI,
 	MT2701_MEMIF_NUM,
 	MT2701_IO_I2S = MT2701_MEMIF_NUM,
 	MT2701_IO_2ND_I2S,
@@ -41,6 +42,7 @@ enum {
 	MT2701_IO_5TH_I2S,
 	MT2701_IO_6TH_I2S,
 	MT2701_IO_MRG,
+	MT2701_IO_HDMI,
 };
 
 enum {
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index fcae38135d93f..4db16132e2c07 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -13,6 +13,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
 
 #include "mt2701-afe-common.h"
 #include "mt2701-afe-clock-ctrl.h"
@@ -60,6 +61,7 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = {
 
 static const unsigned int mt2701_afe_backup_list[] = {
 	AUDIO_TOP_CON0,
+	AUDIO_TOP_CON3,
 	AUDIO_TOP_CON4,
 	AUDIO_TOP_CON5,
 	ASYS_TOP_CON,
@@ -77,6 +79,9 @@ static const unsigned int mt2701_afe_backup_list[] = {
 	AFE_CONN22,
 	AFE_DAC_CON0,
 	AFE_MEMIF_PBUF_SIZE,
+	AFE_HDMI_OUT_CON0,
+	AFE_HDMI_CONN0,
+	AFE_8CH_I2S_OUT_CON,
 };
 
 static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num)
@@ -542,6 +547,229 @@ static const struct snd_soc_dai_ops mt2701_btmrg_ops = {
 	.hw_params = mt2701_btmrg_hw_params,
 };
 
+/*
+ * HDMI BE DAI -- drives the on-SoC 8-channel I2S engine whose output
+ * feeds the HDMI transmitter audio port.
+ *
+ * The HDMI audio hardware path is:
+ *   HDMI memif DMA (AFE_HDMI_OUT_*) -> interconnect mux (AFE_HDMI_CONN0)
+ *   -> 8-channel I2S engine (AFE_8CH_I2S_OUT_CON) -> HDMI TX audio port
+ *
+ * The I2S3 clock tree provides the bit/master clocks; we set its
+ * mclk_rate to 128*fs (matching HDMI_AUD_MCLK_128FS) and let
+ * mt2701_mclk_configuration program the PLL/divider path.
+ */
+#define MT2701_HDMI_I2S_PATH	3
+
+static int mt2701_afe_hdmi_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	if (!afe_priv->hadds2pll_ck || !afe_priv->audio_hdmi_ck) {
+		dev_err(afe->dev, "HDMI audio clocks not available\n");
+		return -ENODEV;
+	}
+
+	ret = clk_prepare_enable(afe_priv->hadds2pll_ck);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(afe_priv->audio_hdmi_ck);
+	if (ret)
+		goto err_hdmi;
+
+	if (afe_priv->audio_spdf_ck) {
+		ret = clk_prepare_enable(afe_priv->audio_spdf_ck);
+		if (ret)
+			goto err_spdf;
+	}
+
+	if (afe_priv->audio_apll_ck) {
+		ret = clk_prepare_enable(afe_priv->audio_apll_ck);
+		if (ret)
+			goto err_apll;
+	}
+
+	ret = mt2701_afe_enable_mclk(afe, MT2701_HDMI_I2S_PATH);
+	if (ret)
+		goto err_mclk;
+
+	return 0;
+
+err_mclk:
+	if (afe_priv->audio_apll_ck)
+		clk_disable_unprepare(afe_priv->audio_apll_ck);
+err_apll:
+	if (afe_priv->audio_spdf_ck)
+		clk_disable_unprepare(afe_priv->audio_spdf_ck);
+err_spdf:
+	clk_disable_unprepare(afe_priv->audio_hdmi_ck);
+err_hdmi:
+	clk_disable_unprepare(afe_priv->hadds2pll_ck);
+	return ret;
+}
+
+static void mt2701_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	mt2701_afe_disable_mclk(afe, MT2701_HDMI_I2S_PATH);
+	if (afe_priv->audio_apll_ck)
+		clk_disable_unprepare(afe_priv->audio_apll_ck);
+	if (afe_priv->audio_spdf_ck)
+		clk_disable_unprepare(afe_priv->audio_spdf_ck);
+	clk_disable_unprepare(afe_priv->audio_hdmi_ck);
+	clk_disable_unprepare(afe_priv->hadds2pll_ck);
+}
+
+static int mt2701_afe_hdmi_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	unsigned int channels = params_channels(params);
+	unsigned int rate = params_rate(params);
+	unsigned int divp1;
+	unsigned int val;
+	unsigned int i;
+	int ret;
+
+	/*
+	 * Compute AUDIO_TOP_CON3.HDMI_BCK_DIV up front. The divider
+	 * drives an internal reference for the HDMI transmitter's
+	 * audio packet engine; it must scale with the sample rate so
+	 * that the packet engine's timing matches the data flowing in
+	 * from the AFE memif/I2S3 side. Empirically, with audpll_sel
+	 * parented to hadds2pll_98m (98.304 MHz), the correct value at
+	 * 48 kHz is div = 44 (i.e. (div+1) = 45), giving 1.0923 MHz.
+	 * Scaling inversely with rate: (div + 1) = 45 * 48000 / rate.
+	 * Integer rounding introduces small (<1%) errors at 32 kHz;
+	 * 44.1 kHz is nearly exact via round-to-nearest. Reject rates
+	 * that fall outside the 6-bit divider range before touching
+	 * any hardware so no side effects are left behind on error.
+	 */
+	divp1 = (45U * 48000U + rate / 2) / rate;
+	if (divp1 == 0 || divp1 > 64)
+		return -EINVAL;
+
+	/*
+	 * Park the I2S3 clock tree at 128*fs -- this is the MCLK that
+	 * the ASYS I2S3 engine uses to derive its BCK/LRCK. The engine
+	 * outputs BCK = 64*fs (stereo, 32-bit word length).
+	 */
+	afe_priv->i2s_path[MT2701_HDMI_I2S_PATH].mclk_rate = rate * 128;
+	ret = mt2701_mclk_configuration(afe, MT2701_HDMI_I2S_PATH);
+	if (ret)
+		return ret;
+
+	/* Program and start the ASYS I2S3 engine (FS, I2S mode, enable). */
+	mt2701_i2s_path_enable(afe,
+			       &afe_priv->i2s_path[MT2701_HDMI_I2S_PATH],
+			       SNDRV_PCM_STREAM_PLAYBACK, rate);
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
+			   AUDIO_TOP_CON3_HDMI_BCK_DIV_MASK,
+			   AUDIO_TOP_CON3_HDMI_BCK_DIV(divp1 - 1));
+
+	/*
+	 * HDMI output memif: set channel count and confirm 16-bit
+	 * sample width. Both fields must be written together so that
+	 * stale reset-default or prior-stream values in BIT_WIDTH
+	 * cannot persist.
+	 */
+	regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
+			   AFE_HDMI_OUT_CON0_CH_NUM_MASK |
+			   AFE_HDMI_OUT_CON0_BIT_WIDTH_MASK,
+			   AFE_HDMI_OUT_CON0_CH_NUM(channels) |
+			   AFE_HDMI_OUT_CON0_BIT_WIDTH_16);
+
+	/*
+	 * Interconnect mux -- map DMA input slots to HDMI output slots.
+	 * Each output takes a 3-bit field at shift (i*3). Swap the first
+	 * two inputs so that the DMA's interleaved L/R pair lands on the
+	 * correct HDMI L/R output slots. Remaining slots are identity.
+	 */
+	val = (1 << 0) | (0 << 3);  /* O20 <- I21, O21 <- I20 */
+	for (i = 2; i < 8; i++)
+		val |= ((i & 0x7) << (i * 3));
+	regmap_write(afe->regmap, AFE_HDMI_CONN0, val);
+
+	/*
+	 * 8-channel I2S framing: standard I2S, 32-bit slots,
+	 * LRCK/BCK inverted. The wire protocol is fixed.
+	 */
+	regmap_update_bits(afe->regmap, AFE_8CH_I2S_OUT_CON,
+			   AFE_8CH_I2S_OUT_CON_WLEN_MASK |
+			   AFE_8CH_I2S_OUT_CON_I2S_DELAY |
+			   AFE_8CH_I2S_OUT_CON_LRCK_INV |
+			   AFE_8CH_I2S_OUT_CON_BCK_INV,
+			   AFE_8CH_I2S_OUT_CON_WLEN_32BIT |
+			   AFE_8CH_I2S_OUT_CON_I2S_DELAY |
+			   AFE_8CH_I2S_OUT_CON_LRCK_INV |
+			   AFE_8CH_I2S_OUT_CON_BCK_INV);
+	return 0;
+}
+
+static int mt2701_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		/* Ungate HDMI and SPDIF power islands. */
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+				   AUDIO_TOP_CON0_PDN_HDMI_CK |
+				   AUDIO_TOP_CON0_PDN_SPDIF_CK, 0);
+		/* Enable HDMI output memif. */
+		regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1);
+		/* Enable 8-channel I2S engine. */
+		regmap_update_bits(afe->regmap, AFE_8CH_I2S_OUT_CON,
+				   AFE_8CH_I2S_OUT_CON_EN,
+				   AFE_8CH_I2S_OUT_CON_EN);
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		regmap_update_bits(afe->regmap, AFE_8CH_I2S_OUT_CON,
+				   AFE_8CH_I2S_OUT_CON_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+				   AUDIO_TOP_CON0_PDN_HDMI_CK |
+				   AUDIO_TOP_CON0_PDN_SPDIF_CK,
+				   AUDIO_TOP_CON0_PDN_HDMI_CK |
+				   AUDIO_TOP_CON0_PDN_SPDIF_CK);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int mt2701_afe_hdmi_hw_free(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	mt2701_afe_i2s_path_disable(afe,
+				    &afe_priv->i2s_path[MT2701_HDMI_I2S_PATH],
+				    SNDRV_PCM_STREAM_PLAYBACK);
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt2701_afe_hdmi_ops = {
+	.startup	= mt2701_afe_hdmi_startup,
+	.shutdown	= mt2701_afe_hdmi_shutdown,
+	.hw_params	= mt2701_afe_hdmi_hw_params,
+	.hw_free	= mt2701_afe_hdmi_hw_free,
+	.trigger	= mt2701_afe_hdmi_trigger,
+};
+
 static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 	/* FE DAIs: memory intefaces to CPU */
 	{
@@ -628,6 +856,19 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		},
 		.ops = &mt2701_single_memif_dai_ops,
 	},
+	{
+		.name = "PCM_HDMI",
+		.id = MT2701_MEMIF_HDMI,
+		.playback = {
+			.stream_name = "HDMI Multich",
+			.channels_min = 2,
+			.channels_max = 8,
+			.rates = (SNDRV_PCM_RATE_44100 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
 	/* BE DAIs */
 	{
 		.name = "I2S0",
@@ -748,7 +989,20 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		},
 		.ops = &mt2701_btmrg_ops,
 		.symmetric_rate = 1,
-	}
+	},
+	{
+		.name = "HDMI I2S",
+		.id = MT2701_IO_HDMI,
+		.playback = {
+			.stream_name = "HDMI 8CH I2S Playback",
+			.channels_min = 2,
+			.channels_max = 8,
+			.rates = (SNDRV_PCM_RATE_44100 |
+				  SNDRV_PCM_RATE_48000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_afe_hdmi_ops,
+	},
 };
 
 static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
@@ -927,6 +1181,14 @@ static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = {
 	{"I16I17", "Multich I2S2 Out Switch", "DLM"},
 	{"I18I19", "Multich I2S3 Out Switch", "DLM"},
 
+	/*
+	 * HDMI FE -> BE direct route. The HDMI memif has its own DMA
+	 * path that feeds the 8-channel internal I2S straight into the
+	 * HDMI transmitter; no mixer/interconnect selection is exposed
+	 * to the user.
+	 */
+	{"HDMI 8CH I2S Playback", NULL, "HDMI Multich"},
+
 	{ "I12", NULL, "I12I13" },
 	{ "I13", NULL, "I12I13" },
 	{ "I14", NULL, "I14I15" },
@@ -1207,6 +1469,35 @@ static const struct mtk_base_memif_data memif_data_array[MT2701_MEMIF_NUM] = {
 		.agent_disable_shift = 16,
 		.msb_reg = -1,
 	},
+	{
+		/*
+		 * HDMI memif feeds the on-SoC 8-channel internal I2S that
+		 * drives the HDMI transmitter audio port. Unlike the
+		 * standard memifs, the enable bit, channel count and bit
+		 * width all live in AFE_HDMI_OUT_CON0, so mono/fs/hd/agent
+		 * fields are left at -1 and programmed from the BE DAI ops
+		 * instead.
+		 */
+		.name = "HDMI",
+		.id = MT2701_MEMIF_HDMI,
+		.reg_ofs_base = AFE_HDMI_OUT_BASE,
+		.reg_ofs_cur = AFE_HDMI_OUT_CUR,
+		.reg_ofs_end = AFE_HDMI_OUT_END,
+		.fs_reg = -1,
+		.fs_shift = -1,
+		.fs_maskbit = 0,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.enable_reg = AFE_HDMI_OUT_CON0,
+		.enable_shift = 0,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.hd_align_reg = -1,
+		.hd_align_mshift = 0,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = 0,
+		.msb_reg = -1,
+	},
 };
 
 static const struct mtk_base_irq_data irq_data[MT2701_IRQ_ASYS_END] = {
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 6/9] ASoC: mediatek: mt2701: add machine driver for on-chip HDMI codec
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Add a simple ASoC machine driver that wires the MT2701/MT7623N
AFE HDMI playback path to the on-chip HDMI transmitter exposed
as a generic hdmi-audio-codec "i2s-hifi" DAI.

The driver binds to "mediatek,mt2701-hdmi-audio". MT7623N device
trees carry "mediatek,mt7623n-hdmi-audio" as a board-specific
fallback, matching the dt-binding.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2: no changes

 sound/soc/mediatek/Kconfig              |  10 +++
 sound/soc/mediatek/mt2701/Makefile      |   1 +
 sound/soc/mediatek/mt2701/mt2701-hdmi.c | 114 ++++++++++++++++++++++++
 3 files changed, 125 insertions(+)
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-hdmi.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 3a1e1fa3fe5cc..fa076e7854adc 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -26,6 +26,16 @@ config SND_SOC_MT2701_CS42448
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+config SND_SOC_MT2701_HDMI
+	tristate "ASoC Audio driver for MT2701 with on-chip HDMI codec"
+	depends on SND_SOC_MT2701
+	select SND_SOC_HDMI_CODEC
+	help
+	  This adds the ASoC machine driver for MediaTek MT2701 and
+	  MT7623N boards routing the AFE I2S back-end to the on-chip
+	  HDMI transmitter via the generic HDMI codec.
+	  If unsure select "N".
+
 config SND_SOC_MT2701_WM8960
 	tristate "ASoc Audio driver for MT2701 with WM8960 codec"
 	depends on SND_SOC_MT2701 && I2C
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
index 507fa26c39452..59623d3d3a038 100644
--- a/sound/soc/mediatek/mt2701/Makefile
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
 
 # machine driver
 obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o
+obj-$(CONFIG_SND_SOC_MT2701_HDMI) += mt2701-hdmi.o
 obj-$(CONFIG_SND_SOC_MT2701_WM8960) += mt2701-wm8960.o
diff --git a/sound/soc/mediatek/mt2701/mt2701-hdmi.c b/sound/soc/mediatek/mt2701/mt2701-hdmi.c
new file mode 100644
index 0000000000000..a84907879c04e
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-hdmi.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt2701-hdmi.c -- MT2701 HDMI ALSA SoC machine driver
+ *
+ * Copyright (c) 2026 Daniel Golle <daniel@makrotopia.org>
+ *
+ * Based on mt2701-cs42448.c
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+
+enum {
+	DAI_LINK_FE_HDMI_OUT,
+	DAI_LINK_BE_HDMI_I2S,
+};
+
+SND_SOC_DAILINK_DEFS(fe_hdmi_out,
+	DAILINK_COMP_ARRAY(COMP_CPU("PCM_HDMI")),
+	DAILINK_COMP_ARRAY(COMP_DUMMY()),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(be_hdmi_i2s,
+	DAILINK_COMP_ARRAY(COMP_CPU("HDMI I2S")),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt2701_hdmi_dai_links[] = {
+	[DAI_LINK_FE_HDMI_OUT] = {
+		.name = "HDMI Playback",
+		.stream_name = "HDMI Playback",
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.dynamic = 1,
+		.playback_only = 1,
+		SND_SOC_DAILINK_REG(fe_hdmi_out),
+	},
+	[DAI_LINK_BE_HDMI_I2S] = {
+		.name = "HDMI BE",
+		.no_pcm = 1,
+		.playback_only = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			   SND_SOC_DAIFMT_CBC_CFC,
+		SND_SOC_DAILINK_REG(be_hdmi_i2s),
+	},
+};
+
+static struct snd_soc_card mt2701_hdmi_soc_card = {
+	.name = "mt2701-hdmi",
+	.owner = THIS_MODULE,
+	.dai_link = mt2701_hdmi_dai_links,
+	.num_links = ARRAY_SIZE(mt2701_hdmi_dai_links),
+};
+
+static int mt2701_hdmi_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt2701_hdmi_soc_card;
+	struct device *dev = &pdev->dev;
+	struct device_node *platform_node;
+	struct device_node *codec_node;
+	struct snd_soc_dai_link *dai_link;
+	int ret;
+	int i;
+
+	platform_node = of_parse_phandle(dev->of_node, "mediatek,platform", 0);
+	if (!platform_node)
+		return dev_err_probe(dev, -EINVAL,
+				     "Property 'mediatek,platform' missing\n");
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (dai_link->platforms->name)
+			continue;
+		dai_link->platforms->of_node = platform_node;
+	}
+
+	codec_node = of_parse_phandle(dev->of_node, "mediatek,audio-codec", 0);
+	if (!codec_node) {
+		of_node_put(platform_node);
+		return dev_err_probe(dev, -EINVAL,
+				     "Property 'mediatek,audio-codec' missing\n");
+	}
+	mt2701_hdmi_dai_links[DAI_LINK_BE_HDMI_I2S].codecs->of_node = codec_node;
+
+	card->dev = dev;
+
+	ret = devm_snd_soc_register_card(dev, card);
+
+	of_node_put(platform_node);
+	of_node_put(codec_node);
+	return ret;
+}
+
+static const struct of_device_id mt2701_hdmi_machine_dt_match[] = {
+	{ .compatible = "mediatek,mt2701-hdmi-audio" },
+	{ .compatible = "mediatek,mt7623n-hdmi-audio" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt2701_hdmi_machine_dt_match);
+
+static struct platform_driver mt2701_hdmi_machine = {
+	.driver = {
+		.name = "mt2701-hdmi",
+		.of_match_table = mt2701_hdmi_machine_dt_match,
+	},
+	.probe = mt2701_hdmi_machine_probe,
+};
+module_platform_driver(mt2701_hdmi_machine);
+
+MODULE_DESCRIPTION("MT2701 HDMI ALSA SoC machine driver");
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mt2701-hdmi");
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 7/9] ARM: dts: mediatek: mt2701: wire HDMI audio path clocks into AFE
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Add the HADDS2 PLL 294 MHz root, the audio_hdmi and audio_spdf
interface gates and the audio_apll gate to the MT2701 AFE node,
and reparent the AUDPLL mux to HADDS2PLL_98M so the HDMI audio
serial clock path has a stable 294.912 MHz source. The clock
names match the updated mediatek,mt2701-audio binding.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2: no changes

 arch/arm/boot/dts/mediatek/mt2701.dtsi | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/mediatek/mt2701.dtsi b/arch/arm/boot/dts/mediatek/mt2701.dtsi
index 128b87229f3d5..80c8c7e6a422a 100644
--- a/arch/arm/boot/dts/mediatek/mt2701.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt2701.dtsi
@@ -464,7 +464,11 @@ afe: audio-controller {
 				 <&audsys CLK_AUD_AFE_CONN>,
 				 <&audsys CLK_AUD_A1SYS>,
 				 <&audsys CLK_AUD_A2SYS>,
-				 <&audsys CLK_AUD_AFE_MRGIF>;
+				 <&audsys CLK_AUD_AFE_MRGIF>,
+				 <&topckgen CLK_TOP_HADDS2PLL_294M>,
+				 <&audsys CLK_AUD_HDMI>,
+				 <&audsys CLK_AUD_SPDF>,
+				 <&audsys CLK_AUD_APLL>;
 
 			clock-names = "infra_sys_audio_clk",
 				      "top_audio_mux1_sel",
@@ -499,15 +503,22 @@ afe: audio-controller {
 				      "audio_afe_conn_pd",
 				      "audio_a1sys_pd",
 				      "audio_a2sys_pd",
-				      "audio_mrgif_pd";
+				      "audio_mrgif_pd",
+				      "hadds2pll_294m",
+				      "audio_hdmi_pd",
+				      "audio_spdf_pd",
+				      "audio_apll_pd";
 
 			assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>,
 					  <&topckgen CLK_TOP_AUD_MUX2_SEL>,
 					  <&topckgen CLK_TOP_AUD_MUX1_DIV>,
-					  <&topckgen CLK_TOP_AUD_MUX2_DIV>;
+					  <&topckgen CLK_TOP_AUD_MUX2_DIV>,
+					  <&topckgen CLK_TOP_AUDPLL_MUX_SEL>;
 			assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>,
-						 <&topckgen CLK_TOP_AUD2PLL_90M>;
-			assigned-clock-rates = <0>, <0>, <49152000>, <45158400>;
+						 <&topckgen CLK_TOP_AUD2PLL_90M>,
+						 <0>, <0>,
+						 <&topckgen CLK_TOP_HADDS2PLL_98M>;
+			assigned-clock-rates = <0>, <0>, <49152000>, <45158400>, <0>;
 		};
 	};
 
-- 
2.53.0

^ permalink raw reply related

* [PATCH v2 8/9] ARM: dts: mediatek: mt7623: wire HDMI audio path clocks into AFE
From: Daniel Golle @ 2026-04-20  1:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Jaroslav Kysela, Takashi Iwai, Arnd Bergmann, Cyril Chao,
	Daniel Golle, Nícolas F. R. A. Prado, Kuninori Morimoto,
	Eugen Hristev, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <cover.1776646435.git.daniel@makrotopia.org>

Mirror the MT2701 change for the MT7623 SoC dtsi: add HADDS2PLL,
audio_hdmi, audio_spdf and audio_apll to the AFE clocks list and
reparent the AUDPLL mux to HADDS2PLL_98M. Required for HDMI audio
on MT7623N boards via the shared mt2701 AFE driver.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2: no changes

 arch/arm/boot/dts/mediatek/mt7623.dtsi | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi
index 71ac2b94c6ba3..4eb028ffee6f5 100644
--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi
@@ -665,7 +665,11 @@ afe: audio-controller {
 				 <&audsys CLK_AUD_AFE_CONN>,
 				 <&audsys CLK_AUD_A1SYS>,
 				 <&audsys CLK_AUD_A2SYS>,
-				 <&audsys CLK_AUD_AFE_MRGIF>;
+				 <&audsys CLK_AUD_AFE_MRGIF>,
+				 <&topckgen CLK_TOP_HADDS2PLL_294M>,
+				 <&audsys CLK_AUD_HDMI>,
+				 <&audsys CLK_AUD_SPDF>,
+				 <&audsys CLK_AUD_APLL>;
 
 			clock-names = "infra_sys_audio_clk",
 				      "top_audio_mux1_sel",
@@ -700,15 +704,22 @@ afe: audio-controller {
 				      "audio_afe_conn_pd",
 				      "audio_a1sys_pd",
 				      "audio_a2sys_pd",
-				      "audio_mrgif_pd";
+				      "audio_mrgif_pd",
+				      "hadds2pll_294m",
+				      "audio_hdmi_pd",
+				      "audio_spdf_pd",
+				      "audio_apll_pd";
 
 			assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>,
 					  <&topckgen CLK_TOP_AUD_MUX2_SEL>,
 					  <&topckgen CLK_TOP_AUD_MUX1_DIV>,
-					  <&topckgen CLK_TOP_AUD_MUX2_DIV>;
+					  <&topckgen CLK_TOP_AUD_MUX2_DIV>,
+					  <&topckgen CLK_TOP_AUDPLL_MUX_SEL>;
 			assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>,
-						 <&topckgen CLK_TOP_AUD2PLL_90M>;
-			assigned-clock-rates = <0>, <0>, <49152000>, <45158400>;
+						 <&topckgen CLK_TOP_AUD2PLL_90M>,
+						 <0>, <0>,
+						 <&topckgen CLK_TOP_HADDS2PLL_98M>;
+			assigned-clock-rates = <0>, <0>, <49152000>, <45158400>, <0>;
 		};
 	};
 
-- 
2.53.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox