summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/spi-cadence-quadspi.c2
-rw-r--r--drivers/spi/spi.c75
-rw-r--r--include/linux/spi/spi.h16
3 files changed, 42 insertions, 51 deletions
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index af253b86f1ab..2ce4fc136a51 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -33,7 +33,7 @@
#define CQSPI_NAME "cadence-qspi"
#define CQSPI_MAX_CHIPSELECT 4
-static_assert(CQSPI_MAX_CHIPSELECT <= SPI_CS_CNT_MAX);
+static_assert(CQSPI_MAX_CHIPSELECT <= SPI_DEVICE_CS_CNT_MAX);
/* Quirks */
#define CQSPI_NEEDS_WR_DELAY BIT(0)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index f95c4304df8e..2e0647a06890 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;
@@ -622,11 +623,6 @@ static void spi_dev_set_name(struct spi_device *spi)
*/
#define SPI_INVALID_CS ((s8)-1)
-static inline bool is_valid_cs(s8 chip_select)
-{
- return chip_select != SPI_INVALID_CS;
-}
-
static inline int spi_dev_check_cs(struct device *dev,
struct spi_device *spi, u8 idx,
struct spi_device *new_spi, u8 new_idx)
@@ -635,9 +631,9 @@ 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) {
+ if (cs == cs_new) {
dev_err(dev, "chipselect %u already in use\n", cs_new);
return -EBUSY;
}
@@ -652,7 +648,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,10 +670,16 @@ 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_DEVICE_CS_CNT_MAX) {
+ dev_err(dev, "num_cs %d > max %d\n", spi->num_chipselect,
+ SPI_DEVICE_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) {
+ if (cs >= ctlr->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, idx),
ctlr->num_chipselect);
return -EINVAL;
@@ -689,13 +691,17 @@ 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;
}
}
+ /* Initialize unused logical CS as invalid */
+ for (idx = spi->num_chipselect; idx < SPI_DEVICE_CS_CNT_MAX; idx++)
+ spi_set_chipselect(spi, idx, SPI_INVALID_CS);
+
/* Set the bus ID string */
spi_dev_set_name(spi);
@@ -717,10 +723,9 @@ 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]);
+ spi_set_csgpiod(spi, idx, ctlr->cs_gpiods[cs]);
}
}
@@ -773,14 +778,6 @@ int spi_add_device(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_add_device);
-static void spi_set_all_cs_unused(struct spi_device *spi)
-{
- u8 idx;
-
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++)
- spi_set_chipselect(spi, idx, SPI_INVALID_CS);
-}
-
/**
* spi_new_device - instantiate one new SPI device
* @ctlr: Controller to which device is connected
@@ -816,7 +813,6 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
/* Use provided chip-select for proxy device */
- spi_set_all_cs_unused(proxy);
spi_set_chipselect(proxy, 0, chip->chip_select);
proxy->max_speed_hz = chip->max_speed_hz;
@@ -1024,7 +1020,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 +1076,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_DEVICE_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)
@@ -2354,7 +2354,7 @@ static void of_spi_parse_dt_cs_delay(struct device_node *nc,
static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
struct device_node *nc)
{
- u32 value, cs[SPI_CS_CNT_MAX];
+ u32 value, cs[SPI_DEVICE_CS_CNT_MAX];
int rc, idx;
/* Mode (clock phase/polarity/etc.) */
@@ -2427,31 +2427,22 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
return 0;
}
- if (ctlr->num_chipselect > SPI_CS_CNT_MAX) {
- dev_err(&ctlr->dev, "No. of CS is more than max. no. of supported CS\n");
- return -EINVAL;
- }
-
- spi_set_all_cs_unused(spi);
-
/* Device address */
rc = of_property_read_variable_u32_array(nc, "reg", &cs[0], 1,
- SPI_CS_CNT_MAX);
+ SPI_DEVICE_CS_CNT_MAX);
if (rc < 0) {
dev_err(&ctlr->dev, "%pOF has no valid 'reg' property (%d)\n",
nc, rc);
return rc;
}
- if (rc > ctlr->num_chipselect) {
- dev_err(&ctlr->dev, "%pOF has number of CS > ctlr->num_chipselect (%d)\n",
- nc, rc);
- return rc;
- }
+
if ((of_property_present(nc, "parallel-memories")) &&
(!(ctlr->flags & SPI_CONTROLLER_MULTI_CS))) {
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]);
@@ -2576,7 +2567,6 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
strscpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
/* Use provided chip-select for ancillary device */
- spi_set_all_cs_unused(ancillary);
spi_set_chipselect(ancillary, 0, chip_select);
/* Take over SPI mode/speed from SPI main device */
@@ -2824,7 +2814,6 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
return ERR_PTR(-ENOMEM);
}
- spi_set_all_cs_unused(spi);
spi_set_chipselect(spi, 0, lookup.chip_select);
ACPI_COMPANION_SET(&spi->dev, adev);
@@ -3324,7 +3313,7 @@ int spi_register_controller(struct spi_controller *ctlr)
}
/* Setting last_cs to SPI_INVALID_CS means no chip selected */
- for (idx = 0; idx < SPI_CS_CNT_MAX; idx++)
+ for (idx = 0; idx < SPI_DEVICE_CS_CNT_MAX; idx++)
ctlr->last_cs[idx] = SPI_INVALID_CS;
status = device_add(&ctlr->dev);
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index e9ea43234d9a..cb2c2df31089 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -21,7 +21,7 @@
#include <uapi/linux/spi/spi.h>
/* Max no. of CS supported per spi device */
-#define SPI_CS_CNT_MAX 24
+#define SPI_DEVICE_CS_CNT_MAX 4
struct dma_chan;
struct software_node;
@@ -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)
@@ -228,7 +229,8 @@ struct spi_device {
struct spi_delay cs_hold;
struct spi_delay cs_inactive;
- u8 chip_select[SPI_CS_CNT_MAX];
+ u8 chip_select[SPI_DEVICE_CS_CNT_MAX];
+ u8 num_chipselect;
/*
* Bit mask of the chipselect(s) that the driver need to use from
@@ -236,9 +238,9 @@ struct spi_device {
* multiple chip selects & memories are connected in parallel
* then more than one bit need to be set in cs_index_mask.
*/
- u32 cs_index_mask : SPI_CS_CNT_MAX;
+ u32 cs_index_mask : SPI_DEVICE_CS_CNT_MAX;
- struct gpio_desc *cs_gpiod[SPI_CS_CNT_MAX]; /* Chip select gpio desc */
+ struct gpio_desc *cs_gpiod[SPI_DEVICE_CS_CNT_MAX]; /* Chip select gpio desc */
/*
* Likely need more hooks for more protocol options affecting how
@@ -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;
}
@@ -719,8 +721,8 @@ struct spi_controller {
bool auto_runtime_pm;
bool fallback;
bool last_cs_mode_high;
- s8 last_cs[SPI_CS_CNT_MAX];
- u32 last_cs_index_mask : SPI_CS_CNT_MAX;
+ s8 last_cs[SPI_DEVICE_CS_CNT_MAX];
+ u32 last_cs_index_mask : SPI_DEVICE_CS_CNT_MAX;
struct completion xfer_completion;
size_t max_dma_len;