mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Khalil <khalilst@gmail.com>
To: broonie@kernel.org, hdegoede@kernel.org, ilpo.jarvinen@linux.intel.com
Cc: rf@opensource.cirrus.com, linux-spi@vger.kernel.org,
	platform-driver-x86@vger.kernel.org,
	linux-kernel@vger.kernel.org, Khalil Laleh <khalilst@gmail.com>
Subject: [RFC PATCH 1/2] platform/x86: serial-multi-instantiate: Add GPIO chip select support for SPI devices
Date: Sun, 15 Feb 2026 14:55:23 +0100	[thread overview]
Message-ID: <20260215135524.1171065-2-khalil@rentman.nl> (raw)
In-Reply-To: <20260215135524.1171065-1-khalil@rentman.nl>

To: broonie@kernel.org, hdegoede@kernel.org, ilpo.jarvinen@linux.intel.com
Cc: rf@opensource.cirrus.com, linux-spi@vger.kernel.org,
    platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org

Some ACPI platforms (e.g., HP/ASUS laptops with Intel Lunar Lake and
dual CS35L56 amplifiers) have a broken cs-gpios property in the SPI
controller's _DSD that only declares the first chip select. The second
chip select GPIO is defined as a GpioIo resource in the peripheral's
ACPI node but is not referenced by the controller.

This causes the SPI framework to have no GPIO descriptor for CS > 0,
so the chip select line is never toggled for the second device.

Fix this by acquiring the chip select GPIO from the ACPI GpioIo resource
in serial-multi-instantiate and installing it on the controller's
cs_gpiods array. The GPIO must be set on the controller (not the device)
because __spi_add_device() unconditionally overwrites spi->cs_gpiod[]
from ctlr->cs_gpiods[cs].

The controller's cs_gpiods array is reallocated to accommodate the
additional chip select, and SPI_CONTROLLER_GPIO_SS is set so the
framework calls both the GPIO toggle and the controller's set_cs
callback (needed for clock gate management on Intel LPSS controllers).

Link: https://bugzilla.kernel.org/show_bug.cgi?id=221064
Link: https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/2131138
Link: https://github.com/thesofproject/linux/issues/5621
Signed-off-by: Khalil Laleh <khalilst@gmail.com>
---
 drivers/platform/x86/serial-multi-instantiate.c | 83 ++++++++++++++++++
 1 file changed, 83 insertions(+)

--- a/drivers/platform/x86/serial-multi-instantiate.c
+++ b/drivers/platform/x86/serial-multi-instantiate.c
@@ -8,6 +8,9 @@

 #include <linux/acpi.h>
 #include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -17,6 +20,17 @@
 #include <linux/spi/spi.h>
 #include <linux/types.h>

+/*
+ * ACPI GPIO mapping for the chip select GpioIo resource.
+ * Maps "cs-gpios" to the first GpioIo resource in the ACPI _CRS.
+ */
+static const struct acpi_gpio_params smi_cs_gpio_params = { 0, 0, false };
+
+static const struct acpi_gpio_mapping smi_cs_gpio_mapping[] = {
+	{ "cs-gpios", &smi_cs_gpio_params, 1 },
+	{ }
+};
+
 #define IRQ_RESOURCE_TYPE	GENMASK(1, 0)
 #define IRQ_RESOURCE_NONE	0
 #define IRQ_RESOURCE_GPIO	1
@@ -114,8 +128,11 @@
 	struct acpi_device *adev = ACPI_COMPANION(dev);
 	struct spi_controller *ctlr;
 	struct spi_device *spi_dev;
+	struct gpio_desc *cs_gpio = NULL;
 	char name[50];
 	int i, ret, count;
+	bool gpio_mapped = false;
+	u16 cs;

 	ret = acpi_spi_count_resources(adev);
 	if (ret < 0)
@@ -139,6 +156,72 @@
 		}

 		ctlr = spi_dev->controller;
+		cs = spi_get_chipselect(spi_dev, 0);
+
+		if (cs >= ctlr->num_chipselect) {
+			dev_info(dev, "Increasing num_chipselect from %u to %u for CS%u\n",
+				 ctlr->num_chipselect, cs + 1, cs);
+			ctlr->num_chipselect = cs + 1;
+		}
+
+		/*
+		 * For devices with CS > 0, use GPIO chip select from ACPI
+		 * GpioIo resource. The GPIO must be set on the controller's
+		 * cs_gpiods array (not the device's cs_gpiod) because
+		 * __spi_add_device() overwrites spi->cs_gpiod from
+		 * ctlr->cs_gpiods[cs]. Also reallocate the array since
+		 * a broken ACPI cs-gpios property may have undersized it.
+		 *
+		 * SPI_CONTROLLER_GPIO_SS ensures the framework calls both
+		 * the GPIO toggle and controller->set_cs (for clock gate
+		 * management on Intel LPSS controllers).
+		 */
+		if (cs > 0 && !gpio_mapped) {
+			ret = devm_acpi_dev_add_driver_gpios(dev, smi_cs_gpio_mapping);
+			if (ret)
+				dev_warn(dev, "Failed to add GPIO mapping: %d\n", ret);
+			else
+				gpio_mapped = true;
+		}
+
+		if (cs > 0 && gpio_mapped && !cs_gpio) {
+			cs_gpio = devm_gpiod_get(dev, "cs", GPIOD_OUT_HIGH);
+			if (IS_ERR(cs_gpio)) {
+				dev_warn(dev, "Failed to get CS GPIO: %ld\n",
+					 PTR_ERR(cs_gpio));
+				cs_gpio = NULL;
+			} else {
+				dev_info(dev, "Got CS GPIO for amp CS%u\n", cs);
+			}
+		}
+
+		if (cs > 0 && cs_gpio) {
+			/*
+			 * Set GPIO on the controller's cs_gpiods array so
+			 * __spi_add_device() will propagate it to the device.
+			 * Reallocate the array to fit the new num_chipselect.
+			 */
+			struct gpio_desc **new_gpiods;
+
+			new_gpiods = devm_kcalloc(&ctlr->dev,
+						  ctlr->num_chipselect,
+						  sizeof(*new_gpiods),
+						  GFP_KERNEL);
+			if (new_gpiods) {
+				if (ctlr->cs_gpiods)
+					new_gpiods[0] = ctlr->cs_gpiods[0];
+				new_gpiods[cs] = cs_gpio;
+				ctlr->cs_gpiods = new_gpiods;
+				ctlr->flags |= SPI_CONTROLLER_GPIO_SS;
+				dev_info(dev, "Set GPIO CS on controller for CS%u\n", cs);
+			} else {
+				dev_err(dev, "Failed to alloc cs_gpiods\n");
+			}
+		}
+
+		dev_info(dev, "Device %d: CS=%u, num_chipselect=%u, gpio_cs=%s\n",
+			 i, cs, ctlr->num_chipselect,
+			 (cs > 0 && cs_gpio) ? "yes" : "no");

 		strscpy(spi_dev->modalias, inst_array[i].type);

  reply	other threads:[~2026-02-15 13:56 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-15 13:55 [RFC PATCH 0/2] Fix second CS35L56 amplifier on Intel LPSS SPI with broken ACPI cs-gpios Khalil
2026-02-15 13:55 ` Khalil [this message]
2026-02-23 15:50   ` [RFC PATCH 1/2] platform/x86: serial-multi-instantiate: Add GPIO chip select support for SPI devices Richard Fitzgerald
2026-04-11 18:04   ` [PATCH v2 0/3] Fix CS35L56 amplifier on Intel LPSS SPI with broken ACPI cs-gpios Khalil
2026-04-11 18:04     ` [PATCH 1/3] spi: Preserve preset cs_gpiod in __spi_add_device() Khalil
2026-04-11 18:04     ` [PATCH 2/3] platform/x86: serial-multi-instantiate: Fix SPI chip select on platforms with incomplete ACPI cs-gpios Khalil
2026-04-11 18:04     ` [PATCH 3/3] spi: pxa2xx: Handle clock gating for GPIO chip select devices Khalil
2026-04-11 21:57     ` [PATCH v2 0/3] Fix CS35L56 amplifier on Intel LPSS SPI with broken ACPI cs-gpios Mark Brown
2026-04-13  8:48       ` Richard Fitzgerald
2026-04-13  9:02         ` Richard Fitzgerald
2026-04-12 16:31   ` Khalil
2026-04-12 16:31     ` [PATCH 1/3] spi: Preserve preset cs_gpiod in __spi_add_device() Khalil
2026-04-12 16:31     ` [PATCH 2/3] platform/x86: serial-multi-instantiate: Fix SPI chip select on platforms with incomplete ACPI cs-gpios Khalil
2026-04-12 16:31     ` [PATCH 3/3] spi: pxa2xx: Handle clock gating for GPIO chip select devices Khalil
2026-02-15 13:55 ` [RFC PATCH 2/2] spi: pxa2xx: Handle dynamic " Khalil

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20260215135524.1171065-2-khalil@rentman.nl \
    --to=khalilst@gmail.com \
    --cc=broonie@kernel.org \
    --cc=hdegoede@kernel.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=rf@opensource.cirrus.com \
    /path/to/YOUR_REPLY

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

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

all inboxes | Powered by JetHome®