On 02/05/2023 08:28, Jaewon Kim wrote: > Support interrupt based pio mode to optimize cpu usage. > When transmitting data size is larget than 32 bytes, operates with > interrupt based pio mode. > > By using the FIFORDY INT, an interrupt can be triggered when > the desired size of data has been received. Using this, we can support > interrupt based pio mode. > > Signed-off-by: Jaewon Kim <jaewon02.kim@xxxxxxxxxxx> > --- > drivers/spi/spi-s3c64xx.c | 66 ++++++++++++++++++++++++++++++++++----- > 1 file changed, 58 insertions(+), 8 deletions(-) > > diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c > index 2a8304678df9..323c6da9730b 100644 > --- a/drivers/spi/spi-s3c64xx.c > +++ b/drivers/spi/spi-s3c64xx.c > @@ -58,6 +58,8 @@ > #define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17) > #define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17) > #define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17) > +#define S3C64XX_SPI_MODE_RX_RDY_LVL GENMASK(16, 11) > +#define S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT 11 > #define S3C64XX_SPI_MODE_SELF_LOOPBACK (1<<3) > #define S3C64XX_SPI_MODE_RXDMA_ON (1<<2) > #define S3C64XX_SPI_MODE_TXDMA_ON (1<<1) > @@ -114,6 +116,8 @@ > > #define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT > > +#define S3C64XX_SPI_POLLING_SIZE 32 > + > #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) > #define is_polling(x) (x->cntrlr_info->polling) > > @@ -552,7 +556,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd, > } > > static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, > - struct spi_transfer *xfer) > + struct spi_transfer *xfer, bool use_irq) > { > void __iomem *regs = sdd->regs; > unsigned long val; > @@ -573,6 +577,12 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, > if (RX_FIFO_LVL(status, sdd) < xfer->len) > usleep_range(time_us / 2, time_us); > > + if (use_irq) { > + val = msecs_to_jiffies(ms); > + if (!wait_for_completion_timeout(&sdd->xfer_completion, val)) > + return -EIO; > + } > + > val = msecs_to_loops(ms); > do { > status = readl(regs + S3C64XX_SPI_STATUS); > @@ -735,10 +745,13 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, > void *rx_buf = NULL; > int target_len = 0, origin_len = 0; > int use_dma = 0; > + bool use_irq = false; > int status; > u32 speed; > u8 bpw; > unsigned long flags; > + u32 rdy_lv; > + u32 val; > > reinit_completion(&sdd->xfer_completion); > > @@ -759,17 +772,46 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, > sdd->rx_dma.ch && sdd->tx_dma.ch) { > use_dma = 1; > > - } else if (xfer->len > fifo_len) { > + } else if (xfer->len >= fifo_len) { I don't fully understand this. If len equals to fifo_len, everything would fit into FIFO so no need for all this? > tx_buf = xfer->tx_buf; > rx_buf = xfer->rx_buf; > origin_len = xfer->len; > - > target_len = xfer->len; > - if (xfer->len > fifo_len) > - xfer->len = fifo_len; > + xfer->len = fifo_len - 1; > } > > do { > + /* transfer size is greater than 32, change to IRQ mode */ > + if (xfer->len > S3C64XX_SPI_POLLING_SIZE) > + use_irq = true; > + > + if (use_irq) { > + reinit_completion(&sdd->xfer_completion); > + > + rdy_lv = xfer->len; Style is: /* * > + /* Setup RDY_FIFO trigger Level > + * RDY_LVL = > + * fifo_lvl up to 64 byte -> N bytes > + * 128 byte -> RDY_LVL * 2 bytes > + * 256 byte -> RDY_LVL * 4 bytes I don't understand it. Based on this equation for 256 bytes, RDY_LVL = RDY_LVL * 4? Didn't you mean xfer->len? Best regards, Krzysztof