Re: [PATCH v7 4/7] iio: dac: ad5686: implement new sync() op for the spi bus
David Lechner <[email protected]>
| Newsgroups | org.kernel.vger.linux-hardening,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-iio,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 7/10/26 6:20 AM, Rodrigo Alencar via B4 Relay wrote: > From: Rodrigo Alencar <[email protected]> > > Use of local SPI bus data to manage a collection of SPI transfers and > flush them to the SPI platform driver with the sync() operation. This > allows for faster handling of multiple channel DAC writes, avoiding kernel > overhead per spi_sync() call, which will be helpful when enabling > triggered buffer support. > > Signed-off-by: Rodrigo Alencar <[email protected]> > --- > drivers/iio/dac/ad5686-spi.c | 129 ++++++++++++++++++++++++++++++++----------- > drivers/iio/dac/ad5686.c | 4 +- > drivers/iio/dac/ad5686.h | 8 ++- > drivers/iio/dac/ad5696-i2c.c | 2 +- > 4 files changed, 108 insertions(+), 35 deletions(-) > > diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c > index d3b64b4361d5..ae74a17ba48e 100644 > --- a/drivers/iio/dac/ad5686-spi.c > +++ b/drivers/iio/dac/ad5686-spi.c > @@ -13,59 +13,95 @@ > #include <linux/errno.h> > #include <linux/mod_devicetable.h> > #include <linux/module.h> > +#include <linux/overflow.h> > #include <linux/spi/spi.h> > > #include <asm/byteorder.h> > > #include "ad5686.h" > > +/** > + * struct ad5686_spi_data - SPI bus specific data > + * @msg: SPI message used for transfers > + * @size: number of transfers currently in the message > + * @capacity: maximum number of transfers that can be added to the message > + * @xfers: array of SPI transfers, allocated with the provided capacity > + */ > +struct ad5686_spi_data { > + struct spi_message msg; > + unsigned int size; > + unsigned int capacity; > + struct spi_transfer xfers[] __counted_by(capacity); > +}; > + > static int ad5686_spi_write(struct ad5686_state *st, > u8 cmd, u8 addr, u16 val) > { > - struct spi_device *spi = to_spi_device(st->dev); > - u8 tx_len, *buf; > + struct ad5686_spi_data *bus_data = st->bus_data; > + struct spi_transfer *xfer; > This could use some comments similar to the explanation in the commit message that this function is just queuing writes to be sent over the bus when sync() is called. > + if (bus_data->size >= bus_data->capacity) > + return -E2BIG; > + > + if (bus_data->size) > + bus_data->xfers[bus_data->size - 1].cs_change = 1; > + else > + spi_message_init(&bus_data->msg); > + > + xfer = &bus_data->xfers[bus_data->size]; Why not a local variable for st->data[bus_data->size] too so we don't have to write it so many times? > switch (st->chip_info->regmap_type) { > case AD5310_REGMAP: > - st->data[0].d16 = cpu_to_be16(FIELD_PREP(AD5310_CMD_MSK, cmd) | > - FIELD_PREP(AD5310_DATA_MSK, val)); > - buf = &st->data[0].d8[0]; > - tx_len = 2; > + st->data[bus_data->size].d16 = > + cpu_to_be16(FIELD_PREP(AD5310_CMD_MSK, cmd) | > + FIELD_PREP(AD5310_DATA_MSK, val)); > + *xfer = (struct spi_transfer) { > + .tx_buf = &st->data[bus_data->size].d16, > + .len = sizeof(st->data[bus_data->size].d16), > + }; > break; > case AD5683_REGMAP: > - st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | > - FIELD_PREP(AD5683_DATA_MSK, val)); > - buf = &st->data[0].d8[1]; > - tx_len = 3; > + st->data[bus_data->size].d32 = > + cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | > + FIELD_PREP(AD5683_DATA_MSK, val)); > + *xfer = (struct spi_transfer) { > + .tx_buf = &st->data[bus_data->size].d8[1], > + .len = sizeof(st->data[bus_data->size].d8) - 1, > + }; > break; > case AD5686_REGMAP: > - st->data[0].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | > - FIELD_PREP(AD5686_ADDR_MSK, addr) | > - FIELD_PREP(AD5686_DATA_MSK, val)); > - buf = &st->data[0].d8[1]; > - tx_len = 3; > + st->data[bus_data->size].d32 = > + cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, cmd) | > + FIELD_PREP(AD5686_ADDR_MSK, addr) | > + FIELD_PREP(AD5686_DATA_MSK, val)); > + *xfer = (struct spi_transfer) { > + .tx_buf = &st->data[bus_data->size].d8[1], > + .len = sizeof(st->data[bus_data->size].d8) - 1, > + }; > break; > default: > return -EINVAL; > } > > - return spi_write(spi, buf, tx_len); > + spi_message_add_tail(xfer, &bus_data->msg); > + bus_data->size++; > + > + return 0; > +} > + > +static int ad5686_spi_sync(struct ad5686_state *st) > +{ > + struct spi_device *spi = to_spi_device(st->dev); > + struct ad5686_spi_data *bus_data = st->bus_data; > + > + bus_data->size = 0; /* always reset, even on sync failure */ > + return spi_sync(spi, &bus_data->msg); > } > > static int ad5686_spi_read(struct ad5686_state *st, u8 addr) > { > - struct spi_transfer t[] = { > - { > - .tx_buf = &st->data[0].d8[1], > - .len = 3, > - .cs_change = 1, > - }, { > - .tx_buf = &st->data[1].d8[1], > - .rx_buf = &st->data[2].d8[1], > - .len = 3, > - }, > - }; > struct spi_device *spi = to_spi_device(st->dev); > + struct ad5686_spi_data *bus_data = st->bus_data; > + struct spi_transfer *xfer = &bus_data->xfers[0]; It would be nice if the commit message also explained why the read() function needs to be changed to use bus_data. > u8 cmd = 0; > int ret; > > @@ -86,8 +122,21 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) > FIELD_PREP(AD5686_ADDR_MSK, addr)); > st->data[1].d32 = cpu_to_be32(FIELD_PREP(AD5686_CMD_MSK, AD5686_CMD_NOOP)); > > - ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); > - if (ret < 0) > + xfer[0] = (struct spi_transfer) { > + .tx_buf = &st->data[0].d8[1], > + .len = sizeof(st->data[0].d8) - 1, > + .cs_change = 1, > + }; > + xfer[1] = (struct spi_transfer) { > + .tx_buf = &st->data[1].d8[1], > + .rx_buf = &st->data[2].d8[1], > + .len = sizeof(st->data[1].d8) - 1, > + }; > + > + spi_message_init_with_transfers(&bus_data->msg, xfer, 2); > + > + ret = spi_sync(spi, &bus_data->msg); > + if (ret) > return ret; > > return be32_to_cpu(st->data[2].d32);