From nobody Fri Jun 12 11:31:58 2026 Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6BBC3ACA5F for ; Wed, 10 Jun 2026 21:29:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126982; cv=none; b=eyHK7rloO1Ky6VC7VpkdUzIWdNH3Io/BQ0UJbE4NLQ6z2nz8IfP4y6iKcJHPFZo/7McqSmQfkOmmigY9isPnRbMvwbUE9gla7twn92Izyr56+2lEPBK6UZRMTQ/I5Ude2C8+qf9OKOecJLjR5S1743N7s6wGFj+zq2L3lpZWN2Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126982; c=relaxed/simple; bh=trgz8cBBhoMcWZm4BFymiPHpU+7G88HDCgUCGN9Npl8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JH49LcR1iZMZWYxmX6gfri4Z4doTemjNMR7/E4hZOrZnqXoG14VXPsUM4wa0OtOYMP/o0DSftvx9+9wqSEqpOVs++bS7PMvkpjXbqbkGObOAv3om2sRAxD0K35mrwEGC2fCC0+pPxJfw23M9C7Pcz3RisOQJ5RDyEJ4L4WT+mWg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=TisvyiKO; arc=none smtp.client-ip=209.85.128.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="TisvyiKO" Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-490cf322ed0so32565565e9.1 for ; Wed, 10 Jun 2026 14:29:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1781126979; x=1781731779; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=arBcvsWOJ7tCGJfn8TBgJSURx+zdaxN19ttwPiWsVPk=; b=TisvyiKOzWHpBa1neK2svgXdE3ygIaRpNanXf7tVddtbkXTaa4ygSlC1IPGwld4UU/ lKh+9WUenEuYpXzJRtQfRXw2zOZXYITf5OP5aey/xwlgAh6xG2I5Cz010Nn6tZ7Hi/JI 3wwFavA9kVent3O7dhTvDEop+BYoejflZHOJBucwSKWvxUc7qCOgEgmqIgY+XuGhnU0A kv7pgg8/xfVlofIekJqPzBnZchvZ5EHR8zaomqzbcOtTnl7LRqGrx0O89wO5X7dEuymJ BxZXyK+XLOCsspVEBVotGJwnYyowN04Dq8ASplUEffQyKGxt86ABOzwotBBqlyWBgkmh mTVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781126979; x=1781731779; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=arBcvsWOJ7tCGJfn8TBgJSURx+zdaxN19ttwPiWsVPk=; b=PhCgu1phPqwrsdW988Ervm8/hBaAMLfu2lWsX0QnV7aNNj9Ec/MtrowSPqwWtlGtzE CM6+GtOpu1JFDdDOVJQiKKvvHrYilNmpIno9MdGUuv8ooyrduKYtgdpqgn/rm/wAMPZ5 kRD7ykuukq2scfQebxnyWt7/xphpOoluKkjRSHHERNHM/iB9xawrDEE01Okpk9RJS0t2 ghSgyxDxC2wJhJE6Fiyj65xmTPveo0VHqQ65jLer550jh+KQc5KGsWqZU/8p2UZPpMt3 0i/fJEmHoK3y7IH4pQJvy90VAHcSXjqYcqu5o4vALFVgItb/quZ3wmFC1Od1NCZVfMJj I6yg== X-Gm-Message-State: AOJu0Yx6bIgCeNUVIvp14ZdpiaitYHC32cL+ucmePB9GELIBeCKARx4z MNTCmjkD7D+bzDkv2ilDw5xFm3EBrw9vYvaLszamPs5jlynrRTR7ZBk3m0HfJkGjO7I= X-Gm-Gg: Acq92OG9Y4iWBv9O8MQm7mTdaj27TmT/yBIF3BMC+71Q42inTB88H43ZuYHuOnP4aR5 IKafiszcNypjCEfUEoDxV5P+j/lum7MvfJZGHr+jO1hAxw4Y7rkZuODsSWGLFEEv9rFZIpTN4jL QwH2Fl0rkm0rB3atjallOpA2Z/Os7vQ5ac4Sgs7h2yAOLs5E7G9IS3L4sTg5Rrzo1PGU8TnpX7j iytVPxMYD/im6/84ZrU3fBm9AhzWCl61lyh/EKEFAtLjabpLKpMxHb38SXgrF+AMddvrz1Idntd TBHLkhjio63EgUYhobwvQQi1tq030citHfNtp5s3Tot7LCuZo/Fgol/XBtu6sboiaepti6QGKbq 4rWwiP1wi/EGyml7822yjdQSyApXQuTUXIKlGbSxB4u+F0tW3mlfP4qjy8WrBGg9f5ISQaNfmvL THxew+QKy0UeE7T3FDxSGrElY1FWgN4b8= X-Received: by 2002:a7b:c8da:0:b0:490:e1cd:e5a3 with SMTP id 5b1f17b1804b1-490e1cde5ecmr23023835e9.26.1781126979178; Wed, 10 Jun 2026 14:29:39 -0700 (PDT) Received: from [127.0.1.1] ([151.61.238.34]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490e4228768sm970965e9.0.2026.06.10.14.29.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Jun 2026 14:29:38 -0700 (PDT) From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:25 +0200 Subject: [PATCH v2 1/4] ASoC: meson: gx: add gx-formatter and gx-interface Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260610-reshape-aiu-as-axg-v2-1-cac3663a8b51@baylibre.com> References: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> In-Reply-To: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> To: Jerome Brunet , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Neil Armstrong , Kevin Hilman , Martin Blumenstingl Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-amlogic@lists.infradead.org, Valerio Setti X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=11719; i=vsetti@baylibre.com; h=from:subject:message-id; bh=trgz8cBBhoMcWZm4BFymiPHpU+7G88HDCgUCGN9Npl8=; b=owGbwMvMwCF2z3ty7kUrRgbG02pJDFma1x30fy88v9r8P99NAakzzu4JWYttVjPdvnGU7/z6g CL7WJnJHaUsDGIcDLJiiiws0+/9LihVe2iccLIAZg4rE8gQBi5OAZjIWSZGhl1nv/Lei/7cUph6 er+Yaus8lQ0s17iD3/8xZlh+RnxCy0lGhnV3IzMOMqb+lrE8vfG5jmDN0llb5ovtvJ1Zrcv3V8m shA0A X-Developer-Key: i=vsetti@baylibre.com; a=openpgp; fpr=0497DEFB707526E13360C970DE4B936DD13A0100 These files are the basic block which allow to shape I2S in GX devices the same as the AXG ones: the DAI backend only controls the interface (i.e. clocks and pins) whereas a formatter takes care of properly formatting the data. gx-formatter and gx-interface are strongly inspired to axg-tdm-formatter and axg-tdm, respectively. The long term plan is to join the two platforms to use the same formatter solution. There is only a minor addition here compared to what has been done for AXG and it's "gx_formatter_create()" which is required in order to let already existing AIU code to make use of this formatter without making any devicetree change. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet --- sound/soc/meson/Makefile | 1 + sound/soc/meson/gx-formatter.c | 282 +++++++++++++++++++++++++++++++++++++= ++++ sound/soc/meson/gx-formatter.h | 56 ++++++++ sound/soc/meson/gx-interface.h | 48 +++++++ 4 files changed, 387 insertions(+) diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index 24078e4396b02d545d8ba4bcb1632979001354e3..146ec81526ba091a174a113ce3d= 8412ddbbfd9dd 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -4,6 +4,7 @@ snd-soc-meson-aiu-y :=3D aiu.o snd-soc-meson-aiu-y +=3D aiu-acodec-ctrl.o snd-soc-meson-aiu-y +=3D aiu-codec-ctrl.o snd-soc-meson-aiu-y +=3D aiu-encoder-i2s.o +snd-soc-meson-aiu-y +=3D gx-formatter.o snd-soc-meson-aiu-y +=3D aiu-encoder-spdif.o snd-soc-meson-aiu-y +=3D aiu-fifo.o snd-soc-meson-aiu-y +=3D aiu-fifo-i2s.o diff --git a/sound/soc/meson/gx-formatter.c b/sound/soc/meson/gx-formatter.c new file mode 100644 index 0000000000000000000000000000000000000000..311e63affb239ee575d59b7c6ea= 5c1c5f3ab2300 --- /dev/null +++ b/sound/soc/meson/gx-formatter.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// +// Copyright (c) 2026 BayLibre, SAS. +// Author: Valerio Setti + +#include +#include +#include +#include + +#include "gx-formatter.h" + +struct gx_formatter { + struct list_head list; + struct gx_stream *stream; + const struct gx_formatter_driver *drv; + bool enabled; + struct regmap *map; +}; + +static int gx_formatter_enable(struct gx_formatter *formatter) +{ + int ret; + + /* Do nothing if the formatter is already enabled */ + if (formatter->enabled) + return 0; + + /* Setup the stream parameter in the formatter */ + if (formatter->drv->ops->prepare) { + ret =3D formatter->drv->ops->prepare(formatter->map, + formatter->drv->quirks, + formatter->stream); + if (ret) + return ret; + } + + /* Finally, actually enable the formatter */ + if (formatter->drv->ops->enable) + formatter->drv->ops->enable(formatter->map); + + formatter->enabled =3D true; + + return 0; +} + +static void gx_formatter_disable(struct gx_formatter *formatter) +{ + /* Do nothing if the formatter is already disabled */ + if (!formatter->enabled) + return; + + if (formatter->drv->ops->disable) + formatter->drv->ops->disable(formatter->map); + + formatter->enabled =3D false; +} + +static int gx_formatter_attach(struct gx_formatter *formatter) +{ + struct gx_stream *ts =3D formatter->stream; + int ret =3D 0; + + mutex_lock(&ts->lock); + + /* Catch up if the stream is already running when we attach */ + if (ts->ready) { + ret =3D gx_formatter_enable(formatter); + if (ret) { + pr_err("failed to enable formatter\n"); + goto out; + } + } + + list_add_tail(&formatter->list, &ts->formatter_list); +out: + mutex_unlock(&ts->lock); + return ret; +} + +static void gx_formatter_detach(struct gx_formatter *formatter) +{ + struct gx_stream *ts =3D formatter->stream; + + if (!ts) + return; + + mutex_lock(&ts->lock); + list_del(&formatter->list); + mutex_unlock(&ts->lock); + + gx_formatter_disable(formatter); +} + +static int gx_formatter_power_up(struct gx_formatter *formatter, + struct snd_soc_dapm_widget *w) +{ + struct gx_stream *ts =3D formatter->drv->ops->get_stream(w); + int ret; + + /* + * If we don't get a stream at this stage, it would mean that the + * widget is powering up but is not attached to any backend DAI. + * It should not happen, ever ! + */ + if (WARN_ON(!ts)) + return -ENODEV; + + formatter->stream =3D ts; + INIT_LIST_HEAD(&formatter->list); + ret =3D gx_formatter_attach(formatter); + if (ret) + return ret; + + return 0; +} + +static void gx_formatter_power_down(struct gx_formatter *formatter) +{ + gx_formatter_detach(formatter); + formatter->stream =3D NULL; +} + +int gx_formatter_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, + int event) +{ + struct snd_soc_component *c; + struct gx_formatter *formatter; + int ret =3D 0; + + c =3D snd_soc_dapm_to_component(w->dapm); + + if (w->priv) + formatter =3D w->priv; + else + formatter =3D snd_soc_component_get_drvdata(c); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret =3D gx_formatter_power_up(formatter, w); + break; + + case SND_SOC_DAPM_PRE_PMD: + gx_formatter_power_down(formatter); + break; + + default: + dev_err(c->dev, "Unexpected event %d\n", event); + return -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(gx_formatter_event); + +int gx_formatter_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + const struct gx_formatter_driver *drv; + struct gx_formatter *formatter; + void __iomem *regs; + + drv =3D of_device_get_match_data(dev); + if (!drv) { + dev_err(dev, "failed to match device\n"); + return -ENODEV; + } + + formatter =3D devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL); + if (!formatter) + return -ENOMEM; + platform_set_drvdata(pdev, formatter); + formatter->drv =3D drv; + + regs =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + formatter->map =3D devm_regmap_init_mmio(dev, regs, drv->regmap_cfg); + if (IS_ERR(formatter->map)) { + dev_err(dev, "failed to init regmap: %ld\n", + PTR_ERR(formatter->map)); + return PTR_ERR(formatter->map); + } + + return devm_snd_soc_register_component(dev, drv->component_drv, + NULL, 0); +} +EXPORT_SYMBOL_GPL(gx_formatter_probe); + +int gx_formatter_create(struct device *dev, + struct snd_soc_dapm_widget *w, + const struct gx_formatter_driver *drv, + struct regmap *regmap) +{ + struct gx_formatter *formatter; + + formatter =3D devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL); + if (!formatter) + return -ENOMEM; + + formatter->drv =3D drv; + formatter->map =3D regmap; + + w->priv =3D formatter; + + return 0; +} +EXPORT_SYMBOL_GPL(gx_formatter_create); + +int gx_stream_start(struct gx_stream *ts) +{ + struct gx_formatter *formatter; + int ret =3D 0; + + mutex_lock(&ts->lock); + + /* Start all the formatters attached to the stream */ + list_for_each_entry(formatter, &ts->formatter_list, list) { + ret =3D gx_formatter_enable(formatter); + if (ret) { + pr_err("failed to enable formatter\n"); + goto out; + } + } + + ts->ready =3D true; + +out: + mutex_unlock(&ts->lock); + return ret; +} +EXPORT_SYMBOL_GPL(gx_stream_start); + +void gx_stream_stop(struct gx_stream *ts) +{ + struct gx_formatter *formatter; + + mutex_lock(&ts->lock); + ts->ready =3D false; + + /* Stop all the formatters attached to the stream */ + list_for_each_entry(formatter, &ts->formatter_list, list) { + gx_formatter_disable(formatter); + } + + mutex_unlock(&ts->lock); +} +EXPORT_SYMBOL_GPL(gx_stream_stop); + +struct gx_stream *gx_stream_alloc(struct gx_iface *iface) +{ + struct gx_stream *ts; + + ts =3D kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts) { + INIT_LIST_HEAD(&ts->formatter_list); + mutex_init(&ts->lock); + ts->iface =3D iface; + } + + return ts; +} +EXPORT_SYMBOL_GPL(gx_stream_alloc); + +void gx_stream_free(struct gx_stream *ts) +{ + /* + * If the list is not empty, it would mean that one of the formatter + * widget is still powered and attached to the interface while we + * are removing the TDM DAI. It should not be possible + */ + WARN_ON(!list_empty(&ts->formatter_list)); + mutex_destroy(&ts->lock); + kfree(ts); +} +EXPORT_SYMBOL_GPL(gx_stream_free); + +MODULE_DESCRIPTION("Amlogic GX formatter driver"); +MODULE_AUTHOR("Valerio Setti "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/meson/gx-formatter.h b/sound/soc/meson/gx-formatter.h new file mode 100644 index 0000000000000000000000000000000000000000..b90b1814d79b49e3e6e5f447016= 1bc1e8bba6ebd --- /dev/null +++ b/sound/soc/meson/gx-formatter.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (c) 2026 Baylibre SAS. + * Author: Valerio Setti + */ + +#ifndef _MESON_GX_FORMATTER_H +#define _MESON_GX_FORMATTER_H + +#include "gx-interface.h" + +struct platform_device; +struct regmap; +struct snd_soc_dapm_widget; +struct snd_kcontrol; + +struct gx_formatter_hw { + unsigned int skew_offset; +}; + +struct gx_formatter_ops { + struct gx_stream *(*get_stream)(struct snd_soc_dapm_widget *w); + void (*enable)(struct regmap *map); + void (*disable)(struct regmap *map); + int (*prepare)(struct regmap *map, + const struct gx_formatter_hw *quirks, + struct gx_stream *ts); +}; + +struct gx_formatter_driver { + const struct snd_soc_component_driver *component_drv; + const struct regmap_config *regmap_cfg; + const struct gx_formatter_ops *ops; + const struct gx_formatter_hw *quirks; +}; + +int gx_formatter_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, + int event); +int gx_formatter_probe(struct platform_device *pdev); + +int gx_formatter_create(struct device *dev, + struct snd_soc_dapm_widget *w, + const struct gx_formatter_driver *drv, + struct regmap *regmap); + +/* + * Formatter data is already freed when the associated device is removed, + * so we just need to remove the pointer from the widget. + */ +static inline void gx_formatter_free(struct snd_soc_dapm_widget *w) +{ + w->priv =3D NULL; +} + +#endif /* _MESON_GX_FORMATTER_H */ diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h new file mode 100644 index 0000000000000000000000000000000000000000..65c46dcce32a8c2d2a95afe3b99= e65e759781a6a --- /dev/null +++ b/sound/soc/meson/gx-interface.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (c) 2026 Baylibre SAS. + * Author: Valerio Setti + */ + +#ifndef _MESON_GX_INTERFACE_H +#define _MESON_GX_INTERFACE_H + +#include +#include +#include +#include +#include + +struct gx_iface { + struct clk *mclk; + unsigned long mclk_rate; + + /* format is common to all the DAIs of the iface */ + unsigned int fmt; + + /* For component wide symmetry */ + int rate; + + /* Only for GX platform */ + int bs_quirk; +}; + +struct gx_stream { + struct gx_iface *iface; + struct list_head formatter_list; + struct mutex lock; + unsigned int channels; + unsigned int width; + unsigned int physical_width; + bool ready; + + /* For continuous clock tracking */ + bool clk_enabled; +}; + +struct gx_stream *gx_stream_alloc(struct gx_iface *iface); +void gx_stream_free(struct gx_stream *ts); +int gx_stream_start(struct gx_stream *ts); +void gx_stream_stop(struct gx_stream *ts); + +#endif /* _MESON_GX_INTERFACE_H */ --=20 2.39.5 From nobody Fri Jun 12 11:31:58 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BAEAC3B52EB for ; Wed, 10 Jun 2026 21:29:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126983; cv=none; b=E4SQu7HK5KMKYAOchhjDkyf/dry1Ri8mZzf3RGPJZtBw0p9EPqyDdyF4ucXvFV/bFmF4p72Cs+dOHEuFuZ5ucPwOveBbMAOIub+NNe7d+CbuDIQTvMW6qQ8en1SVnCtJIKJHLnXRg/gISTTP8tEXWq7baWp26YYU4HP1DkEYf7Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126983; c=relaxed/simple; bh=pgscRYSf0CnocgVAT3NBszrMFG6puvajLA4Nw2Ybqg0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fjEcGwF+3xUixuE7eaA0yb6cmhL9lg6ctHxPFrft3sxgDkA1eYm7g3nu9BDlrc6U9VwFFYIQr9plqTNHoRQvTE1Z+RbsOIzv5wEUo4QFKt+5qoKATuXSMFscu1lNLccf+z5mJlup9BseCLXG05wTPKSr2jSuuIIeZtlOssq5QE4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=KUWVZKD5; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="KUWVZKD5" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-490cf322ed0so32565635e9.1 for ; Wed, 10 Jun 2026 14:29:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1781126980; x=1781731780; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=b5n/WB65Bulk0t5EdzRIcppU+woA0ls1FJjQ79kkwdI=; b=KUWVZKD5L87akKeEKfTTGhJWTaQ0MEJyQFUGlQt97xgCKD4auUlWQjfIuoNGOZPm41 7HjyAOGojnXztjvxD+naW9WVJQEnHAaxQc993ZvsN8zqBbUCmr9iD9NlqDZe/sQc7Zcf DeqWwKiFJpDD4VZf5o12xrVANJHrK5YcctmY7GEgSUCuSBsv84Sb/0cGGWq/mnqSW0df gpI36ms8D3Jz89MfYo7TPX5pbZIY+xDtHPMZ6VA1Zq7mqc711n7QDA7aZOwqWJjOOOp5 0Fj8PJx8kySVTd0Qw7/La906cNCdI+dupHCZzccSy0dt9JZTDcOZ/f555hEAipTF3hb+ 3Ong== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781126980; x=1781731780; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=b5n/WB65Bulk0t5EdzRIcppU+woA0ls1FJjQ79kkwdI=; b=Xv/0KdWZ6Gz4ZNS63ixwwgLc0u1CULT1h6kJPF57rdWwXYi5ddsXoTauGLH7TJz032 Vb9NQKfenEpz/scokrVn4G0h4IkhS6pcB7626Aj92wtGHNe7+1uS/CEMJp27kk+Wsxwp j55TydfulF7OUf3rDwHpLBLynEXgM0krCNj4d8zNy9bqmo/gjv3QcK+7NNAPvzVB4lw9 MXnXXDD8dilvK+eln1SWXIauGyCaiCQcKBxoLMTGVmv8Neh5pvcLHxcegXCdEtbv/Muw 8x7cUeUpkIyfgMCN2iUmLMBMhD8DvIT8oH7jnsvS7mKSqsrwUzA8j0rTo3D4HKn94Lcl /+lA== X-Gm-Message-State: AOJu0Ywtus5BMldwk+14Que+GHzfwxivI/abQdP6yMxNUfF849SlTdrU DV0vQpNBoojiV0/uNflWlKESWFlzAOM4aYLMdjiEMn0D1LXk8oQiGp5oVLo5sSfNpoI= X-Gm-Gg: Acq92OFVQY30kuVFU5CiKJbZ5RMC3i27VfD5JwuTNPxVZt7kRHH3KgJuoGLoeIXDeKp qknIBwkNz2zjBmHPCkZAAvx45zF/ganD8Wfb0tdYpkjgrthCcoXoyOmzdmb+lwdVaQtuMpV7aPq +aTWGHlsRNyKsLtVZUYe2czccJVw6wr8Dckr84HHcilHL/6fdTXfBppwh05n9h/vQ5Xp1o3Sfg9 z+186ExzcYmNcijQCgp5I/FlXs/h8D2OKJBS7JBCCW2DA1qr71sHXYJkyZ+d2wc7XMyLhEU9MJ3 53NQtHIH5lWv5QLLWNlYf2IES+Ain35M7mp4geKUZEa/7KYvUCR9pwCsLhqbReE0Eut3uYey2Ub 0UgIgPBkw/3bWVFKqHi1b/fAbvyzsLwLg3XC2RnSZaCxARYy250opyQw9j7eePaQ0ZXTjv5hmsp kmw0GNJolcIFPugaLkbanLogYipPUz468= X-Received: by 2002:a05:600c:6087:b0:48a:8b02:ae91 with SMTP id 5b1f17b1804b1-490c25b0231mr457881835e9.11.1781126980260; Wed, 10 Jun 2026 14:29:40 -0700 (PDT) Received: from [127.0.1.1] ([151.61.238.34]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490e4228768sm970965e9.0.2026.06.10.14.29.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Jun 2026 14:29:39 -0700 (PDT) From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:26 +0200 Subject: [PATCH v2 2/4] ASoC: meson: aiu-encoder-i2s: prepare for multiple streams Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260610-reshape-aiu-as-axg-v2-2-cac3663a8b51@baylibre.com> References: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> In-Reply-To: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> To: Jerome Brunet , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Neil Armstrong , Kevin Hilman , Martin Blumenstingl Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-amlogic@lists.infradead.org, Valerio Setti X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=11845; i=vsetti@baylibre.com; h=from:subject:message-id; bh=pgscRYSf0CnocgVAT3NBszrMFG6puvajLA4Nw2Ybqg0=; b=owGbwMvMwCF2z3ty7kUrRgbG02pJDFma1x02TC8IZFvQdb8z83t6V+eau8YT+x0X8e1X3xB0W HGns29oRykLgxgHg6yYIgvL9Hu/C0rVHhonnCyAmcPKBDKEgYtTACay/yrD/yR5g+UKK3f6POQs ldu/eMcTyQCPqh96qc65eZbX/2Wx1jAyXHn650n6esN/v7RN9LL6L8zVtrD9scFfet367wemJnr eZgUA X-Developer-Key: i=vsetti@baylibre.com; a=openpgp; fpr=0497DEFB707526E13360C970DE4B936DD13A0100 aiu-encoder-i2s is going to be the interface that handles both playback and capture, so this commit does all the required changes to prepare for that since so far it only handled playback: - probe/remove functions are added to allocate/free per stream data, respectively. - 'struc gx_iface' and 'struct gx_stream' are used to store interface or stream associated data, respecively. - interface wide rate symmetry is enforced. - quirks on bclk are also enforced if/when necessary. Clock-wise instead of bulk enabling all the clocks on startup and disabling them on shutdown, only the peripheral's internal ones are enabled/disabled in those functions, whereas MCLK and I2S clock divider are handled in prepare/hw_free. Finally a trigger() callback is also added to start/stop the associated I2S data formatter. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet --- sound/soc/meson/aiu-encoder-i2s.c | 207 ++++++++++++++++++++++++++++++++++= ---- sound/soc/meson/aiu.h | 3 + 2 files changed, 193 insertions(+), 17 deletions(-) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encode= r-i2s.c index 3b4061508c18047fe8d6f3f98061720f8ce238f2..f50b03824ad280afabb31eecc20= ccb855defa11e 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -10,6 +10,8 @@ #include =20 #include "aiu.h" +#include "gx-formatter.h" +#include "gx-interface.h" =20 #define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) #define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) @@ -112,6 +114,9 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_= component *component, struct snd_pcm_hw_params *params, unsigned int bs) { + struct aiu *aiu =3D snd_soc_component_get_drvdata(component); + struct gx_iface *iface =3D &aiu->i2s.iface; + /* * NOTE: this HW is odd. * In most configuration, the i2s divider is 'mclk / blck'. @@ -126,6 +131,18 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc= _component *component, return -EINVAL; } bs +=3D bs / 2; + iface->bs_quirk =3D true; + } else { + /* + * If the bs quirk is currently applied for one stream and another + * ones tries to setup a configuration for which the quirk is + * not required, then fail. + */ + if (iface->bs_quirk) { + dev_err(component->dev, + "bclk requirements are incompatible with active stream\n"); + return -EINVAL; + } } =20 /* Use CLK_MORE for mclk to bclk divider */ @@ -145,14 +162,15 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_= component *component, struct snd_pcm_hw_params *params) { struct aiu *aiu =3D snd_soc_component_get_drvdata(component); + struct gx_iface *iface =3D &aiu->i2s.iface; unsigned int srate =3D params_rate(params); unsigned int fs, bs; int ret; =20 /* Get the oversampling factor */ - fs =3D DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate); + fs =3D DIV_ROUND_CLOSEST(iface->mclk_rate, srate); =20 - if (fs % 64) + if ((fs % 64) || (fs =3D=3D 0)) return -EINVAL; =20 /* Send data MSB first */ @@ -188,24 +206,59 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_s= ubstream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct gx_stream *ts =3D snd_soc_dai_get_dma_data(dai, substream); + struct gx_iface *iface =3D ts->iface; struct snd_soc_component *component =3D dai->component; int ret; =20 - /* Disable the clock while changing the settings */ - aiu_encoder_i2s_divider_enable(component, false); + /* + * Enforce interface wide rate symmetry only if there is more than + * 1 stream active. + */ + if (snd_soc_dai_active(dai) > 1) { + if (iface->rate && iface->rate !=3D params_rate(params)) { + dev_err(dai->dev, "can't set iface rate (%d !=3D %d)\n", + iface->rate, params_rate(params)); + return -EINVAL; + } + } =20 ret =3D aiu_encoder_i2s_setup_desc(component, params); if (ret) { - dev_err(dai->dev, "setting i2s desc failed\n"); + dev_err(dai->dev, "setting i2s desc failed: %d\n", ret); return ret; } =20 ret =3D aiu_encoder_i2s_set_clocks(component, params); if (ret) { - dev_err(dai->dev, "setting i2s clocks failed\n"); + dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); return ret; } =20 + iface->rate =3D params_rate(params); + ts->physical_width =3D params_physical_width(params); + ts->width =3D params_width(params); + ts->channels =3D params_channels(params); + + return 0; +} + +static int aiu_encoder_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct gx_stream *ts =3D snd_soc_dai_get_dma_data(dai, substream); + struct snd_soc_component *component =3D dai->component; + int ret; + + if (ts->clk_enabled) + return 0; + + ret =3D clk_prepare_enable(ts->iface->mclk); + if (ret) + return ret; + + ts->clk_enabled =3D true; + aiu_encoder_i2s_divider_enable(component, true); =20 return 0; @@ -214,9 +267,24 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_su= bstream *substream, static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct gx_stream *ts =3D snd_soc_dai_get_dma_data(dai, substream); + struct gx_iface *iface =3D ts->iface; struct snd_soc_component *component =3D dai->component; =20 - aiu_encoder_i2s_divider_enable(component, false); + /* + * If this is the last substream being closed then disable the i2s + * clock divider and clear 'iface->rate'. + */ + if (snd_soc_dai_active(dai) <=3D 1) { + aiu_encoder_i2s_divider_enable(component, 0); + iface->rate =3D 0; + iface->bs_quirk =3D false; + } + + if (ts->clk_enabled) { + clk_disable_unprepare(ts->iface->mclk); + ts->clk_enabled =3D false; + } =20 return 0; } @@ -224,6 +292,8 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_subst= ream *substream, static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int f= mt) { struct snd_soc_component *component =3D dai->component; + struct aiu *aiu =3D snd_soc_component_get_drvdata(component); + struct gx_iface *iface =3D &aiu->i2s.iface; unsigned int inv =3D fmt & SND_SOC_DAIFMT_INV_MASK; unsigned int val =3D 0; unsigned int skew; @@ -255,9 +325,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai = *dai, unsigned int fmt) skew =3D 0; break; default: + dev_err(dai->dev, "unsupported dai format\n"); return -EINVAL; } =20 + iface->fmt =3D fmt; + val |=3D FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew); snd_soc_component_update_bits(component, AIU_CLK_CTRL, AIU_CLK_CTRL_LRCLK_INVERT | @@ -272,6 +345,7 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_da= i *dai, int clk_id, unsigned int freq, int dir) { struct aiu *aiu =3D snd_soc_component_get_drvdata(dai->component); + struct gx_iface *iface =3D &aiu->i2s.iface; int ret; =20 if (WARN_ON(clk_id !=3D 0)) @@ -280,11 +354,15 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_= dai *dai, int clk_id, if (dir =3D=3D SND_SOC_CLOCK_IN) return 0; =20 - ret =3D clk_set_rate(aiu->i2s.clks[MCLK].clk, freq); - if (ret) - dev_err(dai->dev, "Failed to set sysclk to %uHz", freq); + ret =3D clk_set_rate(iface->mclk, freq); + if (ret) { + dev_err(dai->dev, "Failed to set sysclk to %uHz: %d", freq, ret); + return ret; + } =20 - return ret; + iface->mclk_rate =3D freq; + + return 0; } =20 static const unsigned int hw_channels[] =3D {2, 8}; @@ -305,15 +383,35 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_sub= stream *substream, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_channel_constraints); if (ret) { - dev_err(dai->dev, "adding channels constraints failed\n"); + dev_err(dai->dev, "adding channels constraints failed: %d\n", ret); return ret; } =20 - ret =3D clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks); - if (ret) - dev_err(dai->dev, "failed to enable i2s clocks\n"); + /* + * Enable only clocks which are required for the interface internal + * logic. MCLK is enabled/disabled from the formatter and the I2S + * divider is enabled/disabled in "hw_params"/"hw_free", respectively. + */ + ret =3D clk_prepare_enable(aiu->i2s.clks[PCLK].clk); + if (ret) { + dev_err(dai->dev, "failed to enable PCLK: %d\n", ret); + return ret; + } + ret =3D clk_prepare_enable(aiu->i2s.clks[MIXER].clk); + if (ret) { + dev_err(dai->dev, "failed to enable MIXER: %d\n", ret); + clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); + return ret; + } + ret =3D clk_prepare_enable(aiu->i2s.clks[AOCLK].clk); + if (ret) { + dev_err(dai->dev, "failed to enable AOCLK: %d\n", ret); + clk_disable_unprepare(aiu->i2s.clks[MIXER].clk); + clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); + return ret; + } =20 - return ret; + return 0; } =20 static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream, @@ -321,14 +419,89 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_s= ubstream *substream, { struct aiu *aiu =3D snd_soc_component_get_drvdata(dai->component); =20 - clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks); + clk_disable_unprepare(aiu->i2s.clks[AOCLK].clk); + clk_disable_unprepare(aiu->i2s.clks[MIXER].clk); + clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); +} + +static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + struct gx_stream *ts =3D snd_soc_dai_get_dma_data(dai, substream); + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret =3D gx_stream_start(ts); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + gx_stream_stop(ts); + ret =3D 0; + break; + default: + ret =3D -EINVAL; + } + + return ret; +} + +static int aiu_encoder_i2s_remove_dai(struct snd_soc_dai *dai) +{ + int stream; + + for_each_pcm_streams(stream) { + struct gx_stream *ts; + + ts =3D snd_soc_dai_dma_data_get(dai, stream); + if (ts) + gx_stream_free(ts); + + snd_soc_dai_dma_data_set(dai, stream, NULL); + } + + return 0; +} + +static int aiu_encoder_i2s_probe_dai(struct snd_soc_dai *dai) +{ + struct aiu *aiu =3D snd_soc_dai_get_drvdata(dai); + struct gx_iface *iface =3D &aiu->i2s.iface; + int stream; + + for_each_pcm_streams(stream) { + struct gx_stream *ts; + + if (!snd_soc_dai_get_widget(dai, stream)) + continue; + + ts =3D gx_stream_alloc(iface); + if (!ts) { + aiu_encoder_i2s_remove_dai(dai); + return -ENOMEM; + } + snd_soc_dai_dma_data_set(dai, stream, ts); + } + + iface->mclk =3D aiu->i2s.clks[MCLK].clk; + iface->mclk_rate =3D clk_get_rate(iface->mclk); + + return 0; } =20 const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops =3D { + .probe =3D aiu_encoder_i2s_probe_dai, + .remove =3D aiu_encoder_i2s_remove_dai, .hw_params =3D aiu_encoder_i2s_hw_params, + .prepare =3D aiu_encoder_i2s_prepare, .hw_free =3D aiu_encoder_i2s_hw_free, .set_fmt =3D aiu_encoder_i2s_set_fmt, .set_sysclk =3D aiu_encoder_i2s_set_sysclk, .startup =3D aiu_encoder_i2s_startup, .shutdown =3D aiu_encoder_i2s_shutdown, + .trigger =3D aiu_encoder_i2s_trigger, }; diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h index 0f94c8bf608181112d78402532b832eb50c2d409..68310de0bdf7a97d8de2ff306c1= 59248ee9b0ede 100644 --- a/sound/soc/meson/aiu.h +++ b/sound/soc/meson/aiu.h @@ -7,6 +7,8 @@ #ifndef _MESON_AIU_H #define _MESON_AIU_H =20 +#include "gx-formatter.h" + struct clk; struct clk_bulk_data; struct device; @@ -25,6 +27,7 @@ struct aiu_interface { struct clk_bulk_data *clks; unsigned int clk_num; int irq; + struct gx_iface iface; }; =20 struct aiu_platform_data { --=20 2.39.5 From nobody Fri Jun 12 11:31:58 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B8CA23BADB1 for ; Wed, 10 Jun 2026 21:29:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126984; cv=none; b=r2qkXz6DbtBO2Dv0yMiqj4fc7fj+V7mVEJoH4SXyAVi4X+0GDad87mm+ltDjfv+/noBU2RopmNGunzZVXJQxLsAOwmns1JF/g8pV0iZG6lvztxzcnqrufVjCgWor4eBxDKHq78KquN1rXeFm45Vq0Y0ckb3wsNs8TTTR2VcUrCY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126984; c=relaxed/simple; bh=1AVgdXapivwMhAZ343GX8lNmX+kCIj8zw6th//wHOqE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gVg1o92yyG0Spkk2INNWUkN7vC86xSScBCfS5DXzhIKxjRU/k+T5FH85VxX4jL93uFgFmXub1kvYJwS4oAzg1uo7f991C6Fs8hxO1X4QtNI5DPA4y3jEP+UCWaz893yGPkRnYkYC2p2txSFLE68cMTC9mdSXBzIT2ADzefUGK0E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=hyDIdfDc; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="hyDIdfDc" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-490cf322ed0so32565725e9.1 for ; Wed, 10 Jun 2026 14:29:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1781126981; x=1781731781; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=1wcd9+cR2Lw/1NK825QM1reyVrOzsO3D1IfFbzXKQDk=; b=hyDIdfDcLVvEbW4UrtYk6CZ11cmHpbEPeX8YgemXEXUNm7B5ImejrIhCaRfNrnKA0R 4/2KZhYIT1IEdsp2l5bhwej9UZ4QBo79ZzBxfgWWDdt2MsTCM9mYF4/0PGJakMZ0+etY cmfTF5P2whlmKTwdV9/k+9U44utYkrUUGW1pAiAy1Kfgh9FyAv61DHIpHbH1wHaL8zPI Pj/aJMuLBn7dTbwQGHFa4507/Ru1Bqw6PBU3LFvI2CXsFLePOlHzRkEKRULvmk+rqCOK Z7nbBioJ2ydQZy/QiRpweHjzQdQnzuju8iUR9OKJkRZGA/qSZmiomO+RAz7uVTKpP00r GyKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781126981; x=1781731781; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=1wcd9+cR2Lw/1NK825QM1reyVrOzsO3D1IfFbzXKQDk=; b=EVfINAfO8XdZNPdVxFftQ+iaqjawFckh2sR0cZ8QG5ZxISQArgSm3wscNWgnC/8lrG T4MvAT2I0kptkHTFOis0wMtDWqkmJYIwwVVKqOv3brXl9yEV/o2lx8LgK2D2yuHD5ea0 5OJVhuYajjbuw1JZTe346VgxVVWLZQSpRcPTVZF8SqVw1SdSXBp2bCNwKVa9kxYUCT2r Ere1UwIlZU755RPGJsRCdTjaj4svnV6loo0y5oaFsvuiVaQhD7vd9GsWEyufeRzbBZES aPpJlCKATuM/2oRpCIZUv/AQe+rx8zfRLZDggYz1wNu9XLnYA3Yxy3uPy4vQ6336oOv0 2ltw== X-Gm-Message-State: AOJu0YwgsaucYBugsOAgfquQPs50dlzQZP0oyvfgXXU9why8sw+R9GPW LXhnDj4UbMbb3XXShX7F8E8TQL1CmWt1cOJ9/an//TvjuLvg8jsF1HzYjR/ug/bAwaA= X-Gm-Gg: Acq92OFWEH5iJmVCzW/3wvvJwR0RR68z+u6IlMcaJTQzQAURreysM1coeah2BCueHD+ R1ydXGP/eycWynZ79haz4E6XHcOvWz8cYoNqLxZLhQTsp2/ECdrB5osmmY4Ez07bhKsEhXElaCd gEXr7lxpoJe4wQza+FpeJ7lCjpBqQDAZpLp/gdZ9u3wdnA3iAx5WLim5yBoc28uYeXK3DmA0liT 8d0Yq9aFPfzcu3GMzvYuOsBRk4QLAArGmSjgE0/N33Mja109Cx8BaimUzizVVu1EcVaCW3r5e8e Oob7mE6uWlF767i3DdSC84EdKSitZpsoSaEJ8iqSLi/myYjLpm57NBPVhXnU++lBp65JbmiCKf8 7MuJTzzfKgubf3sfjrFEfutre2IxeaUgGM58jwo4oPbZaej/8bn4MDMqHsBNCX98Efhxae8hwO3 6jwL1PiynExYgIKVR21SVt5PNudz9h5ZmZ0249pDdAtA== X-Received: by 2002:a05:600c:1f83:b0:490:b724:5085 with SMTP id 5b1f17b1804b1-490c2621a5cmr438401955e9.33.1781126981257; Wed, 10 Jun 2026 14:29:41 -0700 (PDT) Received: from [127.0.1.1] ([151.61.238.34]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490e4228768sm970965e9.0.2026.06.10.14.29.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Jun 2026 14:29:40 -0700 (PDT) From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:27 +0200 Subject: [PATCH v2 3/4] ASoC: meson: aiu: introduce I2S output formatter Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260610-reshape-aiu-as-axg-v2-3-cac3663a8b51@baylibre.com> References: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> In-Reply-To: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> To: Jerome Brunet , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Neil Armstrong , Kevin Hilman , Martin Blumenstingl Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-amlogic@lists.infradead.org, Valerio Setti X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4373; i=vsetti@baylibre.com; h=from:subject:message-id; bh=1AVgdXapivwMhAZ343GX8lNmX+kCIj8zw6th//wHOqE=; b=owGbwMvMwCF2z3ty7kUrRgbG02pJDFma1x1ePSnd+f7CXK14q9JTSbxRaod51PSMRfyvXwktf vji6EvfjlIWBjEOBlkxRRaW6fd+F5SqPTROOFkAM4eVCWQIAxenAExkxkKG/zF6VifmBpzlkO6s 8ijzNUq1Tgrem7vTZ5OM5hGJ6LVZjAx/eP/+0Hc0Lo466hPUnpKyXyPg0Nf83a2c1Z+uHf3/+tx xfgA= X-Developer-Key: i=vsetti@baylibre.com; a=openpgp; fpr=0497DEFB707526E13360C970DE4B936DD13A0100 Introduce aiu-formatter-i2s, a gx_formatter implementation for the AIU I2S playback path. This is going to replace data formatting tasks that are currently being implemented in aiu-encoder-i2s. This should ideally follow the same design pattern used on the AXG platform (see axg-tdmout), where basically the widget/formatter corresponds to a single audio component. This is not possible in the GX platform though because all the features are currently implemented in the AIU audio component and changing that would require backward incompatible device-tree changes. Therefore aiu-formatter-i2s is kept very simple and it only implements the bare minimum functionalities to provide I2S playback formatting. It's not a standalone component though because this is still belongs to AIU. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet --- sound/soc/meson/Makefile | 1 + sound/soc/meson/aiu-formatter-i2s.c | 104 ++++++++++++++++++++++++++++++++= ++++ 2 files changed, 105 insertions(+) diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index 146ec81526ba091a174a113ce3d8412ddbbfd9dd..f9ec0ebb01f048728b8f85fd8e5= 8fb90df990470 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -5,6 +5,7 @@ snd-soc-meson-aiu-y +=3D aiu-acodec-ctrl.o snd-soc-meson-aiu-y +=3D aiu-codec-ctrl.o snd-soc-meson-aiu-y +=3D aiu-encoder-i2s.o snd-soc-meson-aiu-y +=3D gx-formatter.o +snd-soc-meson-aiu-y +=3D aiu-formatter-i2s.o snd-soc-meson-aiu-y +=3D aiu-encoder-spdif.o snd-soc-meson-aiu-y +=3D aiu-fifo.o snd-soc-meson-aiu-y +=3D aiu-fifo-i2s.o diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-form= atter-i2s.c new file mode 100644 index 0000000000000000000000000000000000000000..b4604734fe88da2acd6e5c2f9f5= 9e8ecb0a017a5 --- /dev/null +++ b/sound/soc/meson/aiu-formatter-i2s.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2026 BayLibre, SAS. +// Author: Valerio Setti + +#include +#include +#include + +#include "aiu.h" +#include "gx-formatter.h" + +#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) +#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) +#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) +#define AIU_RST_SOFT_I2S_FAST BIT(0) + +#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) + +static struct snd_soc_dai * +aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dai *be; + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + if (!p->connect) + continue; + + if (p->sink->id =3D=3D snd_soc_dapm_dai_in) + return (struct snd_soc_dai *)p->sink->priv; + + be =3D aiu_formatter_i2s_get_be(p->sink); + if (be) + return be; + } + + return NULL; +} + +static struct gx_stream * +aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dai *be =3D aiu_formatter_i2s_get_be(w); + + if (!be) + return NULL; + + return snd_soc_dai_dma_data_get_playback(be); +} + +static int aiu_formatter_i2s_prepare(struct regmap *map, + const struct gx_formatter_hw *quirks, + struct gx_stream *ts) +{ + /* Always operate in split (classic interleaved) mode */ + unsigned int desc =3D 0; + unsigned int tmp; + + /* Reset required to update the pipeline */ + regmap_write(map, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST); + regmap_read(map, AIU_I2S_SYNC, &tmp); + + switch (ts->physical_width) { + case 16: /* Nothing to do */ + break; + + case 32: + desc |=3D (AIU_I2S_SOURCE_DESC_MODE_24BIT | + AIU_I2S_SOURCE_DESC_MODE_32BIT); + break; + + default: + return -EINVAL; + } + + switch (ts->channels) { + case 2: /* Nothing to do */ + break; + case 8: + desc |=3D AIU_I2S_SOURCE_DESC_MODE_8CH; + break; + default: + return -EINVAL; + } + + regmap_update_bits(map, AIU_I2S_SOURCE_DESC, + AIU_I2S_SOURCE_DESC_MODE_8CH | + AIU_I2S_SOURCE_DESC_MODE_24BIT | + AIU_I2S_SOURCE_DESC_MODE_32BIT, + desc); + + /* Send data MSB first */ + regmap_update_bits(map, AIU_I2S_DAC_CFG, + AIU_I2S_DAC_CFG_MSB_FIRST, + AIU_I2S_DAC_CFG_MSB_FIRST); + + return 0; +} + +const struct gx_formatter_ops aiu_formatter_i2s_ops =3D { + .get_stream =3D aiu_formatter_i2s_get_stream, + .prepare =3D aiu_formatter_i2s_prepare, +}; --=20 2.39.5 From nobody Fri Jun 12 11:31:58 2026 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D05FD3BBFC1 for ; Wed, 10 Jun 2026 21:29:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126985; cv=none; b=T0PmW6DzNgw9R82SLk2krUW6ft55tDUUYbPAt+8UHjpVKTwfOOdDV2k1cDbX3vduLY1xuszbdX992wgrxOBN+YWQBDHRZC8bc4WWr9GCLpakd3saBZv7C8vmAE3tgAqv3akdTYJbNIrUj+RteqkR9mw/pYnd6uUecqHFjgkKn0I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781126985; c=relaxed/simple; bh=/h2Td7mUr6sv6XUhWr9Xcq7WvMFZwzP575T2baPy/Ds=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ne6v0nLY3/BucaSzfiLvh2cIp1Uy5/irJ11eMpVGU4T7hPeBxhNjbQ+kJsk6A9cSXGabs+dnJPD1a9O8g7ZXMyigDvmKDEmrEoi8LEdOWrdH2+epetuhXzXISgkSe505K4SLsoOLBMNIKRNd412a8VqjW3ngUIxNiz8mmdBDg/0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=pLzxiZ1F; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="pLzxiZ1F" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-490cf3000f0so46388735e9.1 for ; Wed, 10 Jun 2026 14:29:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1781126982; x=1781731782; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=HdSvP4OsE7eHoTjId0UaG2CyxblqVBvzSM5Fo0qLTpA=; b=pLzxiZ1FiM7CUp6dubACI08KMSSgsoshkZFfkl86LGoGBWcfnvsiYH+SiUc3QwmuhA EyhfZ0Bpk//pfwPopaBTVsVPyjiwGdgS+nVeS9x30FZd83Jzwb/kaO2w0wREBGreEyh+ 8Yv5x5CRzANUdld5pfczlkZ0y4i8JvOjyuJkqnYX6/KvUq1QhtLquLVVRbDTK2oLdjOg kG3/QxtFfP6ObPdyRBlMhXT3z1GtMbKApFf/bs7RlkEhTFD7AAEUTFlF+5lNJfVKUhLI K8AJndctsUarFFdcZoebKNI8o5OmwuHrGDiuMW69n2oBM7ytkN2EGD4IwctkgbVoCvF9 cTtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781126982; x=1781731782; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=HdSvP4OsE7eHoTjId0UaG2CyxblqVBvzSM5Fo0qLTpA=; b=YS0TiuqnNrvL8te+R9QXdzdUqVtEMV1BQanLYY7WicP/GQTn9g03H6kYxt5tHcrtRt FHF5dSns9uwMj928EDdsl0Xaka5zx7qGoy/p8tOPVce+B0UqUVC16lv+sGIGOXlsLrYF 5iQt4NnAf7zydgRCSnnI1B69rlSTS15AIG8LJTrRPlwZEO4r3DwBwMpO1bRAPsv63Qg6 K19Y3azDL36CQtWtoCfDsrRQZOSFO0/gv4OH3ZKnGulV/O9iMr0b7n8lE5fdqClGGH49 t/6+scRvr3JR05t6zC6YqrwI9Y5SCtc6l4GjCFn9uf6Q5zNtl767IjY2lDhFZwNKidxz wHcw== X-Gm-Message-State: AOJu0YzKlq7qr9/brCOXXZqWu+vAQLFdOaB2ZE1VzM/+8BeKCZ4Q0TXm /V+yw3kTQEdW2xG2Il5Gbt1hylkjHERFBlVq2+nmA092XStv/3EsBc1WFgpUKlJrMeg= X-Gm-Gg: Acq92OGFA9G+0O8CpbFlctkglu8eZYM8kJCkGo1f1t0NTB1NELGUTzk/Sh2AtpKx2pB uHIMm1yZ06srj2StW5jwy8gBoN6nJjD+eaCRNbnPPUOpFYra2sfgkw4cjbTaDpv5upvt7FHosg1 YsIlZR8WwUCiswiDaXpIEuKEP6m5TM9tHgf5LPGi2hbt1g4um1a46OjGUETNCAXYOHdC29yT0sG Um60xLlNcQONEM3oNOxxvHY+b5Tq4Aur2KpgaS8+qtIyOHjlI0NTC6O/anHGT33u9jRVSmZi2n+ e1gd4ZWHo2M8edZaqcFGfEyxpfGMbBG0QNcoos1x7pAWMuzuaPHU/U/TYQ9eog33D8Q3294+IGe KwFmykHmPrPwErbRW6iCRDNvRSC1fWBo+Nk7lD6mYqD2xehmgpfavLi+GKK0RcT10jmbgCthZ0C 8mG0jKN5uVq5rVnQXWPdGLu2OmIlJ3qQnjrOfBEyaeAw== X-Received: by 2002:a05:600d:6446:10b0:490:bccf:2bd6 with SMTP id 5b1f17b1804b1-490e2e29494mr5787235e9.15.1781126982292; Wed, 10 Jun 2026 14:29:42 -0700 (PDT) Received: from [127.0.1.1] ([151.61.238.34]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490e4228768sm970965e9.0.2026.06.10.14.29.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Jun 2026 14:29:42 -0700 (PDT) From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:28 +0200 Subject: [PATCH v2 4/4] ASoC: meson: aiu: use aiu-formatter-i2s to format I2S output data Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260610-reshape-aiu-as-axg-v2-4-cac3663a8b51@baylibre.com> References: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> In-Reply-To: <20260610-reshape-aiu-as-axg-v2-0-cac3663a8b51@baylibre.com> To: Jerome Brunet , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Neil Armstrong , Kevin Hilman , Martin Blumenstingl Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-amlogic@lists.infradead.org, Valerio Setti X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7991; i=vsetti@baylibre.com; h=from:subject:message-id; bh=/h2Td7mUr6sv6XUhWr9Xcq7WvMFZwzP575T2baPy/Ds=; b=owGbwMvMwCF2z3ty7kUrRgbG02pJDFma1x2COF5w1rWmPDvsyMu7KsxGbZuhj/f+yfwLelrq7 h1c9EW/o5SFQYyDQVZMkYVl+r3fBaVqD40TThbAzGFlAhnCwMUpABNpiWZkOLL1F/sOzeA12y7O z9z7PX6yvM9SM9bah3v5/Trsz2qfKGP4yfj1WP1cjlLvYotjP4/t5ZmXwx95fHka1zPrNy1bWA4 ZMAMA X-Developer-Key: i=vsetti@baylibre.com; a=openpgp; fpr=0497DEFB707526E13360C970DE4B936DD13A0100 Create a new DAPM widget for "I2S formatter" and place it on the path between FIFO and output DAI interface. Remove I2S output formatting code from aiu-encoder-i2s since it's now implemented from aiu-formatter-i2s. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet --- sound/soc/meson/aiu-encoder-i2s.c | 78 ++++++++++-------------------------= ---- sound/soc/meson/aiu.c | 32 ++++++++++++++-- sound/soc/meson/aiu.h | 1 + 3 files changed, 48 insertions(+), 63 deletions(-) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encode= r-i2s.c index f50b03824ad280afabb31eecc20ccb855defa11e..83b579e98f1c75ce03fea1c6ff4= e99b2fedebe0c 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -13,13 +13,8 @@ #include "gx-formatter.h" #include "gx-interface.h" =20 -#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) -#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) -#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) #define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11) -#define AIU_RST_SOFT_I2S_FAST BIT(0) =20 -#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) #define AIU_CLK_CTRL_I2S_DIV_EN BIT(0) #define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2) #define AIU_CLK_CTRL_AOCLK_INVERT BIT(6) @@ -37,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_so= c_component *component, enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0); } =20 -static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component, - struct snd_pcm_hw_params *params) -{ - /* Always operate in split (classic interleaved) mode */ - unsigned int desc =3D AIU_I2S_SOURCE_DESC_MODE_SPLIT; - - /* Reset required to update the pipeline */ - snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST); - snd_soc_component_read(component, AIU_I2S_SYNC); - - switch (params_physical_width(params)) { - case 16: /* Nothing to do */ - break; - - case 32: - desc |=3D (AIU_I2S_SOURCE_DESC_MODE_24BIT | - AIU_I2S_SOURCE_DESC_MODE_32BIT); - break; - - default: - return -EINVAL; - } - - switch (params_channels(params)) { - case 2: /* Nothing to do */ - break; - case 8: - desc |=3D AIU_I2S_SOURCE_DESC_MODE_8CH; - break; - default: - return -EINVAL; - } - - snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC, - AIU_I2S_SOURCE_DESC_MODE_8CH | - AIU_I2S_SOURCE_DESC_MODE_24BIT | - AIU_I2S_SOURCE_DESC_MODE_32BIT | - AIU_I2S_SOURCE_DESC_MODE_SPLIT, - desc); - - return 0; -} - static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *compon= ent, struct snd_pcm_hw_params *params, unsigned int bs) @@ -173,11 +125,6 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_c= omponent *component, if ((fs % 64) || (fs =3D=3D 0)) return -EINVAL; =20 - /* Send data MSB first */ - snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG, - AIU_I2S_DAC_CFG_MSB_FIRST, - AIU_I2S_DAC_CFG_MSB_FIRST); - /* Set bclk to lrlck ratio */ snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL, AIU_CODEC_DAC_LRCLK_CTRL_DIV, @@ -223,12 +170,6 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_su= bstream *substream, } } =20 - ret =3D aiu_encoder_i2s_setup_desc(component, params); - if (ret) { - dev_err(dai->dev, "setting i2s desc failed: %d\n", ret); - return ret; - } - ret =3D aiu_encoder_i2s_set_clocks(component, params); if (ret) { dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); @@ -411,6 +352,25 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_subs= tream *substream, return ret; } =20 + /* + * We're always operating in split mode for the playback stream. + * + * This setting arguably belong to the 'aiu-formatter', but it's kept + * here for backward compatibility reason. At reset the I2S encoder + * operates in normal mode which would only support 8ch, but by default + * only 2ch are enabled. If a playback stream is started without + * changing to split mode, then the I2S encoder doesn't consume audio + * samples and the playback fails. + * Moving this to 'aiu-formatter' would cause the split mode to be set + * only when the formatter is enabled, which doesn't happen at boot as + * the default value for "HDMI CTRL SRC" is "DISABLED". + */ + ret =3D snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC, + AIU_I2S_SOURCE_DESC_MODE_SPLIT, + AIU_I2S_SOURCE_DESC_MODE_SPLIT); + if (ret < 0) + dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret); + return 0; } =20 diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index f2890111c1d2cfa2213bf01849957a796744b9ae..64ace4d25d92cbe137066359a83= 9e1b11bf140f8 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, = AIU_I2S_MISC, static const struct snd_kcontrol_new aiu_spdif_encode_mux =3D SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum); =20 -static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] =3D { - SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0, - &aiu_spdif_encode_mux), +#define AIU_WIDGET_SPDIF_SRC_SEL 0 +#define AIU_WIDGET_I2S_FORMATTER 1 + +static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] =3D { + [AIU_WIDGET_SPDIF_SRC_SEL] =3D + SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0, + &aiu_spdif_encode_mux), + [AIU_WIDGET_I2S_FORMATTER] =3D + SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0, + gx_formatter_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), }; =20 static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] =3D { - { "I2S Encoder Playback", NULL, "I2S FIFO Playback" }, + { "I2S Formatter", NULL, "I2S FIFO Playback" }, + { "I2S Encoder Playback", NULL, "I2S Formatter" }, { "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" }, { "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" }, { "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" }, @@ -172,6 +181,11 @@ static const struct regmap_config aiu_regmap_cfg =3D { .max_register =3D 0x2ac, }; =20 +const struct gx_formatter_driver aiu_formatter_i2s_drv =3D { + .regmap_cfg =3D &aiu_regmap_cfg, + .ops =3D &aiu_formatter_i2s_ops, +}; + static int aiu_clk_bulk_get(struct device *dev, const char * const *ids, unsigned int num, @@ -282,6 +296,14 @@ static int aiu_probe(struct platform_device *pdev) if (ret) return ret; =20 + /* Allocate the aiu-formatter into its widget */ + ret =3D gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FOR= MATTER], + &aiu_formatter_i2s_drv, map); + if (ret) { + dev_err(dev, "Failed to allocate aiu formatter\n"); + goto err; + } + /* Register the cpu component of the aiu */ ret =3D snd_soc_register_component(dev, &aiu_cpu_component, aiu_cpu_dai_drv, @@ -310,12 +332,14 @@ static int aiu_probe(struct platform_device *pdev) =20 return 0; err: + gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]); snd_soc_unregister_component(dev); return ret; } =20 static void aiu_remove(struct platform_device *pdev) { + gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]); snd_soc_unregister_component(&pdev->dev); } =20 diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h index 68310de0bdf7a97d8de2ff306c159248ee9b0ede..7d0b98c1f351b3c526ca06c43a4= c04ee5f4b6dfa 100644 --- a/sound/soc/meson/aiu.h +++ b/sound/soc/meson/aiu.h @@ -61,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops; extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops; extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops; extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops; +extern const struct gx_formatter_ops aiu_formatter_i2s_ops; =20 #define AIU_IEC958_BPF 0x000 #define AIU_958_MISC 0x010 --=20 2.39.5