lede/target/linux/bcm27xx/patches-6.12/950-0372-spi-gpio-Fix-spi-gpio-to-correctly-implement-sck-idl.patch
=?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= d81c03f05e bcm27xx: add 6.12 patches from RPi repo
These patches were generated from:
https://github.com/raspberrypi/linux/commits/rpi-6.12.y
With the following command:
git format-patch -N v6.12.27..HEAD
(HEAD -> 8d3206ee456a5ecdf9ddbfd8e5e231e4f0cd716e)

Exceptions:
- (def)configs patches
- github workflows patches
- applied & reverted patches
- readme patches
- wireless patches

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2025-06-20 17:01:06 +08:00

135 lines
4.4 KiB
Diff

From 2d1edfd1b8332092022f0b5ee26c1263e63b1b8a Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Wed, 1 Mar 2023 17:57:11 +0000
Subject: [PATCH] spi: gpio: Fix spi-gpio to correctly implement sck-idle-input
Formerly, if configured using DT, CS GPIOs were driven from spi.c
and it was possible for CS to be asserted (low) *before* starting
to drive SCK. CS GPIOs have been brought under control of this
driver in both ACPI and DT cases, with a fixup for GPIO polarity.
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
drivers/spi/spi-gpio.c | 69 +++++++++++++++++++++++++++++-------------
1 file changed, 48 insertions(+), 21 deletions(-)
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -34,8 +34,9 @@ struct spi_gpio {
struct gpio_desc *sck;
struct gpio_desc *miso;
struct gpio_desc *mosi;
- bool sck_idle_input;
struct gpio_desc **cs_gpios;
+ bool sck_idle_input;
+ bool cs_dont_invert;
};
/*----------------------------------------------------------------------*/
@@ -232,12 +233,18 @@ static void spi_gpio_chipselect(struct s
gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL);
}
- /* Drive chip select line, if we have one */
+ /*
+ * Drive chip select line, if we have one.
+ * SPI chip selects are normally active-low, but when
+ * cs_dont_invert is set, we assume their polarity is
+ * controlled by the GPIO, and write '1' to assert.
+ */
if (spi_gpio->cs_gpios) {
struct gpio_desc *cs = spi_gpio->cs_gpios[spi_get_chipselect(spi, 0)];
+ int val = ((spi->mode & SPI_CS_HIGH) || spi_gpio->cs_dont_invert) ?
+ is_active : !is_active;
- /* SPI chip selects are normally active-low */
- gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+ gpiod_set_value_cansleep(cs, val);
}
if (spi_gpio->sck_idle_input && !is_active)
@@ -261,11 +268,14 @@ static int spi_gpio_setup(struct spi_dev
/*
* The CS GPIOs have already been
* initialized from the descriptor lookup.
+ * Here we set them to the non-asserted state.
*/
if (spi_gpio->cs_gpios) {
cs = spi_gpio->cs_gpios[spi_get_chipselect(spi, 0)];
if (!spi->controller_state && cs) {
- ret = gpiod_direction_output(cs, !(spi->mode & SPI_CS_HIGH));
+ ret = gpiod_direction_output(cs,
+ !((spi->mode & SPI_CS_HIGH) ||
+ spi_gpio->cs_dont_invert));
if (ret)
return ret;
}
@@ -342,13 +352,43 @@ static int spi_gpio_request(struct devic
return PTR_ERR_OR_ZERO(spi_gpio->sck);
}
+/*
+ * In order to implement "sck-idle-input" (which requires SCK
+ * direction and CS level to be switched in a particular order),
+ * we need to control GPIO chip selects from within this driver.
+ */
+
+static int spi_gpio_probe_get_cs_gpios(struct device *dev,
+ struct spi_controller *master,
+ bool gpio_defines_polarity)
+{
+ int i;
+ struct spi_gpio *spi_gpio = spi_controller_get_devdata(master);
+
+ spi_gpio->cs_dont_invert = gpio_defines_polarity;
+ spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect,
+ sizeof(*spi_gpio->cs_gpios),
+ GFP_KERNEL);
+ if (!spi_gpio->cs_gpios)
+ return -ENOMEM;
+
+ for (i = 0; i < master->num_chipselect; i++) {
+ spi_gpio->cs_gpios[i] =
+ devm_gpiod_get_index(dev, "cs", i,
+ gpio_defines_polarity ?
+ GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
+ if (IS_ERR(spi_gpio->cs_gpios[i]))
+ return PTR_ERR(spi_gpio->cs_gpios[i]);
+ }
+
+ return 0;
+}
+
static int spi_gpio_probe_pdata(struct platform_device *pdev,
struct spi_controller *host)
{
struct device *dev = &pdev->dev;
struct spi_gpio_platform_data *pdata = dev_get_platdata(dev);
- struct spi_gpio *spi_gpio = spi_controller_get_devdata(host);
- int i;
#ifdef GENERIC_BITBANG
if (!pdata || !pdata->num_chipselect)
@@ -360,20 +400,7 @@ static int spi_gpio_probe_pdata(struct p
*/
host->num_chipselect = pdata->num_chipselect ?: 1;
- spi_gpio->cs_gpios = devm_kcalloc(dev, host->num_chipselect,
- sizeof(*spi_gpio->cs_gpios),
- GFP_KERNEL);
- if (!spi_gpio->cs_gpios)
- return -ENOMEM;
-
- for (i = 0; i < host->num_chipselect; i++) {
- spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", i,
- GPIOD_OUT_HIGH);
- if (IS_ERR(spi_gpio->cs_gpios[i]))
- return PTR_ERR(spi_gpio->cs_gpios[i]);
- }
-
- return 0;
+ return spi_gpio_probe_get_cs_gpios(dev, host, false);
}
static int spi_gpio_probe(struct platform_device *pdev)