#include <linux/interrupt.h>
 #include <linux/iopoll.h>
 #include <linux/log2.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/reset.h>
 #define CSI_MODE_SETUP         0x00000040
 
 /* CSI_CLKSEL */
+#define CSI_CLKSEL_SS_ENA      BIT(19)
+#define CSI_CLKSEL_SS_POL      BIT(18)
+#define CSI_CLKSEL_SS          (CSI_CLKSEL_SS_ENA | CSI_CLKSEL_SS_POL)
 #define CSI_CLKSEL_CKP         BIT(17)
 #define CSI_CLKSEL_DAP         BIT(16)
 #define CSI_CLKSEL_MODE                (CSI_CLKSEL_CKP|CSI_CLKSEL_DAP)
 
 #define CSI_MAX_SPI_SCKO       (8 * HZ_PER_MHZ)
 
+#define CSI_CLKSEL_SS_DISABLED                 0
+#define CSI_CLKSEL_SS_ENABLED_ACTIVE_LOW       BIT(1)
+#define CSI_CLKSEL_SS_ENABLED_ACTIVE_HIGH      GENMASK(1, 0)
+
 struct rzv2m_csi_priv {
        void __iomem *base;
        struct clk *csiclk;
        wait_queue_head_t wait;
        u32 errors;
        u32 status;
+       bool target_aborted;
+       bool use_ss_pin;
 };
 
 static void rzv2m_csi_reg_write_bit(const struct rzv2m_csi_priv *csi,
        return 0;
 }
 
+static inline void rzv2m_csi_empty_rxfifo(struct rzv2m_csi_priv *csi)
+{
+       unsigned int i;
+
+       for (i = 0; i < csi->words_to_transfer; i++)
+               readl(csi->base + CSI_IFIFO);
+}
+
 static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
 {
        unsigned int bytes_transferred = max(csi->bytes_received, csi->bytes_sent);
 
        rzv2m_csi_enable_irqs(csi, enable_bits);
 
-       ret = wait_event_timeout(csi->wait,
-                                ((csi->status & wait_mask) == wait_mask) ||
-                                csi->errors, HZ);
+       if (spi_controller_is_target(csi->controller)) {
+               ret = wait_event_interruptible(csi->wait,
+                               ((csi->status & wait_mask) == wait_mask) ||
+                               csi->errors || csi->target_aborted);
+               if (ret || csi->target_aborted)
+                       ret = -EINTR;
+       } else {
+               ret = wait_event_timeout(csi->wait,
+                               ((csi->status & wait_mask) == wait_mask) ||
+                               csi->errors, HZ) == 0 ? -ETIMEDOUT : 0;
+       }
 
        rzv2m_csi_disable_irqs(csi, enable_bits);
 
        if (csi->errors)
                return -EIO;
 
-       if (!ret)
-               return -ETIMEDOUT;
-
-       return 0;
-}
-
-static int rzv2m_csi_wait_for_tx_empty(struct rzv2m_csi_priv *csi)
-{
-       int ret;
-
-       if (readl(csi->base + CSI_OFIFOL) == 0)
-               return 0;
-
-       ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_TREND, CSI_CNT_TREND_E);
-       if (ret == -ETIMEDOUT)
-               csi->errors |= TX_TIMEOUT_ERROR;
-
        return ret;
 }
 
 {
        int ret;
 
-       if (readl(csi->base + CSI_IFIFOL) == csi->bytes_to_transfer)
+       if (readl(csi->base + CSI_IFIFOL) >= csi->bytes_to_transfer)
                return 0;
 
        ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_R_TRGR,
 static int rzv2m_csi_setup(struct spi_device *spi)
 {
        struct rzv2m_csi_priv *csi = spi_controller_get_devdata(spi->controller);
+       u32 slave_selection = CSI_CLKSEL_SS_DISABLED;
        int ret;
 
        rzv2m_csi_sw_reset(csi, 0);
        rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_DIR,
                                !!(spi->mode & SPI_LSB_FIRST));
 
-       /* Set the operation mode as master */
-       rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SLAVE, 0);
+       /* Set the role, 1 for target and 0 for host */
+       rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SLAVE,
+                               !!spi_controller_is_target(csi->controller));
+
+       if (csi->use_ss_pin)
+               slave_selection = spi->mode & SPI_CS_HIGH ?
+                       CSI_CLKSEL_SS_ENABLED_ACTIVE_HIGH :
+                       CSI_CLKSEL_SS_ENABLED_ACTIVE_LOW;
+
+       /* Configure the slave selection (SS) pin */
+       rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SS, slave_selection);
 
        /* Give the IP a SW reset */
        ret = rzv2m_csi_sw_reset(csi, 1);
        /* Make sure the TX FIFO is empty */
        writel(0, csi->base + CSI_OFIFOL);
 
+       /* Make sure the RX FIFO is empty */
+       writel(0, csi->base + CSI_IFIFOL);
+
        csi->bytes_sent = 0;
        csi->bytes_received = 0;
        csi->errors = 0;
+       csi->target_aborted = false;
 
        rzv2m_csi_disable_all_irqs(csi);
        rzv2m_csi_clear_all_irqs(csi);
 
                rzv2m_csi_enable_irqs(csi, CSI_INT_OVERF | CSI_INT_UNDER);
 
-               /* Make sure the RX FIFO is empty */
-               writel(0, csi->base + CSI_IFIFOL);
-
                writel(readl(csi->base + CSI_INT), csi->base + CSI_INT);
                csi->status = 0;
 
-               rzv2m_csi_start_stop_operation(csi, 1, false);
-
                /* TX */
                if (csi->txbuf) {
                        ret = rzv2m_csi_fill_txfifo(csi);
                        if (ret)
                                break;
 
-                       ret = rzv2m_csi_wait_for_tx_empty(csi);
-                       if (ret)
-                               break;
-
                        if (csi->bytes_sent == csi->buffer_len)
                                tx_completed = true;
                }
 
+               rzv2m_csi_start_stop_operation(csi, 1, false);
+
                /*
                 * Make sure the RX FIFO contains the desired number of words.
                 * We then either flush its content, or we copy it onto
                if (ret)
                        break;
 
-               /* RX */
-               if (csi->rxbuf) {
+               if (!spi_controller_is_target(csi->controller))
                        rzv2m_csi_start_stop_operation(csi, 0, false);
 
+               /* RX */
+               if (csi->rxbuf) {
                        ret = rzv2m_csi_read_rxfifo(csi);
                        if (ret)
                                break;
 
                        if (csi->bytes_received == csi->buffer_len)
                                rx_completed = true;
+               } else {
+                       rzv2m_csi_empty_rxfifo(csi);
                }
 
-               ret = rzv2m_csi_start_stop_operation(csi, 0, true);
-               if (ret)
-                       goto pio_quit;
-
                if (csi->errors) {
                        ret = -EIO;
-                       goto pio_quit;
+                       break;
                }
        }
 
        rzv2m_csi_start_stop_operation(csi, 0, true);
-
-pio_quit:
        rzv2m_csi_disable_all_irqs(csi);
        rzv2m_csi_enable_rx_trigger(csi, false);
        rzv2m_csi_clear_all_irqs(csi);
 
        rzv2m_csi_setup_operating_mode(csi, transfer);
 
-       rzv2m_csi_setup_clock(csi, transfer->speed_hz);
+       if (!spi_controller_is_target(csi->controller))
+               rzv2m_csi_setup_clock(csi, transfer->speed_hz);
 
        ret = rzv2m_csi_pio_transfer(csi);
        if (ret) {
        return ret;
 }
 
+static int rzv2m_csi_target_abort(struct spi_controller *ctlr)
+{
+       struct rzv2m_csi_priv *csi = spi_controller_get_devdata(ctlr);
+
+       csi->target_aborted = true;
+       wake_up(&csi->wait);
+
+       return 0;
+}
+
 static int rzv2m_csi_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct spi_controller *controller;
        struct device *dev = &pdev->dev;
        struct rzv2m_csi_priv *csi;
        struct reset_control *rstc;
+       bool target_mode;
        int irq;
        int ret;
 
-       controller = devm_spi_alloc_host(dev, sizeof(*csi));
+       target_mode = of_property_read_bool(np, "spi-slave");
+
+       if (target_mode)
+               controller = devm_spi_alloc_target(dev, sizeof(*csi));
+       else
+               controller = devm_spi_alloc_host(dev, sizeof(*csi));
+
        if (!controller)
                return -ENOMEM;
 
        csi = spi_controller_get_devdata(controller);
        platform_set_drvdata(pdev, csi);
 
+       csi->use_ss_pin = false;
+       if (spi_controller_is_target(controller) &&
+           !of_property_read_bool(np, "renesas,csi-no-ss"))
+               csi->use_ss_pin = true;
+
        csi->dev = dev;
        csi->controller = controller;
+       csi->target_aborted = false;
 
        csi->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(csi->base))
 
        init_waitqueue_head(&csi->wait);
 
-       controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+       controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
        controller->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
        controller->setup = rzv2m_csi_setup;
        controller->transfer_one = rzv2m_csi_transfer_one;
        controller->use_gpio_descriptors = true;
+       controller->target_abort = rzv2m_csi_target_abort;
 
        device_set_node(&controller->dev, dev_fwnode(dev));