regmap-spi will split data and address between two transfers in the same message so use addr_affects_max_raw_rw to flag that the number bytes to read or write should be a little less (address + padding size), so that the SPI controller can merge the entire message into a single CS period Signed-off-by: Lucas Tanure <tanureal@xxxxxxxxxxxxxxxxxxxxx> --- drivers/base/regmap/regmap-spi.c | 14 ++++++++++++-- drivers/base/regmap/regmap.c | 9 +++++++++ include/linux/regmap.h | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 603a4c1c2066..0c1f2e51c0c7 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -115,12 +115,22 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi, struct spi_master *master = spi->master; struct regmap_bus *bus = NULL; - if (master->max_transfer_size) { + if (master->max_transfer_size || (master->flags & SPI_CONTROLLER_CS_PER_TRANSFER)) { bus = kmemdup(®map_spi, sizeof(*bus), GFP_KERNEL); if (!bus) return ERR_PTR(-ENOMEM); bus->free_on_exit = true; - bus->max_raw_read = bus->max_raw_write = master->max_transfer_size(spi); + + /* regmap-spi will split data and address between two transfers in the same message + * so use addr_affects_max_raw_rw to flag that the number bytes to read or write + * should be a little less (address + padding size), so the controller can + * fit both transfers in a single CS period + */ + bus->addr_affects_max_raw_rw = master->flags & SPI_CONTROLLER_CS_PER_TRANSFER; + + if (master->max_transfer_size) + bus->max_raw_read = bus->max_raw_write = master->max_transfer_size(spi); + return bus; } diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 6ad41d0720ba..31d0949b6c2f 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -815,6 +815,15 @@ struct regmap *__regmap_init(struct device *dev, if (bus) { map->max_raw_read = bus->max_raw_read; map->max_raw_write = bus->max_raw_write; + if (bus->addr_affects_max_raw_rw) { + if (map->max_raw_read < map->format.buf_size || + map->max_raw_write < map->format.buf_size) { + ret = -EINVAL; + goto err_name; + } + map->max_raw_read -= (map->format.reg_bytes + map->format.pad_bytes); + map->max_raw_write -= (map->format.reg_bytes + map->format.pad_bytes); + } } map->dev = dev; map->bus = bus; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 77755196277c..a90d1e270b1f 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -504,6 +504,7 @@ typedef void (*regmap_hw_free_context)(void *context); * @max_raw_read: Max raw read size that can be used on the bus. * @max_raw_write: Max raw write size that can be used on the bus. * @free_on_exit: kfree this on exit of regmap + * @addr_affects_max_raw_rw: max_raw_[read|write] must include the address and padding preamble */ struct regmap_bus { bool fast_io; @@ -522,6 +523,7 @@ struct regmap_bus { size_t max_raw_read; size_t max_raw_write; bool free_on_exit; + bool addr_affects_max_raw_rw; }; /* -- 2.33.0