* [PATCH 06/16] ASoC: twl4030-codec: Allow setting APLL rate through the .set_sysclk() interface
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Grond <grond66@riseup.net>
On the Pandora, the APLL is actually what drives all of the audio clocks on
the board. Since the TWL4030 is only used for capture, we need some way of
setting the correct rate for playback streams, since they will not go
through the TWL4030's .hw_params() code path (which is normally how APLL
rate is set).
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
include/linux/mfd/twl4030-audio.h | 3 +
sound/soc/codecs/twl4030.c | 140 +++++++++++++++++++++---------
2 files changed, 101 insertions(+), 42 deletions(-)
diff --git a/include/linux/mfd/twl4030-audio.h b/include/linux/mfd/twl4030-audio.h
index 1c28605dfda80..4378eef97b0fc 100644
--- a/include/linux/mfd/twl4030-audio.h
+++ b/include/linux/mfd/twl4030-audio.h
@@ -244,6 +244,9 @@
#define TWL4030_VIBRA_SEL 0x10
#define TWL4030_VIBRA_DIR_SEL 0x20
+/* clock ID used for setting APLL rate */
+#define TWL4030_CLOCK_APLL 0xffff
+
/* TWL4030 codec resource IDs */
enum twl4030_audio_res {
TWL4030_AUDIO_RES_POWER = 0,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 9476cdfd4dde9..ff36679166e20 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -198,6 +198,38 @@ static void twl4030_codec_enable(struct snd_soc_component *component, int enable
udelay(10);
}
+static int twl4030_perform_writes(struct snd_soc_component *component,
+ const unsigned int *regs,
+ const unsigned int *vals,
+ unsigned int n)
+{
+ struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+ int reboot_codec = twl4030->codec_powered;
+ unsigned int i;
+ int ret;
+
+ if (reboot_codec)
+ twl4030_codec_enable(component, 0);
+
+ for (i = 0; i < n; ++i) {
+ ret = twl4030_write(component, regs[i], vals[i]);
+ if (ret)
+ return ret;
+ }
+
+ if (reboot_codec)
+ twl4030_codec_enable(component, 1);
+
+ return 0;
+}
+
+static inline int
+twl4030_perform_single_write(struct snd_soc_component *component,
+ unsigned int reg, unsigned int val)
+{
+ return twl4030_perform_writes(component, ®, &val, 1);
+}
+
static void
twl4030_get_board_param_values(struct twl4030_board_params *board_params,
struct device_node *node)
@@ -1690,38 +1722,16 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
twl4030_tdm_enable(component, substream->stream, 0);
}
-static int twl4030_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int twl4030_get_codec_mode_for_apll_rate(struct snd_soc_component *component,
+ unsigned int rate, u8 *res)
{
- struct snd_soc_component *component = dai->component;
- struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
- u8 mode, old_mode, format, old_format;
-
- /* If the substream has 4 channel, do the necessary setup */
- if (params_channels(params) == 4) {
- format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
- mode = twl4030_read(component, TWL4030_REG_CODEC_MODE);
-
- /* Safety check: are we in the correct operating mode and
- * the interface is in TDM mode? */
- if ((mode & TWL4030_OPTION_1) &&
- ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
- twl4030_tdm_enable(component, substream->stream, 1);
- else
- return -EINVAL;
- }
-
- if (twl4030->configured)
- /* Ignoring hw_params for already configured DAI */
- return 0;
+ u8 old_mode, mode;
- /* bit rate */
old_mode = twl4030_read(component,
TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
mode = old_mode & ~TWL4030_APLL_RATE;
- switch (params_rate(params)) {
+ switch (rate) {
case 8000:
mode |= TWL4030_APLL_RATE_8000;
break;
@@ -1753,11 +1763,50 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
mode |= TWL4030_APLL_RATE_96000;
break;
default:
- dev_err(component->dev, "%s: unknown rate %d\n", __func__,
- params_rate(params));
+ dev_err(component->dev, "%s: unknown rate %u\n", __func__,
+ rate);
return -EINVAL;
}
+ *res = mode;
+
+ return mode != old_mode ? 1 : 0;
+}
+
+static int twl4030_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+ u8 mode, format, old_format;
+ int s;
+ unsigned int regs[2], vals[2];
+
+ /* If the substream has 4 channel, do the necessary setup */
+ if (params_channels(params) == 4) {
+ format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
+ mode = twl4030_read(component, TWL4030_REG_CODEC_MODE);
+
+ /* Safety check: are we in the correct operating mode and
+ * the interface is in TDM mode?
+ */
+ if ((mode & TWL4030_OPTION_1) &&
+ ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM))
+ twl4030_tdm_enable(component, substream->stream, 1);
+ else
+ return -EINVAL;
+ }
+
+ if (twl4030->configured)
+ /* Ignoring hw_params for already configured DAI */
+ return 0;
+
+ s = twl4030_get_codec_mode_for_apll_rate(component,
+ params_rate(params), &mode);
+ if (s < 0)
+ return s;
+
/* sample size */
old_format = twl4030_read(component, TWL4030_REG_AUDIO_IF);
format = old_format;
@@ -1775,20 +1824,12 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (format != old_format || mode != old_mode) {
- if (twl4030->codec_powered) {
- /*
- * If the codec is powered, than we need to toggle the
- * codec power.
- */
- twl4030_codec_enable(component, 0);
- twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
- twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
- twl4030_codec_enable(component, 1);
- } else {
- twl4030_write(component, TWL4030_REG_CODEC_MODE, mode);
- twl4030_write(component, TWL4030_REG_AUDIO_IF, format);
- }
+ if (format != old_format || s) {
+ regs[0] = TWL4030_REG_CODEC_MODE;
+ vals[0] = mode;
+ regs[1] = TWL4030_REG_AUDIO_IF;
+ vals[1] = format;
+ twl4030_perform_writes(component, regs, vals, ARRAY_SIZE(regs));
}
/* Store the important parameters for the DAI configuration and set
@@ -1813,6 +1854,21 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
{
struct snd_soc_component *component = codec_dai->component;
struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
+ int s;
+ u8 mode;
+
+ if (clk_id == TWL4030_CLOCK_APLL) {
+ s = twl4030_get_codec_mode_for_apll_rate(component,
+ freq, &mode);
+ if (s < 0)
+ return s;
+
+ if (s)
+ return twl4030_perform_single_write(component,
+ TWL4030_REG_CODEC_MODE, mode);
+
+ return 0;
+ }
switch (freq) {
case 19200000:
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 01/16] dt-bindings: twl-regulator: Add bindings for exposing ti,twl4030-regen
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Grond <grond66@riseup.net>
FIXME: not reflected in the bindings
+Reguired properties:
+For twl3040 REGEN signal:
+ - regulator-min-microvolt:
+ - Same meaning as in bindings/regulator/regulator.yaml, but must match
+ regulator-max-microvolt.
+ - regulator-max-microvolt:
+ - Same meaning as in bindings/regulator/regulator.yaml, but must match
+ regulator-min-microvolt.
+ - startup-delay-us:
+ - Same meaning as in bindings/regulator/fixed-regulator.yaml.
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
Documentation/devicetree/bindings/mfd/ti,twl.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mfd/ti,twl.yaml b/Documentation/devicetree/bindings/mfd/ti,twl.yaml
index 9cc3e4721612e..183fc015e40ad 100644
--- a/Documentation/devicetree/bindings/mfd/ti,twl.yaml
+++ b/Documentation/devicetree/bindings/mfd/ti,twl.yaml
@@ -46,6 +46,7 @@ allOf:
- ti,twl4030-vusb1v5
- ti,twl4030-vusb1v8
- ti,twl4030-vusb3v1
+ - ti,twl4030-regen
ti,retain-on-reset: false
properties:
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 13/16] arm: dts: omap3pandora: create new DT node for the sound card
From: H. Nikolaus Schaller @ 2026-07-11 6:02 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Stefan Leichter <sle85276@gmx.de>
This means that the sound card driver (snd-soc-omap3pandora) will get
loaded by default.
To make this work, we also add dac pcm1773-codec and widgets and
routing as needed.
Signed-off-by: Stefan Leichter <sle85276@gmx.de>
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
.../dts/ti/omap/omap3-pandora-common.dtsi | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
index de9860526b323..13821d926afb0 100644
--- a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
@@ -47,6 +47,45 @@ dac: pcm1773-codec {
vcc-supply = <&vsim>;
enable-gpio = <&gpio4 22 GPIO_ACTIVE_HIGH>; /* GPIO 118 */
status = "okay";
+ #sound-dai-cells = <0>;
+ };
+
+ twl_audio_clk: twl-audio-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12288000>;
+ clock-output-names = "clk256fs";
+ };
+
+ sound: sound {
+ compatible = "openpandora,omap3pandora-sound";
+ status = "okay";
+
+ label = "OpenPandora";
+
+ amp-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+ amp-supply = <®en>;
+
+ widgets =
+ "Line", "Line Out",
+ "Line", "Line In",
+ "Headphone", "Headphone Jack",
+ "Microphone", "Mic (internal)",
+ "Microphone", "Mic (external)";
+
+ routing =
+ "PCM1773 DAC", "APLL Enable",
+ "Headphone Amplifier", "PCM1773 DAC",
+ "Line Out", "PCM1773 DAC",
+ "Headphone Jack", "Headphone Amplifier",
+ "AUXL", "Line In",
+ "AUXR", "Line In",
+ "MAINMIC", "Mic (internal)",
+ "Mic (internal)", "Mic Bias 1",
+ "SUBMIC", "Mic (external)",
+ "Mic (external)", "Mic Bias 2";
+
+ sound-dai = <&mcbsp2>, <&dac>;
};
gpio-leds {
@@ -724,6 +763,9 @@ &mcbsp1 {
/* audio DAC */
&mcbsp2 {
status = "okay";
+ #sound-dai-cells = <0>;
+ clocks = <&mcbsp2_fck>, <&mcbsp2_ick>;
+ clock-names = "fck", "ick";
};
/* bluetooth */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 08/16] ASoC: pcm1773-codec: write a driver for the PCM1773 chip from TI
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Grond <grond66@riseup.net>
This chip is used in the OpenPandora.
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
sound/soc/codecs/Kconfig | 5 ++
sound/soc/codecs/pcm1773.c | 149 +++++++++++++++++++++++++++++++++++++
2 files changed, 154 insertions(+)
create mode 100644 sound/soc/codecs/pcm1773.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 252f683be3c18..3e186652fa06d 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -182,6 +182,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_HDMI_CODEC
imply SND_SOC_PCM1681
imply SND_SOC_PCM1754
+ imply SND_SOC_PCM1773
imply SND_SOC_PCM1789_I2C
imply SND_SOC_PCM179X_I2C
imply SND_SOC_PCM179X_SPI
@@ -1541,6 +1542,10 @@ config SND_SOC_PCM1754
tristate "Texas Instruments PCM1754 CODEC"
depends on GPIOLIB
+config SND_SOC_PCM1773
+ tristate "Texas Instruments PCM1773 CODEC"
+ select GPIOLIB
+
config SND_SOC_PCM1789
tristate
diff --git a/sound/soc/codecs/pcm1773.c b/sound/soc/codecs/pcm1773.c
new file mode 100644
index 0000000000000..75f9fe40a89d5
--- /dev/null
+++ b/sound/soc/codecs/pcm1773.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * pcm1773.c -- codec for the simple PCM1773 output codec from TI
+ *
+ * Shamelessly cobbled together from sound/soc/ti/omap3pandora.c and a few
+ * other codec drivers in sound/soc/codecs/
+ *
+ * Author: Grond <grond66@riseup.net>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+
+struct pcm1773 {
+ struct regulator *regulator;
+ struct gpio_desc *enable_gpio;
+};
+
+static int pcm1773_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct pcm1773 *ctx = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+ int ret;
+
+ /*
+ * The PCM1773 DAC datasheet requires 1ms delay between switching
+ * VCC power on/off and /PD pin high/low
+ */
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (ctx->regulator) {
+ ret = regulator_enable(ctx->regulator);
+ if (ret) {
+ dev_err(dev, "Failed to power DAC: %d\n", ret);
+ return ret;
+ }
+ mdelay(1);
+ }
+
+ if (ctx->enable_gpio)
+ gpiod_set_value_cansleep(ctx->enable_gpio, 1);
+ } else {
+ if (ctx->enable_gpio)
+ gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+
+ if (ctx->regulator) {
+ mdelay(1);
+ regulator_disable(ctx->regulator);
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget pcm1773_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC_E("PCM1773 DAC", "HiFi Playback", SND_SOC_NOPM,
+ 0, 0, pcm1773_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+};
+
+static const struct snd_soc_dapm_route pcm1773_dapm_routes[] = {
+ /* tell DAPM that the main stream flows to the PCM1773 */
+ {"PCM1773 DAC", NULL, "PCM1773 IN"},
+};
+
+static struct snd_soc_dai_driver pcm1773_dai = {
+ .name = "pcm1773-hifi",
+ .playback = {
+ .stream_name = "PCM1773 IN",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ // [TODO] these really should be BE, per the data sheet but for
+ // some reason the omap-mcbsp driver claims only to support LE.
+ // investigate
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+};
+
+static int pcm1773_probe(struct snd_soc_component *component)
+{
+ struct pcm1773 *ctx = NULL;
+ struct device *dev = component->dev;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ snd_soc_component_set_drvdata(component, ctx);
+
+ ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->enable_gpio)) {
+ return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
+ "invalid GPIO specification for enable");
+ }
+ if (ctx->enable_gpio)
+ dev_dbg(dev, "got enable-gpio\n");
+ else
+ dev_warn(dev, "enable-gpio not specified\n");
+
+ ctx->regulator = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(ctx->regulator)) {
+ dev_warn(dev, "cannot get regulator 'vcc'");
+ ctx->regulator = NULL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver soc_component_dev_pcm1773 = {
+ .probe = pcm1773_probe,
+ .dapm_widgets = pcm1773_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm1773_dapm_widgets),
+ .dapm_routes = pcm1773_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm1773_dapm_routes),
+};
+
+static int pcm1773_codec_probe(struct platform_device *pdev)
+{
+ return devm_snd_soc_register_component(&pdev->dev,
+ &soc_component_dev_pcm1773,
+ &pcm1773_dai, 1);
+}
+
+static const struct of_device_id pcm1773_of_match[] = {
+ {
+ .compatible = "ti,pcm1773",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pcm1773_of_match);
+
+static struct platform_driver pcm1773_codec_driver = {
+ .probe = pcm1773_codec_probe,
+ .driver = {
+ .name = "pcm1773-codec",
+ .of_match_table = pcm1773_of_match,
+ },
+};
+
+module_platform_driver(pcm1773_codec_driver);
+
+MODULE_DESCRIPTION("ASoC codec driver PCM1773");
+MODULE_AUTHOR("Grond");
+MODULE_LICENSE("GPL");
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 14/16] arm: dts: omap3-pandora-common: backlight: switch to twl4030 pwm and pwm_bl
From: H. Nikolaus Schaller @ 2026-07-11 6:02 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
This allows to remove the pandora_bl driver and pdata-quirks.
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
index 13821d926afb0..fea7132ce7c5e 100644
--- a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
@@ -31,6 +31,14 @@ hfclk_26m: oscillator {
clock-frequency = <26000000>;
};
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&twl_pwm 0 1922710>;
+
+ brightness-levels = <0 150 158 166 174 185 205 230 255>;
+ default-brightness-level = <6>;
+ };
+
tv: connector {
compatible = "connector-analog-tv";
label = "tv";
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 10/16] ASoC: omap3pandora: Rewrite sound card driver as a platform driver with DT
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Stefan Leichter <sle85276@gmx.de>
This change takes advantage of numerous prior changes and moves a
significant amount of code into the new PCM1773 codec driver (and removes
a hardcoded GPIO and regulator in the process). By using this new driver we
can remove the prior fiction that playback audio goes through the TWL4030.
Previously, the sound card driver worked by checking (through various means)
if it was running on the Pandora, and if so, it would create a new platform
device from nothing to function as the sound card, and rely on some weirdness
to get registered as an ASoC card driver. This has not been the way to do ASoC
card drivers for a while now, so instead we register a platform driver which
matches a device in the Pandora's DT and registers the appropriate ASoC card
driver when found. This also means that the driver will only load when the DT
says that we need it, and we can stop manually loading this thing.
Other significant changes:
- as a side-effect this patch retires the last call to machine_is_omap3_pandora()
- conversion to devm
- separate capture and playback ops
- conversion to dev_err
- use new code for twl4030 to set apll clock
- move widgets and routing to device tree definitions
Signed-off-by: Stefan Leichter <sle85276@gmx.de>
Co-developed-by: Grond <grond66@riseup.net>
Signed-off-by: Grond <grond66@riseup.net>
Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
sound/soc/ti/omap3pandora.c | 454 +++++++++++++++++++++++++-----------
1 file changed, 320 insertions(+), 134 deletions(-)
diff --git a/sound/soc/ti/omap3pandora.c b/sound/soc/ti/omap3pandora.c
index 6c9c184cd9d6f..d3509473f5df0 100644
--- a/sound/soc/ti/omap3pandora.c
+++ b/sound/soc/ti/omap3pandora.c
@@ -6,138 +6,279 @@
*/
#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
+#include <asm/mach-types.h>
+#include <linux/mfd/twl4030-audio.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
-#define PREFIX "ASoC omap3pandora: "
+struct omap3pandora_sound {
+ struct gpio_desc *amp_gpio;
+ struct regulator *amp_regulator;
+
+ struct snd_pcm_substream *playback_stream;
+ struct snd_pcm_substream *capture_stream;
-static struct regulator *omap3pandora_dac_reg;
-static struct gpio_desc *dac_power_gpio;
-static struct gpio_desc *amp_power_gpio;
+ struct mutex sample_rate_lock; // protects all fields after
+ unsigned int sample_rate;
+ int sample_rate_users;
+};
-static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static struct snd_soc_dai_link omap3pandora_dai[];
+
+static int omap3pandora_common_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct device *dev = rtd->dev;
int ret;
- /* Set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- pr_err(PREFIX "can't set codec system clock\n");
- return ret;
- }
-
/* Set McBSP clock to external */
ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
256 * params_rate(params),
SND_SOC_CLOCK_IN);
if (ret < 0) {
- pr_err(PREFIX "can't set cpu system clock\n");
+ dev_err(dev, "cannot set McBSP clock to external: %d\n", ret);
return ret;
}
ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
if (ret < 0) {
- pr_err(PREFIX "can't set SRG clock divider\n");
+ dev_err(dev, "cannot set McBSP clock divider: %d\n", ret);
return ret;
}
return 0;
}
-static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
+static inline int constrain_sample_rate(struct snd_pcm_substream *substream,
+ unsigned int sample_rate)
{
+ return snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ sample_rate);
+}
+
+static inline void relax_sample_rate(struct snd_pcm_substream *substream)
+{
+ const struct snd_interval default_sample_rate_range = {
+ .min = substream->runtime->hw.rate_min,
+ .max = substream->runtime->hw.rate_max,
+ .openmin = 1,
+ .openmax = 1,
+ };
+
+ *constrs_interval(&substream->runtime->hw_constraints,
+ SNDRV_PCM_HW_PARAM_RATE) =
+ default_sample_rate_range;
+}
+
+static void release_sample_rate(struct omap3pandora_sound *ctx,
+ struct snd_pcm_substream *substream)
+{
+ mutex_lock(&ctx->sample_rate_lock);
+
+ if (ctx->sample_rate_users > 0)
+ --ctx->sample_rate_users;
+ if (ctx->sample_rate_users == 0)
+ ctx->sample_rate = 0;
+
+ relax_sample_rate(substream);
+
+ mutex_unlock(&ctx->sample_rate_lock);
+}
+
+static int grab_sample_rate(struct omap3pandora_sound *ctx,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct device *dev = rtd->dev;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx->sample_rate_lock);
+ if (ret)
+ return ret;
+
+ if (++ctx->sample_rate_users == 1)
+ ctx->sample_rate = params_rate(params);
+
+ mutex_unlock(&ctx->sample_rate_lock);
+
+ ret = constrain_sample_rate(substream, ctx->sample_rate);
+ if (ret < 0)
+ goto err;
+
+ ret = constrain_sample_rate(substream, params_rate(params));
+ if (ret < 0) {
+ dev_dbg(dev, "sample rate mismatch; playback/capture share same clock");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ release_sample_rate(ctx, substream);
+
+ return ret;
+}
+
+static int omap3pandora_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct omap3pandora_sound *ctx = snd_soc_card_get_drvdata(card);
+ struct device *dev = rtd->dev;
+ struct snd_soc_pcm_runtime *tmp_rtd;
+ struct snd_soc_pcm_runtime *twl4030_rtd = NULL;
int ret;
/*
- * The PCM1773 DAC datasheet requires 1ms delay between switching
- * VCC power on/off and /PD pin high/low
+ * We need to set the APLL clock rate on the TWL4030 because it feeds
+ * both the DAI of the PCM1773. So find the appropriate RTD and call
+ * the TWL's .set_sysclk callback through there. Ugly, but it must be
+ * done.
*/
- if (SND_SOC_DAPM_EVENT_ON(event)) {
- struct device *dev = snd_soc_dapm_to_dev(w->dapm);
- ret = regulator_enable(omap3pandora_dac_reg);
- if (ret) {
- dev_err(dev, "Failed to power DAC: %d\n", ret);
- return ret;
+ for_each_card_rtds(card, tmp_rtd)
+ if (tmp_rtd->dai_link == &omap3pandora_dai[1]) {
+ twl4030_rtd = tmp_rtd;
+ break;
}
- mdelay(1);
- gpiod_set_value(dac_power_gpio, 1);
- } else {
- gpiod_set_value(dac_power_gpio, 0);
- mdelay(1);
- regulator_disable(omap3pandora_dac_reg);
+ if (!twl4030_rtd) {
+ dev_err(dev, "cannot find TWL4030 runtime data to set APLL rate\n");
+ return -EINVAL;
}
- return 0;
+ ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(twl4030_rtd, 0),
+ TWL4030_CLOCK_APLL, params_rate(params),
+ SND_SOC_CLOCK_OUT);
+ if (ret) {
+ dev_err(dev, "cannot set TWL4030 APLL rate via set_sysclk interface: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (!ctx->playback_stream) {
+ ctx->playback_stream = substream;
+ ret = grab_sample_rate(ctx, substream, params);
+ if (ret)
+ return ret;
+ }
+
+ return omap3pandora_common_hw_params(substream, params);
}
-static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
+static int omap3pandora_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct device *dev = rtd->dev;
+ struct snd_soc_card *card = rtd->card;
+ struct omap3pandora_sound *ctx = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ /* Set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(dev, "cannot set TWL4030 system clock: %d\n", ret);
+ return ret;
+ }
+
+ if (!ctx->capture_stream) {
+ ctx->capture_stream = substream;
+ ret = grab_sample_rate(ctx, substream, params);
+ if (ret)
+ return ret;
+ }
+
+ return omap3pandora_common_hw_params(substream, params);
+}
+
+static int omap3pandora_playback_hw_free(struct snd_pcm_substream *substream)
{
- if (SND_SOC_DAPM_EVENT_ON(event))
- gpiod_set_value(amp_power_gpio, 1);
- else
- gpiod_set_value(amp_power_gpio, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct omap3pandora_sound *ctx = snd_soc_card_get_drvdata(card);
+
+ if (ctx->playback_stream)
+ release_sample_rate(ctx, substream);
+ ctx->playback_stream = NULL;
return 0;
}
-/*
- * Audio paths on Pandora board:
- *
- * |O| ---> PCM DAC +-> AMP -> Headphone Jack
- * |M| A +--------> Line Out
- * |A| <~~clk~~+
- * |P| <--- TWL4030 <--------- Line In and MICs
- */
-static const struct snd_soc_dapm_widget omap3pandora_dapm_widgets[] = {
- SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
- 0, 0, omap3pandora_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
- 0, 0, NULL, 0, omap3pandora_hp_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_LINE("Line Out", NULL),
+static int omap3pandora_common_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct omap3pandora_sound *ctx = snd_soc_card_get_drvdata(card);
+ unsigned int sample_rate = ctx->sample_rate;
- SND_SOC_DAPM_MIC("Mic (internal)", NULL),
- SND_SOC_DAPM_MIC("Mic (external)", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
-};
+ if (!sample_rate)
+ return 0;
-static const struct snd_soc_dapm_route omap3pandora_map[] = {
- {"PCM DAC", NULL, "APLL Enable"},
- {"Headphone Amplifier", NULL, "PCM DAC"},
- {"Line Out", NULL, "PCM DAC"},
- {"Headphone Jack", NULL, "Headphone Amplifier"},
+ return constrain_sample_rate(substream, sample_rate);
+}
- {"AUXL", NULL, "Line In"},
- {"AUXR", NULL, "Line In"},
+static int omap3pandora_capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_card *card = rtd->card;
+ struct omap3pandora_sound *ctx = snd_soc_card_get_drvdata(card);
- {"MAINMIC", NULL, "Mic (internal)"},
- {"Mic (internal)", NULL, "Mic Bias 1"},
+ if (ctx->capture_stream)
+ release_sample_rate(ctx, substream);
+ ctx->capture_stream = NULL;
- {"SUBMIC", NULL, "Mic (external)"},
- {"Mic (external)", NULL, "Mic Bias 2"},
-};
+ return 0;
+}
+
+static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct device *dev = card->dev;
+ struct omap3pandora_sound *ctx =
+ snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = regulator_enable(ctx->amp_regulator);
+ if (ret) {
+ dev_err(dev, "error enabling amplifier regulator: %d\n", ret);
+ return ret;
+ }
+
+ gpiod_set_value(ctx->amp_gpio, 1);
+ } else {
+ gpiod_set_value(ctx->amp_gpio, 0);
+
+ ret = regulator_disable(ctx->amp_regulator);
+ if (ret) {
+ dev_err(dev, "error disabling amplifier regulator: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
{
@@ -171,20 +312,40 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static const struct snd_soc_ops omap3pandora_ops = {
- .hw_params = omap3pandora_hw_params,
+static const struct snd_soc_ops omap3pandora_playback_ops = {
+ .startup = omap3pandora_common_startup,
+ .hw_params = omap3pandora_playback_hw_params,
+ .hw_free = omap3pandora_playback_hw_free,
+};
+
+static const struct snd_soc_ops omap3pandora_capture_ops = {
+ .startup = omap3pandora_common_startup,
+ .hw_params = omap3pandora_capture_hw_params,
+ .hw_free = omap3pandora_capture_hw_free,
};
/* Digital audio interface glue - connects codec <--> CPU */
+#if IS_BUILTIN(CONFIG_SND_SOC_OMAP3_PANDORA)
SND_SOC_DAILINK_DEFS(out,
DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.2")),
- DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm1773-codec", "pcm1773-hifi")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.2")));
SND_SOC_DAILINK_DEFS(in,
DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.4")),
DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.4")));
+#else /* IS_BUILTIN(CONFIG_SND_SOC_OMAP3_PANDORA) */
+SND_SOC_DAILINK_DEFS(out,
+ DAILINK_COMP_ARRAY(COMP_CPU("49022000.mcbsp")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm1773-codec", "pcm1773-hifi")),
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("49022000.mcbsp")));
+
+SND_SOC_DAILINK_DEFS(in,
+ DAILINK_COMP_ARRAY(COMP_CPU("49026000.mcbsp")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("twl4030-codec", "twl4030-hifi")),
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("49026000.mcbsp")));
+#endif /* IS_BUILTIN(CONFIG_SND_SOC_OMAP3_PANDORA) */
static struct snd_soc_dai_link omap3pandora_dai[] = {
{
@@ -192,100 +353,125 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.stream_name = "HiFi Out",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .ops = &omap3pandora_ops,
+ .ops = &omap3pandora_playback_ops,
.init = omap3pandora_out_init,
+ .playback_only = 1,
SND_SOC_DAILINK_REG(out),
}, {
.name = "TWL4030",
.stream_name = "Line/Mic In",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,
- .ops = &omap3pandora_ops,
+ .ops = &omap3pandora_capture_ops,
.init = omap3pandora_in_init,
+ .capture_only = 1,
SND_SOC_DAILINK_REG(in),
}
};
+static const struct snd_soc_dapm_widget omap3pandora_local_widgets[] = {
+ SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
+ 0, 0, NULL, 0, omap3pandora_hp_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+};
+
/* SoC card */
static struct snd_soc_card snd_soc_card_omap3pandora = {
- .name = "omap3pandora",
- .owner = THIS_MODULE,
- .dai_link = omap3pandora_dai,
- .num_links = ARRAY_SIZE(omap3pandora_dai),
-
- .dapm_widgets = omap3pandora_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(omap3pandora_dapm_widgets),
- .dapm_routes = omap3pandora_map,
- .num_dapm_routes = ARRAY_SIZE(omap3pandora_map),
+ .name = "omap3pandora",
+ .owner = THIS_MODULE,
+ .dai_link = omap3pandora_dai,
+ .num_links = ARRAY_SIZE(omap3pandora_dai),
+ .dapm_widgets = omap3pandora_local_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(omap3pandora_local_widgets),
};
-static struct platform_device *omap3pandora_snd_device;
-
-static int __init omap3pandora_soc_init(void)
+static int omap3pandora_probe(struct platform_device *pdev)
{
int ret;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card = &snd_soc_card_omap3pandora;
+ struct omap3pandora_sound *ctx;
- if (!of_machine_is_compatible("openpandora,omap3-pandora-600mhz") &&
- !of_machine_is_compatible("openpandora,omap3-pandora-1ghz"))
- return -ENODEV;
-
- pr_info("OMAP3 Pandora SoC init\n");
-
- omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
- if (omap3pandora_snd_device == NULL) {
- pr_err(PREFIX "Platform device allocation failed\n");
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
return -ENOMEM;
- }
- platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
+ mutex_init(&ctx->sample_rate_lock);
- ret = platform_device_add(omap3pandora_snd_device);
- if (ret) {
- pr_err(PREFIX "Unable to add platform device\n");
- goto fail2;
+ ctx->amp_gpio = devm_gpiod_get(dev, "amp", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->amp_gpio)) {
+ dev_err(dev, "cannot find amplifier gpio\n");
+ return PTR_ERR(ctx->amp_gpio);
}
- dac_power_gpio = devm_gpiod_get(&omap3pandora_snd_device->dev,
- "dac", GPIOD_OUT_LOW);
- if (IS_ERR(dac_power_gpio)) {
- ret = PTR_ERR(dac_power_gpio);
- goto fail3;
+ ctx->amp_regulator = devm_regulator_get(dev, "amp");
+ if (IS_ERR(ctx->amp_regulator)) {
+ ret = PTR_ERR(ctx->amp_regulator);
+ dev_err(dev, "Failed to request regulator for amplifier power: %d\n", ret);
+ return ret;
}
- amp_power_gpio = devm_gpiod_get(&omap3pandora_snd_device->dev,
- "amp", GPIOD_OUT_LOW);
- if (IS_ERR(amp_power_gpio)) {
- ret = PTR_ERR(amp_power_gpio);
- goto fail3;
+ card->dev = dev;
+
+ if (dev->of_node) {
+ ret = snd_soc_of_parse_card_name(card, "label");
+ if (ret)
+ card->name = "omap3pandora";
+
+ ret = snd_soc_of_parse_audio_simple_widgets(card, "widgets");
+ if (ret) {
+ dev_err(dev, "Failed to parse DAPM widgets: %d\n", ret);
+ goto err_mutex;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "routing");
+ if (ret) {
+ dev_err(dev, "Failed to parse audio routing: %d\n", ret);
+ goto err_mutex;
+ }
}
- omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
- if (IS_ERR(omap3pandora_dac_reg)) {
- pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
- dev_name(&omap3pandora_snd_device->dev),
- PTR_ERR(omap3pandora_dac_reg));
- ret = PTR_ERR(omap3pandora_dac_reg);
- goto fail3;
+ snd_soc_card_set_drvdata(card, ctx);
+
+ ret = devm_snd_soc_register_card(dev, card);
+ if (ret) {
+ dev_err(dev, "Failed to register sound card: %d\n", ret);
+ goto err_mutex;
}
return 0;
-fail3:
- platform_device_del(omap3pandora_snd_device);
-fail2:
- platform_device_put(omap3pandora_snd_device);
-
+err_mutex:
+ mutex_destroy(&ctx->sample_rate_lock);
return ret;
}
-module_init(omap3pandora_soc_init);
-static void __exit omap3pandora_soc_exit(void)
+static void omap3pandora_remove(struct platform_device *pdev)
{
- regulator_put(omap3pandora_dac_reg);
- platform_device_unregister(omap3pandora_snd_device);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct omap3pandora_sound *ctx = snd_soc_card_get_drvdata(card);
+
+ mutex_destroy(&ctx->sample_rate_lock);
}
-module_exit(omap3pandora_soc_exit);
+
+static const struct of_device_id omap3pandora_of_match[] = {
+ { .compatible = "openpandora,omap3pandora-sound", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, omap3pandora_of_match);
+
+static struct platform_driver omap3pandora_driver = {
+ .driver = {
+ .name = "omap3pandora-sound",
+ .of_match_table = omap3pandora_of_match,
+ },
+ .probe = omap3pandora_probe,
+ .remove = omap3pandora_remove,
+};
+
+module_platform_driver(omap3pandora_driver);
MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap3pandora-sound");
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 12/16] arm: dts: omap3pandora: Add device node for PCM1773 codec
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Grond <grond66@riseup.net>
This will ensure that the new PCM1773 driver gets loaded automatically.
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
index 5907b2455f75b..de9860526b323 100644
--- a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
@@ -42,6 +42,13 @@ tv_connector_in: endpoint {
};
};
+ dac: pcm1773-codec {
+ compatible = "ti,pcm1773";
+ vcc-supply = <&vsim>;
+ enable-gpio = <&gpio4 22 GPIO_ACTIVE_HIGH>; /* GPIO 118 */
+ status = "okay";
+ };
+
gpio-leds {
compatible = "gpio-leds";
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 16/16] arm: omap2: remove remaining pdata-quirks for pandora legacy devices
From: H. Nikolaus Schaller @ 2026-07-11 6:02 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
After updating the pandora-backligt setup and removing the omap3pandora
sound system and defining related gpios by device tree, we can remove
omap3_pandora_legacy_init() and the related legacy devices completely.
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
arch/arm/mach-omap2/pdata-quirks.c | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index b947bacf23a37..aca7097a692ed 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -268,27 +268,6 @@ static void __init omap3_logicpd_torpedo_init(void)
omap3_gpio126_127_129();
}
-/* omap3pandora legacy devices */
-
-static struct platform_device pandora_backlight = {
- .name = "pandora-backlight",
- .id = -1,
-};
-
-static struct gpiod_lookup_table pandora_soc_audio_gpios = {
- .dev_id = "soc-audio",
- .table = {
- GPIO_LOOKUP("gpio-112-127", 6, "dac", GPIO_ACTIVE_HIGH),
- GPIO_LOOKUP("gpio-0-15", 14, "amp", GPIO_ACTIVE_HIGH),
- { }
- },
-};
-
-static void __init omap3_pandora_legacy_init(void)
-{
- platform_device_register(&pandora_backlight);
- gpiod_add_lookup_table(&pandora_soc_audio_gpios);
-}
#endif /* CONFIG_ARCH_OMAP3 */
#ifdef CONFIG_SOC_DRA7XX
@@ -514,8 +493,6 @@ static struct pdata_init pdata_quirks[] __initdata = {
{ "ti,omap3-evm-37xx", omap3_evm_legacy_init, },
{ "ti,am3517-evm", am3517_evm_legacy_init, },
{ "technexion,omap3-tao3530", omap3_tao3530_legacy_init, },
- { "openpandora,omap3-pandora-600mhz", omap3_pandora_legacy_init, },
- { "openpandora,omap3-pandora-1ghz", omap3_pandora_legacy_init, },
#endif
{ /* sentinel */ },
};
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 07/16] ASoC: dt-bindings: add TI PCM1773
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
PCM1771/3 is a simple audio codec that can be enabled through an
enable-gpio.
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
.../devicetree/bindings/sound/pcm1773.yaml | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/pcm1773.yaml
diff --git a/Documentation/devicetree/bindings/sound/pcm1773.yaml b/Documentation/devicetree/bindings/sound/pcm1773.yaml
new file mode 100644
index 0000000000000..f3e640705bf70
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/pcm1773.yaml
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/sound/pcm1773.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments pcm1773 audio codec
+
+maintainers:
+ - to-be-defined@openpandora.org
+
+description: |+
+ PCM1771 is a simple audio codec that can be enabled
+ through a gpio.
+
+properties:
+ compatible:
+ const: ti,pcm1773
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ audio-codec {
+ compatible = "ti,pcm1773";
+ enable-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+ };
+
+...
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 11/16] ARM: dts: omap3-pandora-common: Enable audio in/out (mcbsp4/2)
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Stefan Leichter <sle85276@gmx.de>
enable mcbsp2 and mcbsp4.
Signed-off-by: Stefan Leichter <sle85276@gmx.de>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
index b4acab1625212..5907b2455f75b 100644
--- a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
@@ -716,6 +716,7 @@ &mcbsp1 {
/* audio DAC */
&mcbsp2 {
+ status = "okay";
};
/* bluetooth */
@@ -724,6 +725,7 @@ &mcbsp3 {
/* to twl4030*/
&mcbsp4 {
+ status = "okay";
};
&venc {
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 15/16] backlight: remove pandora_bl
From: H. Nikolaus Schaller @ 2026-07-11 6:02 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
Retire the platform specific pandora backlight driver since
it can now be replaced by twl_pm and device tree.
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
drivers/video/backlight/Kconfig | 7 --
drivers/video/backlight/Makefile | 1 -
drivers/video/backlight/pandora_bl.c | 159 ---------------------------
3 files changed, 167 deletions(-)
delete mode 100644 drivers/video/backlight/pandora_bl.c
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 7aa1c4b21111f..a250b3edc152c 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -451,13 +451,6 @@ config BACKLIGHT_MP3309C
To compile this driver as a module, choose M here: the module will
be called mp3309c.
-config BACKLIGHT_PANDORA
- tristate "Backlight driver for Pandora console"
- depends on TWL4030_CORE
- help
- If you have a Pandora console, say Y to enable the
- backlight driver.
-
config BACKLIGHT_SKY81452
tristate "Backlight driver for SKY81452"
depends on MFD_SKY81452
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 21c8313cfb121..f97ab8ba85807 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
obj-$(CONFIG_BACKLIGHT_MP3309C) += mp3309c.o
obj-$(CONFIG_BACKLIGHT_MT6370) += mt6370-backlight.o
obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
-obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o
diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c
deleted file mode 100644
index 8a63ded0fa90f..0000000000000
--- a/drivers/video/backlight/pandora_bl.c
+++ /dev/null
@@ -1,159 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Backlight driver for Pandora handheld.
- * Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight.
- * Based on pwm_bl.c
- *
- * Copyright 2009,2012 Gražvydas Ignotas <notasas@gmail.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/backlight.h>
-#include <linux/mfd/twl.h>
-#include <linux/err.h>
-
-#define TWL_PWM0_ON 0x00
-#define TWL_PWM0_OFF 0x01
-
-#define TWL_INTBR_GPBR1 0x0c
-#define TWL_INTBR_PMBR1 0x0d
-
-#define TWL_PMBR1_PWM0_MUXMASK 0x0c
-#define TWL_PMBR1_PWM0 0x04
-#define PWM0_CLK_ENABLE BIT(0)
-#define PWM0_ENABLE BIT(2)
-
-/* range accepted by hardware */
-#define MIN_VALUE 9
-#define MAX_VALUE 63
-#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)
-
-struct pandora_private {
- unsigned old_state;
-#define PANDORABL_WAS_OFF 1
-};
-
-static int pandora_backlight_update_status(struct backlight_device *bl)
-{
- int brightness = bl->props.brightness;
- struct pandora_private *priv = bl_get_data(bl);
- u8 r;
-
- if (bl->props.power != BACKLIGHT_POWER_ON)
- brightness = 0;
- if (bl->props.state & BL_CORE_FBBLANK)
- brightness = 0;
- if (bl->props.state & BL_CORE_SUSPENDED)
- brightness = 0;
-
- if ((unsigned int)brightness > MAX_USER_VALUE)
- brightness = MAX_USER_VALUE;
-
- if (brightness == 0) {
- if (priv->old_state == PANDORABL_WAS_OFF)
- goto done;
-
- /* first disable PWM0 output, then clock */
- twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);
- r &= ~PWM0_ENABLE;
- twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
- r &= ~PWM0_CLK_ENABLE;
- twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
-
- goto done;
- }
-
- if (priv->old_state == PANDORABL_WAS_OFF) {
- /*
- * set PWM duty cycle to max. TPS61161 seems to use this
- * to calibrate it's PWM sensitivity when it starts.
- */
- twl_i2c_write_u8(TWL_MODULE_PWM, MAX_VALUE, TWL_PWM0_OFF);
-
- /* first enable clock, then PWM0 out */
- twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);
- r &= ~PWM0_ENABLE;
- r |= PWM0_CLK_ENABLE;
- twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
- r |= PWM0_ENABLE;
- twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
-
- /*
- * TI made it very easy to enable digital control, so easy that
- * it often triggers unintentionally and disabes PWM control,
- * so wait until 1 wire mode detection window ends.
- */
- usleep_range(2000, 10000);
- }
-
- twl_i2c_write_u8(TWL_MODULE_PWM, MIN_VALUE + brightness, TWL_PWM0_OFF);
-
-done:
- if (brightness != 0)
- priv->old_state = 0;
- else
- priv->old_state = PANDORABL_WAS_OFF;
-
- return 0;
-}
-
-static const struct backlight_ops pandora_backlight_ops = {
- .options = BL_CORE_SUSPENDRESUME,
- .update_status = pandora_backlight_update_status,
-};
-
-static int pandora_backlight_probe(struct platform_device *pdev)
-{
- struct backlight_properties props;
- struct backlight_device *bl;
- struct pandora_private *priv;
- u8 r;
-
- priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- memset(&props, 0, sizeof(props));
- props.max_brightness = MAX_USER_VALUE;
- props.type = BACKLIGHT_RAW;
- bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev,
- priv, &pandora_backlight_ops, &props);
- if (IS_ERR(bl)) {
- dev_err(&pdev->dev, "failed to register backlight\n");
- return PTR_ERR(bl);
- }
-
- platform_set_drvdata(pdev, bl);
-
- /* 64 cycle period, ON position 0 */
- twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON);
-
- priv->old_state = PANDORABL_WAS_OFF;
- bl->props.brightness = MAX_USER_VALUE;
- backlight_update_status(bl);
-
- /* enable PWM function in pin mux */
- twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_PMBR1);
- r &= ~TWL_PMBR1_PWM0_MUXMASK;
- r |= TWL_PMBR1_PWM0;
- twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_PMBR1);
-
- return 0;
-}
-
-static struct platform_driver pandora_backlight_driver = {
- .driver = {
- .name = "pandora-backlight",
- },
- .probe = pandora_backlight_probe,
-};
-
-module_platform_driver(pandora_backlight_driver);
-
-MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
-MODULE_DESCRIPTION("Pandora Backlight Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pandora-backlight");
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 09/16] ASoC: dt-bindings: add OpenPandora Sound Card
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
The OpenPandora audio subsystem describes the routing links between the
OMAP3 McBSP interface, the external PCM1773 DAC, and the TWL4030 audio
codec, alongside amplifiers and power supplies.
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
.../sound/openpandora,omap3pandora-sound.yaml | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/openpandora,omap3pandora-sound.yaml
diff --git a/Documentation/devicetree/bindings/sound/openpandora,omap3pandora-sound.yaml b/Documentation/devicetree/bindings/sound/openpandora,omap3pandora-sound.yaml
new file mode 100644
index 0000000000000..d3c747e5c58d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/openpandora,omap3pandora-sound.yaml
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org
+$schema: http://devicetree.org
+
+title: OpenPandora OMAP3 Audio Complex
+
+maintainers:
+ - H. Nikolaus Schaller <hns@goldelico.com>
+
+description:
+ The OpenPandora audio subsystem describes the routing links between the
+ OMAP3 McBSP interface, the external PCM1773 DAC, and the TWL4030 audio codec,
+ alongside amplifiers and power supplies.
+
+properties:
+ compatible:
+ const: openpandora,omap3pandora-sound
+
+ status: true
+
+ label:
+ $ref: /schemas/types.yaml#/definitions/string
+ description: User-visible name for this sound card.
+
+ amp-gpios:
+ maxItems: 1
+ description: GPIO pin controlling the amplifier power state.
+
+ amp-supply:
+ description: Regulator supplying power to the amplifier.
+
+ sound-dai:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ minItems: 2
+ maxItems: 2
+ description:
+ Phandles to the audio CPU DAI (OMAP3 McBSP) and the codec DAI.
+
+ routing:
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ description:
+ A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source.
+
+ widgets:
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+ description:
+ User-specified audio sound widgets.
+ Each entry is a pair of strings, the first being the widget type
+ (e.g., "Speaker", "Headphone", "Microphone", "Line") and the second being its name.
+
+required:
+ - compatible
+ - sound-dai
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ sound: sound {
+ compatible = "openpandora,omap3pandora-sound";
+ status = "okay";
+
+ label = "OpenPandora";
+
+ amp-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+ amp-supply = <®en>;
+
+ widgets =
+ "Line", "Line Out",
+ "Line", "Line In",
+ "Headphone", "Headphone Jack",
+ "Microphone", "Mic (internal)",
+ "Microphone", "Mic (external)";
+
+ routing =
+ "PCM1773 DAC", "APLL Enable",
+ "Headphone Amplifier", "PCM1773 DAC",
+ "Line Out", "PCM1773 DAC",
+ "Headphone Jack", "Headphone Amplifier",
+ "AUXL", "Line In",
+ "AUXR", "Line In",
+ "MAINMIC", "Mic (internal)",
+ "Mic (internal)", "Mic Bias 1",
+ "SUBMIC", "Mic (external)",
+ "Mic (external)", "Mic Bias 2";
+
+ sound-dai = <&mcbsp2>, <&dac>;
+ };
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 05/16] arm: dts: omap3pandora: Don't use DMA channels for unused SPI masters
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Grond <grond66@riseup.net>
On the pandora, only McSPI1 (spi0) is actually used. Because the device
tree defaults in arch/arm/boot/dts/omap3.dtsi leave all of the mcspi
interfaces enabled, the DMA channels which the device tree assigns to them
cannot be used for anything else. This is a problem because OMAP3's sDMA
controller can only have 32 DMA channels configured at any one time.
So when we try to use (for example) the McBSP subsystem (which is required
for sound) it doesn't work because we've already exhausted our available
DMA channels.
Fix this by disabling mcspi[2-4] on the pandora device tree.
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
.../boot/dts/ti/omap/omap3-pandora-common.dtsi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
index a0116823ffdef..b4acab1625212 100644
--- a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
@@ -693,6 +693,23 @@ lcd_in: endpoint {
};
+/*
+ * Only mcspi1 is used on the pandora, the others do not surface on the board
+ * due to pinmux configuration. disable the unused ones so that they do not
+ * consume DMA channels
+ */
+&mcspi2 {
+ status = "disabled";
+};
+
+&mcspi3 {
+ status = "disabled";
+};
+
+&mcspi4 {
+ status = "disabled";
+};
+
/* n/a - used as GPIOs */
&mcbsp1 {
};
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH 04/16] arm: dts: omap3pandora: Populate DT data for the TWL4030's REGEN regulator
From: H. Nikolaus Schaller @ 2026-07-11 6:01 UTC (permalink / raw)
To: Grond, Stefan Leichter, H . Nikolaus Schaller, Grazvydas Ignotas,
Tony Lindgren, Ethan Nelson-Moore, Jarkko Nikula, Sascha Hauer,
Andreas Kemnade, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Aaro Koskinen,
Kevin Hilman, Roger Quadros, Russell King, Daniel Thompson,
Jingoo Han, Helge Deller, Jaroslav Kysela, Takashi Iwai, Sen Wang,
Richard Fitzgerald, Arnd Bergmann, Srinivas Kandagatla,
Kuninori Morimoto, Charles Keepax, Niranjan H Y
Cc: letux-kernel, devicetree, linux-kernel, linux-sound, linux-omap,
linux-arm-kernel, dri-devel, linux-fbdev, kernel, mfd
In-Reply-To: <cover.1783749722.git.hns@goldelico.com>
From: Grond <grond66@riseup.net>
On the Pandora, REGEN is used to enable TPS61029DRC external regulator
which runs a 5V power rail. The 5ms startup delay is taken from Pandora's
3.2 kernel, where it is labeled as a "guess". So it may be possible to
activate the regulator faster.
On Pandora CC units, this regulator is used as the input to the LCD power
supply. Therefore, problems are likely to arise if the regulator is ever
disabled, so we add the regulator-always-on property to compensate.
Signed-off-by: Grond <grond66@riseup.net>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
index 06c5b23589991..a0116823ffdef 100644
--- a/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3-pandora-common.dtsi
@@ -486,6 +486,14 @@ &vsim {
regulator-always-on;
};
+®en {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <5000>;
+ regulator-always-on;
+ status = "okay";
+};
+
&i2c2 {
clock-frequency = <100000>;
/* no clients so we should disable clock */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH 2/2] module: Bring includes in linux/kmod.h up to date
From: Aaron Tomlin @ 2026-07-10 13:57 UTC (permalink / raw)
To: Petr Pavlu
Cc: Tony Luck, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
Dave Hansen, x86, H. Peter Anvin, Philipp Reisner, Lars Ellenberg,
Christoph Böhmwalder, Jens Axboe, Johan Hovold, Alex Elder,
Greg Kroah-Hartman, Rafael J. Wysocki, Michal Januszewski,
Helge Deller, Alexander Viro, Christian Brauner, Jan Kara,
Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Mark Fasheh,
Joel Becker, Joseph Qi, Tejun Heo, Johannes Weiner,
Michal Koutný, Luis Chamberlain, Daniel Gomez, Sami Tolvanen,
Pavel Machek, Len Brown, Andrew Morton, Danilo Krummrich,
Nikolay Aleksandrov, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, David Howells,
Jarkko Sakkinen, Paul Moore, James Morris, Serge E. Hallyn,
Kentaro Takeda, Tetsuo Handa, linux-edac, linux-kernel, drbd-dev,
linux-block, greybus-dev, linuxppc-dev, linux-acpi, linux-fbdev,
dri-devel, linux-fsdevel, linux-nfs, ocfs2-devel, cgroups,
linux-modules, linux-pm, driver-core, bridge, netdev, keyrings,
linux-security-module
In-Reply-To: <20260708154510.6794-3-petr.pavlu@suse.com>
On Wed, Jul 08, 2026 at 05:44:30PM +0200, Petr Pavlu wrote:
> Including linux/kmod.h alone results in 1.5 MB of preprocessed output, even
> though it provides only a few functions and macros.
>
> The header currently depends on:
>
> * __printf() -> linux/compiler_attributes.h,
> * ENOSYS -> linux/errno.h,
> * bool -> linux/types.h.
>
> Include only these files, reducing the preprocessed output to 10 kB.
>
> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
> ---
> include/linux/kmod.h | 12 ++----------
> 1 file changed, 2 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/kmod.h b/include/linux/kmod.h
> index 9a07c3215389..b9474a62a568 100644
> --- a/include/linux/kmod.h
> +++ b/include/linux/kmod.h
> @@ -2,17 +2,9 @@
> #ifndef __LINUX_KMOD_H__
> #define __LINUX_KMOD_H__
>
> -/*
> - * include/linux/kmod.h
> - */
> -
> -#include <linux/umh.h>
> -#include <linux/gfp.h>
> -#include <linux/stddef.h>
> +#include <linux/compiler_attributes.h>
> #include <linux/errno.h>
> -#include <linux/compiler.h>
> -#include <linux/workqueue.h>
> -#include <linux/sysctl.h>
> +#include <linux/types.h>
>
> #ifdef CONFIG_MODULES
> /* modprobe exit status on success, -ve on error. Return value
> --
> 2.54.0
>
LGTM. Thank you.
Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>
--
Aaron Tomlin
^ permalink raw reply
* Re: [PATCH 1/2] umh, treewide: Explicitly include linux/umh.h where needed
From: Petr Pavlu @ 2026-07-09 9:49 UTC (permalink / raw)
To: Michal Koutný
Cc: Tony Luck, Borislav Petkov, Thomas Gleixner, Ingo Molnar,
Dave Hansen, x86, H. Peter Anvin, Philipp Reisner, Lars Ellenberg,
Christoph Böhmwalder, Jens Axboe, Johan Hovold, Alex Elder,
Greg Kroah-Hartman, Rafael J. Wysocki, Michal Januszewski,
Helge Deller, Alexander Viro, Christian Brauner, Jan Kara,
Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey, Mark Fasheh,
Joel Becker, Joseph Qi, Tejun Heo, Johannes Weiner,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Pavel Machek, Len Brown, Andrew Morton, Danilo Krummrich,
Nikolay Aleksandrov, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, David Howells,
Jarkko Sakkinen, Paul Moore, James Morris, Serge E. Hallyn,
Kentaro Takeda, Tetsuo Handa, linux-edac, linux-kernel, drbd-dev,
linux-block, greybus-dev, linuxppc-dev, linux-acpi, linux-fbdev,
dri-devel, linux-fsdevel, linux-nfs, ocfs2-devel, cgroups,
linux-modules, linux-pm, driver-core, bridge, netdev, keyrings,
linux-security-module
In-Reply-To: <ak6STbqZd-Q-c56v@localhost.localdomain>
On 7/8/26 8:13 PM, Michal Koutný wrote:
> Hi Petr.
>
> On Wed, Jul 08, 2026 at 05:44:29PM +0200, Petr Pavlu <petr.pavlu@suse.com> wrote:
>> diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
>> index a4337c9b5287..60eb994c32ae 100644
>> --- a/kernel/cgroup/cgroup-v1.c
>> +++ b/kernel/cgroup/cgroup-v1.c
>> @@ -16,6 +16,7 @@
>> #include <linux/pid_namespace.h>
>> #include <linux/cgroupstats.h>
>> #include <linux/fs_parser.h>
>> +#include <linux/umh.h>
>>
>> #include <trace/events/cgroup.h>
>
> There is kmod.h in here too but it's unnecessary, no module lazy loading
> in this code.
You're right. I'll remove the kmod.h include from
kernel/cgroup/cgroup-v1.c. I went through all the files again and it
seems this was the only place I missed.
--
Thanks,
Petr
^ permalink raw reply
* [PATCH v2 6/7] drm: Implement vga_switcheroo_client_ops.post_switch
From: Thomas Zimmermann @ 2026-07-09 9:16 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
An output's attached display might have changed while a DRM client's
device did not have the output switched to it.
The nouveau_switcheroo_reprobe() callback sends a hotplug notice to
DRM's internal clients, so that they can reconfigure their display
output if necessary.
As post_switch callback replaces reprobe in vga_switcheroo, update
nouveau accordingly. In the other drivers, remove the NULL-assignment
to reprobe. No functional changes.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Lyude Paul <lyude@redhat.com> # nouveau
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 1 -
drivers/gpu/drm/i915/i915_switcheroo.c | 1 -
drivers/gpu/drm/nouveau/nouveau_vga.c | 19 +++++++++----------
drivers/gpu/drm/radeon/radeon_device.c | 1 -
4 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 87a59a79a019..5bb1567d512d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1708,7 +1708,6 @@ static void amdgpu_switcheroo_pre_switch(struct pci_dev *pdev)
static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
.set_gpu_state = amdgpu_switcheroo_set_state,
- .reprobe = NULL,
.can_switch = amdgpu_switcheroo_can_switch,
.pre_switch = amdgpu_switcheroo_pre_switch,
};
diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c
index 6b306ece0556..d97057722fde 100644
--- a/drivers/gpu/drm/i915/i915_switcheroo.c
+++ b/drivers/gpu/drm/i915/i915_switcheroo.c
@@ -69,7 +69,6 @@ static void i915_switcheroo_pre_switch(struct pci_dev *pdev)
static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
- .reprobe = NULL,
.can_switch = i915_switcheroo_can_switch,
.pre_switch = i915_switcheroo_pre_switch,
};
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 2d2d08be8fbe..29a801124e56 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -54,15 +54,6 @@ nouveau_switcheroo_set_state(struct pci_dev *pdev,
}
}
-static void
-nouveau_switcheroo_reprobe(struct pci_dev *pdev)
-{
- struct nouveau_drm *drm = pci_get_drvdata(pdev);
- struct drm_device *dev = drm->dev;
-
- drm_client_dev_hotplug(dev);
-}
-
static bool
nouveau_switcheroo_can_switch(struct pci_dev *pdev)
{
@@ -84,12 +75,20 @@ nouveau_switcheroo_pre_switch(struct pci_dev *pdev)
drm_client_dev_acquire_outputs(drm->dev);
}
+static void
+nouveau_switcheroo_post_switch(struct pci_dev *pdev)
+{
+ struct nouveau_drm *drm = pci_get_drvdata(pdev);
+
+ drm_client_dev_hotplug(drm->dev);
+}
+
static const struct vga_switcheroo_client_ops
nouveau_switcheroo_ops = {
.set_gpu_state = nouveau_switcheroo_set_state,
- .reprobe = nouveau_switcheroo_reprobe,
.can_switch = nouveau_switcheroo_can_switch,
.pre_switch = nouveau_switcheroo_pre_switch,
+ .post_switch = nouveau_switcheroo_post_switch,
};
void
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 8697a9eb5d13..9523240110a6 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1267,7 +1267,6 @@ static void radeon_switcheroo_pre_switch(struct pci_dev *pdev)
static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
.set_gpu_state = radeon_switcheroo_set_state,
- .reprobe = NULL,
.can_switch = radeon_switcheroo_can_switch,
.pre_switch = radeon_switcheroo_pre_switch,
};
--
2.54.0
^ permalink raw reply related
* [PATCH v2 4/7] vga_switcheroo: Add post_switch callback to client ops
From: Thomas Zimmermann @ 2026-07-09 9:16 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
Add post_switch to struct vga_switcheroo_client_ops to inform the
switcheroo client about a completed switch of the output.
This callback is intended to replace the reprobe client op. It is a
rename of reprobe for consistency with pre_switch.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/vga/vga_switcheroo.c | 4 +++-
include/linux/vga_switcheroo.h | 12 +++++++-----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index bdf1e56ae891..7b0af4a8aa7d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -746,7 +746,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (ret)
return ret;
- if (new_client->ops->reprobe)
+ if (new_client->ops->post_switch)
+ new_client->ops->post_switch(new_client->pdev);
+ else if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 4422daca9ceb..51851831d4c1 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -127,21 +127,22 @@ struct vga_switcheroo_handler {
* @set_gpu_state: do the equivalent of suspend/resume for the card.
* Mandatory. This should not cut power to the discrete GPU,
* which is the job of the handler
- * @reprobe: poll outputs.
- * Optional. This gets called after waking the GPU and switching
- * the outputs to it
+ * @reprobe: deprecated
* @can_switch: check if the device is in a position to switch now.
* Mandatory. The client should return false if a user space process
* has one of its device files open
* @pre_switch: prepare switch
* Optional. This gets called before switching the outputs to the
* GPU. Allows drivers to prepare for the switch.
+ * @post_switch: completes switch
+ * Optional. This gets called after waking the GPU and switching
+ * the outputs to it. Allows drivers to poll the switched outputs.
* @gpu_bound: notify the client id to audio client when the GPU is bound.
*
* Client callbacks. A client can be either a GPU or an audio device on a GPU.
* The @set_gpu_state and @can_switch methods are mandatory, @pre_switch and
- * @reprobe may be set to NULL. For audio clients, the @pre_switch and
- * @reprobe members are bogus. OTOH, @gpu_bound is only for audio clients,
+ * @post_switch may be set to NULL. For audio clients, the @pre_switch and
+ * @post_switch members are bogus. OTOH, @gpu_bound is only for audio clients,
* and not used for GPU clients.
*/
struct vga_switcheroo_client_ops {
@@ -149,6 +150,7 @@ struct vga_switcheroo_client_ops {
void (*reprobe)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
void (*pre_switch)(struct pci_dev *dev);
+ void (*post_switch)(struct pci_dev *dev);
void (*gpu_bound)(struct pci_dev *dev, enum vga_switcheroo_client_id);
};
--
2.54.0
^ permalink raw reply related
* [PATCH v2 7/7] vga-switcheroo: Remove unused interfaces
From: Thomas Zimmermann @ 2026-07-09 9:16 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
Remove all unused interfaces that used to implement the functionality
of pre_switch and post_switch.
For pre_switch, remove vga_switcheroo_client_fb_set(). This further
allows for removing all symbols and data structures that refer to
fbdev; such as fb_info and fb_switch_outputs().
For post_switch, remove the reprobe callback from the client ops.
v2:
- move changes to fbcon and drivers into other patches
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/vga/vga_switcheroo.c | 37 ++++----------------------------
include/linux/vga_switcheroo.h | 12 +++++------
2 files changed, 9 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 7b0af4a8aa7d..9431d83b38a9 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -32,9 +32,9 @@
#include <linux/apple-gmux.h>
#include <linux/debugfs.h>
-#include <linux/fb.h>
+#include <linux/export.h>
#include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
@@ -90,7 +90,6 @@
/**
* struct vga_switcheroo_client - registered client
* @pdev: client pci device
- * @fb_info: framebuffer to which console is remapped on switching
* @pwr_state: current power state if manual power control is used.
* For driver power control, call vga_switcheroo_pwr_state().
* @ops: client callbacks
@@ -105,12 +104,11 @@
* @vga_dev: pci device, indicate which GPU is bound to current audio client
*
* Registered client. A client can be either a GPU or an audio device on a GPU.
- * For audio clients, the @fb_info and @active members are bogus. For GPU
- * clients, the @vga_dev is bogus.
+ * For audio clients, the @active member is bogus. For GPU clients, the @vga_dev
+ * is bogus.
*/
struct vga_switcheroo_client {
struct pci_dev *pdev;
- struct fb_info *fb_info;
enum vga_switcheroo_state pwr_state;
const struct vga_switcheroo_client_ops *ops;
enum vga_switcheroo_client_id id;
@@ -514,27 +512,6 @@ void vga_switcheroo_unregister_client(struct pci_dev *pdev)
}
EXPORT_SYMBOL(vga_switcheroo_unregister_client);
-/**
- * vga_switcheroo_client_fb_set() - set framebuffer of a given client
- * @pdev: client pci device
- * @info: framebuffer
- *
- * Set framebuffer of a given client. The console will be remapped to this
- * on switching.
- */
-void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
- struct fb_info *info)
-{
- struct vga_switcheroo_client *client;
-
- mutex_lock(&vgasr_mutex);
- client = find_client_from_pci(&vgasr_priv.clients, pdev);
- if (client)
- client->fb_info = info;
- mutex_unlock(&vgasr_mutex);
-}
-EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
-
/**
* vga_switcheroo_lock_ddc() - temporarily switch DDC lines to a given client
* @pdev: client pci device
@@ -735,10 +712,6 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (new_client->ops->pre_switch)
new_client->ops->pre_switch(new_client->pdev);
-#if defined(CONFIG_FB)
- else if (new_client->fb_info)
- fb_switch_outputs(new_client->fb_info);
-#endif
mutex_lock(&vgasr_priv.mux_hw_lock);
ret = vgasr_priv.handler->switchto(new_client->id);
@@ -748,8 +721,6 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (new_client->ops->post_switch)
new_client->ops->post_switch(new_client->pdev);
- else if (new_client->ops->reprobe)
- new_client->ops->reprobe(new_client->pdev);
if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
vga_switchoff(active);
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 51851831d4c1..d7eee65664ab 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -31,8 +31,12 @@
#ifndef _LINUX_VGA_SWITCHEROO_H_
#define _LINUX_VGA_SWITCHEROO_H_
-#include <linux/fb.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+struct device;
+struct dev_pm_domain;
+struct fb_info;
struct pci_dev;
/**
@@ -127,7 +131,6 @@ struct vga_switcheroo_handler {
* @set_gpu_state: do the equivalent of suspend/resume for the card.
* Mandatory. This should not cut power to the discrete GPU,
* which is the job of the handler
- * @reprobe: deprecated
* @can_switch: check if the device is in a position to switch now.
* Mandatory. The client should return false if a user space process
* has one of its device files open
@@ -147,7 +150,6 @@ struct vga_switcheroo_handler {
*/
struct vga_switcheroo_client_ops {
void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
- void (*reprobe)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
void (*pre_switch)(struct pci_dev *dev);
void (*post_switch)(struct pci_dev *dev);
@@ -163,9 +165,6 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
struct pci_dev *vga_dev);
-void vga_switcheroo_client_fb_set(struct pci_dev *dev,
- struct fb_info *info);
-
int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags);
void vga_switcheroo_unregister_handler(void);
@@ -185,7 +184,6 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev);
static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
-static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
static inline int vga_switcheroo_register_handler(const struct vga_switcheroo_handler *handler,
enum vga_switcheroo_handler_flags_t handler_flags) { return 0; }
static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
--
2.54.0
^ permalink raw reply related
* [PATCH v2 3/7] vga_switcheroo: Add pre_switch callback to client ops
From: Thomas Zimmermann @ 2026-07-09 9:15 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
Add pre_switch to struct vga_switcheroo_client_ops to inform the
switcheroo client about upcoming switches of the outputs.
This callback is intended to replace the hard-coded call to fbdev's
fb_switch_outputs(). With DRM supporting more clients than just fbdev
emulation, something more flexible is required.
v2:
- remove non-sensical gpu_bound documentation (Sashiko)
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/vga/vga_switcheroo.c | 4 +++-
include/linux/vga_switcheroo.h | 11 ++++++++---
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 22cf52b78b75..bdf1e56ae891 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -733,8 +733,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (!active->driver_power_control)
set_audio_state(active->id, VGA_SWITCHEROO_OFF);
+ if (new_client->ops->pre_switch)
+ new_client->ops->pre_switch(new_client->pdev);
#if defined(CONFIG_FB)
- if (new_client->fb_info)
+ else if (new_client->fb_info)
fb_switch_outputs(new_client->fb_info);
#endif
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 7e6ac0114d55..4422daca9ceb 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -133,17 +133,22 @@ struct vga_switcheroo_handler {
* @can_switch: check if the device is in a position to switch now.
* Mandatory. The client should return false if a user space process
* has one of its device files open
+ * @pre_switch: prepare switch
+ * Optional. This gets called before switching the outputs to the
+ * GPU. Allows drivers to prepare for the switch.
* @gpu_bound: notify the client id to audio client when the GPU is bound.
*
* Client callbacks. A client can be either a GPU or an audio device on a GPU.
- * The @set_gpu_state and @can_switch methods are mandatory, @reprobe may be
- * set to NULL. For audio clients, the @reprobe member is bogus.
- * OTOH, @gpu_bound is only for audio clients, and not used for GPU clients.
+ * The @set_gpu_state and @can_switch methods are mandatory, @pre_switch and
+ * @reprobe may be set to NULL. For audio clients, the @pre_switch and
+ * @reprobe members are bogus. OTOH, @gpu_bound is only for audio clients,
+ * and not used for GPU clients.
*/
struct vga_switcheroo_client_ops {
void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
void (*reprobe)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
+ void (*pre_switch)(struct pci_dev *dev);
void (*gpu_bound)(struct pci_dev *dev, enum vga_switcheroo_client_id);
};
--
2.54.0
^ permalink raw reply related
* [PATCH v2 5/7] drm: Implement struct vga_switcheroo_client_ops.pre_switch
From: Thomas Zimmermann @ 2026-07-09 9:16 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
Call drm_client_dev_acquire_outputs() from vga_switcheroo's pre_switch
callback. Pushes fbcon updates from vga_switcheroo into DRM's fbdev
emulation. This affects amdgpu, i915, nouveau and radeon. No other
drivers implement vga_switcheroo.
Also remove the calls to vga_switcheroo_client_fb_set() from fbcon. It
is called from the DRM client's hotplug and sets the fbcon's framebuffer
at vga_switcheroo. Running pre_switch and hotplug concurrently could
result in a deadlock between clientlist_mutex and vgasr_mutex. Hence
clean up fbcon here as well.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Lyude Paul <lyude@redhat.com> # nouveau
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++++++
drivers/gpu/drm/i915/i915_switcheroo.c | 10 ++++++++++
drivers/gpu/drm/nouveau/nouveau_vga.c | 9 +++++++++
drivers/gpu/drm/radeon/radeon_device.c | 8 ++++++++
drivers/video/fbdev/core/fbcon.c | 8 --------
5 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 78c96c7102e4..87a59a79a019 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1699,10 +1699,18 @@ static bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&dev->open_count) == 0;
}
+static void amdgpu_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_client_dev_acquire_outputs(dev);
+}
+
static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
.set_gpu_state = amdgpu_switcheroo_set_state,
.reprobe = NULL,
.can_switch = amdgpu_switcheroo_can_switch,
+ .pre_switch = amdgpu_switcheroo_pre_switch,
};
/**
diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c
index 7e0791024282..6b306ece0556 100644
--- a/drivers/gpu/drm/i915/i915_switcheroo.c
+++ b/drivers/gpu/drm/i915/i915_switcheroo.c
@@ -5,6 +5,7 @@
#include <linux/vga_switcheroo.h>
+#include <drm/drm_client_event.h>
#include <drm/drm_print.h>
#include "display/intel_display_device.h"
@@ -58,10 +59,19 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
atomic_read(&i915->drm.open_count) == 0;
}
+static void i915_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct drm_i915_private *i915 = pdev_to_i915(pdev);
+
+ if (i915 && intel_display_device_present(i915->display))
+ drm_client_dev_acquire_outputs(&i915->drm);
+}
+
static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
.reprobe = NULL,
.can_switch = i915_switcheroo_can_switch,
+ .pre_switch = i915_switcheroo_pre_switch,
};
int i915_switcheroo_register(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index a6c375a24154..2d2d08be8fbe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -76,11 +76,20 @@ nouveau_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&drm->dev->open_count) == 0;
}
+static void
+nouveau_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct nouveau_drm *drm = pci_get_drvdata(pdev);
+
+ drm_client_dev_acquire_outputs(drm->dev);
+}
+
static const struct vga_switcheroo_client_ops
nouveau_switcheroo_ops = {
.set_gpu_state = nouveau_switcheroo_set_state,
.reprobe = nouveau_switcheroo_reprobe,
.can_switch = nouveau_switcheroo_can_switch,
+ .pre_switch = nouveau_switcheroo_pre_switch,
};
void
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 705c012fcf9e..8697a9eb5d13 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1258,10 +1258,18 @@ static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
return atomic_read(&dev->open_count) == 0;
}
+static void radeon_switcheroo_pre_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_client_dev_acquire_outputs(dev);
+}
+
static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
.set_gpu_state = radeon_switcheroo_set_state,
.reprobe = NULL,
.can_switch = radeon_switcheroo_can_switch,
+ .pre_switch = radeon_switcheroo_pre_switch,
};
/**
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 9f5c4c101581..974c7dcf5251 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -78,7 +78,6 @@
#include <linux/interrupt.h>
#include <linux/crc32.h> /* For counting font checksums */
#include <linux/uaccess.h>
-#include <linux/vga_switcheroo.h>
#include <asm/irq.h>
#include "fbcon.h"
@@ -2851,9 +2850,6 @@ void fbcon_fb_unregistered(struct fb_info *info)
console_lock();
- if (info->device && dev_is_pci(info->device))
- vga_switcheroo_client_fb_set(to_pci_dev(info->device), NULL);
-
fbcon_registered_fb[info->node] = NULL;
fbcon_num_registered_fb--;
@@ -2987,10 +2983,6 @@ static int do_fb_registered(struct fb_info *info)
}
}
- /* Set the fb info for vga_switcheroo clients. Does nothing otherwise. */
- if (info->device && dev_is_pci(info->device))
- vga_switcheroo_client_fb_set(to_pci_dev(info->device), info);
-
return ret;
}
--
2.54.0
^ permalink raw reply related
* [PATCH v2 1/7] drm/edid: Include <linux/fb.h>
From: Thomas Zimmermann @ 2026-07-09 9:15 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
We currently get <linux/fb.h> via <linux/vga_switcheroo.h>. Include it
explicitly.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/drm_edid.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 07970e5b5f65..86ae2d8d4de2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -32,6 +32,7 @@
#include <linux/byteorder/generic.h>
#include <linux/cec.h>
#include <linux/export.h>
+#include <linux/fb.h> /* for KHZ2PICOS() */
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
--
2.54.0
^ permalink raw reply related
* [PATCH v2 0/7] vga_switcheroo, drm: Push fbcon handling into DRM clients
From: Thomas Zimmermann @ 2026-07-09 9:15 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
Vga_switcheroo currently invokes fb_switch_outputs() to inform fbcon
about switching of the physical outputs among framebuffer devices. But
new DRM clients to not use fbdev/fbcon and might require their own
vga_switcheroo support. Let's strictly separate them from each other.
Remove fbdev/fbcon from vga_switcheroo. Introduce a pre_switch callback
for vga_switcheroo clients to do the fbcon update. Allows for removing
all direct interactions between vga_switcheroo and fbdev/fbcon.
There are only four drivers that support vga_switcheroo: amdgpu,
radeon, i915 and nouveau. Update each of them with the new callback.
When vga_switcheroo now invokes pre_switch, each DRM driver forwards
to aquire_outputs and lets the DRM clients handle the new outputs.
At the same time, push the fbcon update into DRM's client for fbdev
emulation. Do this with the new DRM client callback acquire_outputs,
so that other clients can have their own handling of vga_switcheroo.
Also replace the existing reprobe hook with post_switch for symetry.
For nouveau, this is merely a rename of the helper function. The other
drivers dor not implement reprobe.
Tested with radeon on a notebook with Radeon HD 4225 and HD 5430.
v2:
- implement all of pre_switch in a single commit to avoid possible
deadlock in intermediate state (Sashiko)
- fix erroneous docs (Sashiko)
Thomas Zimmermann (7):
drm/edid: Include <linux/fb.h>
drm/client: Add acquire_outputs callback; implement for fbdev
emulation
vga_switcheroo: Add pre_switch callback to client ops
vga_switcheroo: Add post_switch callback to client ops
drm: Implement struct vga_switcheroo_client_ops.pre_switch
drm: Implement vga_switcheroo_client_ops.post_switch
vga-switcheroo: Remove unused interfaces
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 9 ++++-
drivers/gpu/drm/clients/drm_fbdev_client.c | 23 ++++++++----
drivers/gpu/drm/drm_client_event.c | 18 ++++++++++
drivers/gpu/drm/drm_edid.c | 1 +
drivers/gpu/drm/i915/i915_switcheroo.c | 11 +++++-
drivers/gpu/drm/nouveau/nouveau_vga.c | 28 +++++++++------
drivers/gpu/drm/radeon/radeon_device.c | 9 ++++-
drivers/gpu/vga/vga_switcheroo.c | 41 +++++-----------------
drivers/video/fbdev/core/fbcon.c | 8 -----
include/drm/drm_client.h | 14 ++++++++
include/drm/drm_client_event.h | 3 ++
include/linux/vga_switcheroo.h | 29 ++++++++-------
12 files changed, 121 insertions(+), 73 deletions(-)
base-commit: 88c6be63ac7e9238c7791977d3f496ce6623afe4
--
2.54.0
^ permalink raw reply
* [PATCH v2 2/7] drm/client: Add acquire_outputs callback; implement for fbdev emulation
From: Thomas Zimmermann @ 2026-07-09 9:15 UTC (permalink / raw)
To: lukas, jfalempe, alexander.deucher, christian.koenig, airlied,
simona, maarten.lankhorst, mripard, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, lyude, dakr, deller
Cc: dri-devel, amd-gfx, intel-gfx, nouveau, linux-fbdev,
sashiko-reviews, Thomas Zimmermann
In-Reply-To: <20260709092215.168172-1-tzimmermann@suse.de>
Add the callback acquire_outputs to drm_client_funcs to inform an internal
DRM client that vga-switcheroo is about to switch the physical outputs to
the client's device. Allows the client to prepare its internal state for
the upcoming switch.
Wire up the DRM client helpers to invoke the helper for a device's
clients.
Implement acquire_outputs for fbdev emulation. Invoke fb_switch_outputs(),
which remaps framebuffers to virtual terminals in fbcon. Currently this
is still being done by vga-switcheroo. With more DRM clients becoming
available, vga-switcheroo needs to become client agonostic.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/gpu/drm/clients/drm_fbdev_client.c | 23 +++++++++++++++-------
drivers/gpu/drm/drm_client_event.c | 18 +++++++++++++++++
include/drm/drm_client.h | 14 +++++++++++++
include/drm/drm_client_event.h | 3 +++
4 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/clients/drm_fbdev_client.c b/drivers/gpu/drm/clients/drm_fbdev_client.c
index 91d196a397cf..827f32668714 100644
--- a/drivers/gpu/drm/clients/drm_fbdev_client.c
+++ b/drivers/gpu/drm/clients/drm_fbdev_client.c
@@ -47,6 +47,14 @@ static int drm_fbdev_client_restore(struct drm_client_dev *client, bool force)
return 0;
}
+static void drm_fbdev_client_acquire_outputs(struct drm_client_dev *client)
+{
+ struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+
+ if (fb_helper->info)
+ fb_switch_outputs(fb_helper->info);
+}
+
static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
@@ -95,13 +103,14 @@ static int drm_fbdev_client_resume(struct drm_client_dev *client)
}
static const struct drm_client_funcs drm_fbdev_client_funcs = {
- .owner = THIS_MODULE,
- .free = drm_fbdev_client_free,
- .unregister = drm_fbdev_client_unregister,
- .restore = drm_fbdev_client_restore,
- .hotplug = drm_fbdev_client_hotplug,
- .suspend = drm_fbdev_client_suspend,
- .resume = drm_fbdev_client_resume,
+ .owner = THIS_MODULE,
+ .free = drm_fbdev_client_free,
+ .unregister = drm_fbdev_client_unregister,
+ .restore = drm_fbdev_client_restore,
+ .acquire_outputs = drm_fbdev_client_acquire_outputs,
+ .hotplug = drm_fbdev_client_hotplug,
+ .suspend = drm_fbdev_client_suspend,
+ .resume = drm_fbdev_client_resume,
};
/**
diff --git a/drivers/gpu/drm/drm_client_event.c b/drivers/gpu/drm/drm_client_event.c
index 7b3e362f7926..f0af584da23c 100644
--- a/drivers/gpu/drm/drm_client_event.c
+++ b/drivers/gpu/drm/drm_client_event.c
@@ -123,6 +123,24 @@ void drm_client_dev_restore(struct drm_device *dev, bool force)
mutex_unlock(&dev->clientlist_mutex);
}
+void drm_client_dev_acquire_outputs(struct drm_device *dev)
+{
+ struct drm_client_dev *client;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return;
+
+ mutex_lock(&dev->clientlist_mutex);
+ list_for_each_entry(client, &dev->clientlist, list) {
+ if (!client->funcs || !client->funcs->acquire_outputs)
+ continue;
+
+ client->funcs->acquire_outputs(client);
+ }
+ mutex_unlock(&dev->clientlist_mutex);
+}
+EXPORT_SYMBOL(drm_client_dev_acquire_outputs);
+
static int drm_client_suspend(struct drm_client_dev *client)
{
struct drm_device *dev = client->dev;
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 49a21f3dcb36..10a0cae3e48f 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -66,6 +66,20 @@ struct drm_client_funcs {
*/
int (*restore)(struct drm_client_dev *client, bool force);
+ /**
+ * @acquire_outputs:
+ *
+ * Called by vga-switcheroo. Informs the client that the outputs will
+ * be switched to its device. When @acquire_outputs runs, the outputs
+ * have not been switched yet. The client should only prepare the software
+ * state. After the switch happened, the client might get a hotplug
+ * event to update the hardware state.
+ *
+ * This callback exists for remapping framebuffers to virtual terminals
+ * in fbcon.
+ */
+ void (*acquire_outputs)(struct drm_client_dev *client);
+
/**
* @hotplug:
*
diff --git a/include/drm/drm_client_event.h b/include/drm/drm_client_event.h
index 79369c755bc9..c93f404bae1d 100644
--- a/include/drm/drm_client_event.h
+++ b/include/drm/drm_client_event.h
@@ -11,6 +11,7 @@ struct drm_device;
void drm_client_dev_unregister(struct drm_device *dev);
void drm_client_dev_hotplug(struct drm_device *dev);
void drm_client_dev_restore(struct drm_device *dev, bool force);
+void drm_client_dev_acquire_outputs(struct drm_device *dev);
void drm_client_dev_suspend(struct drm_device *dev);
void drm_client_dev_resume(struct drm_device *dev);
#else
@@ -20,6 +21,8 @@ static inline void drm_client_dev_hotplug(struct drm_device *dev)
{ }
static inline void drm_client_dev_restore(struct drm_device *dev, bool force)
{ }
+static inline void drm_client_dev_acquire_outputs(struct drm_device *dev)
+{ }
static inline void drm_client_dev_suspend(struct drm_device *dev)
{ }
static inline void drm_client_dev_resume(struct drm_device *dev)
--
2.54.0
^ permalink raw reply related
* Re: [PATCH 13/13] mm/mremap: convert mremap code to use vma_flags_t
From: Zi Yan @ 2026-07-09 2:28 UTC (permalink / raw)
To: Lorenzo Stoakes, Lance Yang
Cc: akpm, tsbogend, maddy, mpe, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, l.stach, inki.dae, sw0312.kim,
kyungmin.park, krzk, peter.griffin, jani.nikula, joonas.lahtinen,
rodrigo.vivi, tursulin, robin.clark, lumag, lyude, dakr,
tomi.valkeinen, hjc, heiko, andy.yan, thierry.reding, mperttunen,
jonathanh, kraxel, dmitry.osipenko, zack.rusin, matthew.brost,
thomas.hellstrom, oleksandr_andrushchenko, deller, bcrl, viro,
brauner, muchun.song, osalvador, david, baolin.wang, liam, npache,
ryan.roberts, dev.jain, baohua, hughd, vbabka, rppt, surenb,
mhocko, jannh, pfalcato, kees, perex, tiwai, linux-mips,
linux-kernel, linuxppc-dev, dri-devel, etnaviv, linux-arm-kernel,
linux-samsung-soc, intel-gfx, linux-arm-msm, freedreno, nouveau,
linux-rockchip, linux-tegra, virtualization, intel-xe, xen-devel,
linux-fbdev, linux-aio, linux-fsdevel, linux-mm, linux-sound
In-Reply-To: <akaJx8Zt8kazlrjq@lucifer>
On Thu Jul 2, 2026 at 12:07 PM EDT, Lorenzo Stoakes wrote:
> On Thu, Jul 02, 2026 at 09:49:47PM +0800, Lance Yang wrote:
>>
>> On Mon, Jun 29, 2026 at 08:25:36PM +0100, Lorenzo Stoakes wrote:
>> >Replace use of the legacy vm_flags_t flags with vma_flags_t values
>> >throughout the mremap logic.
>> >
>> >Additionally update comments to reflect the changes to be consistent.
>> >
>> >No functional change intended.
>> >
>> >Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
>> >---
>>
>> The vm_flags_set() cases below spell out vma_start_write(), but the
>> vm_flags_clear() cases don't?
>
> Yep as I said elsewhere, implicitly taking the lock is terrible and me doing
> this is completely on purpose to get rid of that :)
>
> But I haven't been clear enough clearly, so I should put the argument as to why
> that's ok in the commit message.
>
> Will do so on respin.
How about also add a comment to vma_clear*() telling us a lock is not
needed and why like you explained a lock is needed for vma_set*()?
This asymmetry could confuse people.
This patch looks good to me.
Reviewed-by: Zi Yan <ziy@nvidia.com>
--
Best Regards,
Yan, Zi
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox