[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250915183725.219473-3-jonas.gorski@gmail.com>
Date: Mon, 15 Sep 2025 20:37:20 +0200
From: Jonas Gorski <jonas.gorski@...il.com>
To: Mark Brown <broonie@...nel.org>,
Amit Kumar Mahapatra <amit.kumar-mahapatra@....com>
Cc: linux-spi@...r.kernel.org,
linux-kernel@...r.kernel.org,
Marc Kleine-Budde <mkl@...gutronix.de>
Subject: [PATCH v2 2/7] spi: keep track of number of chipselects in spi_device
There are several places where we need to iterate over a device's
chipselect. To be able to do it efficiently, store the number of
chipselects in spi_device, like we do for controllers.
Since we now use a device supplied value, add a check to make sure it
isn't more than we can support.
Signed-off-by: Jonas Gorski <jonas.gorski@...il.com>
---
Changes v1 -> v2:
* no changes
drivers/spi/spi.c | 29 +++++++++++++++++++++--------
include/linux/spi/spi.h | 4 +++-
2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b07d6cdf587c..6598fb862d80 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -586,6 +586,7 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
spi->mode = ctlr->buswidth_override_bits;
+ spi->num_chipselect = 1;
device_initialize(&spi->dev);
return spi;
@@ -635,7 +636,7 @@ static inline int spi_dev_check_cs(struct device *dev,
u8 idx_new;
cs = spi_get_chipselect(spi, idx);
- for (idx_new = new_idx; idx_new < SPI_CS_CNT_MAX; idx_new++) {
+ for (idx_new = new_idx; idx_new < new_spi->num_chipselect; idx_new++) {
cs_new = spi_get_chipselect(new_spi, idx_new);
if (is_valid_cs(cs) && is_valid_cs(cs_new) && cs == cs_new) {
dev_err(dev, "chipselect %u already in use\n", cs_new);
@@ -652,7 +653,7 @@ static int spi_dev_check(struct device *dev, void *data)
int status, idx;
if (spi->controller == new_spi->controller) {
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
status = spi_dev_check_cs(dev, spi, idx, new_spi, 0);
if (status)
return status;
@@ -674,7 +675,13 @@ static int __spi_add_device(struct spi_device *spi)
int status, idx;
u8 cs;
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
+ if (spi->num_chipselect > SPI_CS_CNT_MAX) {
+ dev_err(dev, "num_cs %d > max %d\n", spi->num_chipselect,
+ SPI_CS_CNT_MAX);
+ return -EOVERFLOW;
+ }
+
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
/* Chipselects are numbered 0..max; validate. */
cs = spi_get_chipselect(spi, idx);
if (is_valid_cs(cs) && cs >= ctlr->num_chipselect) {
@@ -689,7 +696,7 @@ static int __spi_add_device(struct spi_device *spi)
* For example, spi->chip_select[0] != spi->chip_select[1] and so on.
*/
if (!spi_controller_is_target(ctlr)) {
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
status = spi_dev_check_cs(dev, spi, idx, spi, idx + 1);
if (status)
return status;
@@ -717,7 +724,7 @@ static int __spi_add_device(struct spi_device *spi)
if (ctlr->cs_gpiods) {
u8 cs;
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
cs = spi_get_chipselect(spi, idx);
if (is_valid_cs(cs))
spi_set_csgpiod(spi, idx, ctlr->cs_gpiods[cs]);
@@ -1024,7 +1031,7 @@ static void spi_res_release(struct spi_controller *ctlr, struct spi_message *mes
/*-------------------------------------------------------------------------*/
#define spi_for_each_valid_cs(spi, idx) \
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) \
+ for (idx = 0; idx < spi->num_chipselect; idx++) \
if (!(spi->cs_index_mask & BIT(idx))) {} else
static inline bool spi_is_last_cs(struct spi_device *spi)
@@ -1080,8 +1087,12 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
trace_spi_set_cs(spi, activate);
spi->controller->last_cs_index_mask = spi->cs_index_mask;
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++)
- spi->controller->last_cs[idx] = enable ? spi_get_chipselect(spi, 0) : SPI_INVALID_CS;
+ for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
+ if (enable && idx < spi->num_chipselect)
+ spi->controller->last_cs[idx] = spi_get_chipselect(spi, 0);
+ else
+ spi->controller->last_cs[idx] = SPI_INVALID_CS;
+ }
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
if (spi->controller->last_cs_mode_high)
@@ -2452,6 +2463,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
dev_err(&ctlr->dev, "SPI controller doesn't support multi CS\n");
return -EINVAL;
}
+
+ spi->num_chipselect = rc;
for (idx = 0; idx < rc; idx++)
spi_set_chipselect(spi, idx, cs[idx]);
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index e9ea43234d9a..49c048277e97 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -170,6 +170,7 @@ extern void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
* two delays will be added up.
* @chip_select: Array of physical chipselect, spi->chipselect[i] gives
* the corresponding physical CS for logical CS i.
+ * @num_chipselect: Number of physical chipselects used.
* @cs_index_mask: Bit mask of the active chipselect(s) in the chipselect array
* @cs_gpiod: Array of GPIO descriptors of the corresponding chipselect lines
* (optional, NULL when not using a GPIO line)
@@ -229,6 +230,7 @@ struct spi_device {
struct spi_delay cs_inactive;
u8 chip_select[SPI_CS_CNT_MAX];
+ u8 num_chipselect;
/*
* Bit mask of the chipselect(s) that the driver need to use from
@@ -315,7 +317,7 @@ static inline bool spi_is_csgpiod(struct spi_device *spi)
{
u8 idx;
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
if (spi_get_csgpiod(spi, idx))
return true;
}
--
2.43.0
Powered by blists - more mailing lists