diff options
| author | Benoît Monin <benoit.monin@bootlin.com> | 2025-10-02 14:14:38 +0200 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2025-10-13 11:27:36 +0100 |
| commit | fe8cc44dd173cde5788ab4e3730ac61f3d316d9c (patch) | |
| tree | 445844c8952cfcb11a85a8011b3cf817490bea00 | |
| parent | b926b15547d29a88932de3c24a05c12826fc1dbc (diff) | |
spi: dw: add target mode support
Implement target mode for the DesignWare controller with the following
changes:
Allocate an SPI controller of the correct type based on the spi-slave
property in dw_spi_add_controller() and set the controller properties
depending on its type. Since they are only relevant when acting as a host
controller, settings related to chip-select control and the set_cs()
callback are only set in host mode, as are the loopback support, the
memory operations and the maximum frequency. The target_abort() callback
is set only when configured in target mode.
The number of chip-select is set to 1 in dw_spi_hw_init() since the
controller only has one CS input in target mode.
In dw_spi_update_config(), return after setting the CTRLR0 register as
the other registers are only relevant in host mode and are read-only
in target mode. This function is called as part of the transfer_one()
callback, which is identical in both the host and target mode.
Move the code implementing the handle_err() callback to a new function
named dw_spi_abort(), and use it to implement both the handle_err()
and the target_abort() callbacks.
Finally, drop the error path on the spi-slave property in
dw_spi_mmio_probe(), as it is now a valid configuration.
Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
Link: https://patch.msgid.link/20251002-spi-dw-target-v1-2-993e91c1a712@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
| -rw-r--r-- | drivers/spi/spi-dw-core.c | 82 | ||||
| -rw-r--r-- | drivers/spi/spi-dw-mmio.c | 5 |
2 files changed, 57 insertions, 30 deletions
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 90dea6f9b3da..9ebf244294f8 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -332,6 +332,9 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, dw_writel(dws, DW_SPI_CTRLR0, cr0); + if (spi_controller_is_target(dws->ctlr)) + return; + if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD || cfg->tmode == DW_SPI_CTRLR0_TMOD_RO) dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0); @@ -462,8 +465,7 @@ static int dw_spi_transfer_one(struct spi_controller *ctlr, return 1; } -static void dw_spi_handle_err(struct spi_controller *ctlr, - struct spi_message *msg) +static inline void dw_spi_abort(struct spi_controller *ctlr) { struct dw_spi *dws = spi_controller_get_devdata(ctlr); @@ -473,6 +475,19 @@ static void dw_spi_handle_err(struct spi_controller *ctlr, dw_spi_reset_chip(dws); } +static void dw_spi_handle_err(struct spi_controller *ctlr, + struct spi_message *msg) +{ + dw_spi_abort(ctlr); +} + +static int dw_spi_target_abort(struct spi_controller *ctlr) +{ + dw_spi_abort(ctlr); + + return 0; +} + static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op) { if (op->data.dir == SPI_MEM_DATA_IN) @@ -834,18 +849,23 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) DW_SPI_GET_BYTE(dws->ver, 1)); } - /* - * Try to detect the number of native chip-selects if the platform - * driver didn't set it up. There can be up to 16 lines configured. - */ - if (!dws->num_cs) { - u32 ser; + if (spi_controller_is_target(dws->ctlr)) { + /* There is only one CS input signal in target mode */ + dws->num_cs = 1; + } else { + /* + * Try to detect the number of native chip-selects if the platform + * driver didn't set it up. There can be up to 16 lines configured. + */ + if (!dws->num_cs) { + u32 ser; - dw_writel(dws, DW_SPI_SER, 0xffff); - ser = dw_readl(dws, DW_SPI_SER); - dw_writel(dws, DW_SPI_SER, 0); + dw_writel(dws, DW_SPI_SER, 0xffff); + ser = dw_readl(dws, DW_SPI_SER); + dw_writel(dws, DW_SPI_SER, 0); - dws->num_cs = hweight16(ser); + dws->num_cs = hweight16(ser); + } } /* @@ -901,12 +921,18 @@ static const struct spi_controller_mem_caps dw_spi_mem_caps = { int dw_spi_add_controller(struct device *dev, struct dw_spi *dws) { struct spi_controller *ctlr; + bool target; int ret; if (!dws) return -EINVAL; - ctlr = spi_alloc_host(dev, 0); + target = device_property_read_bool(dev, "spi-slave"); + if (target) + ctlr = spi_alloc_target(dev, 0); + else + ctlr = spi_alloc_host(dev, 0); + if (!ctlr) return -ENOMEM; @@ -929,8 +955,7 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws) dw_spi_init_mem_ops(dws); - ctlr->use_gpio_descriptors = true; - ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; + ctlr->mode_bits = SPI_CPOL | SPI_CPHA; if (dws->caps & DW_SPI_CAP_DFS32) ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); else @@ -939,20 +964,27 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws) ctlr->num_chipselect = dws->num_cs; ctlr->setup = dw_spi_setup; ctlr->cleanup = dw_spi_cleanup; - if (dws->set_cs) - ctlr->set_cs = dws->set_cs; - else - ctlr->set_cs = dw_spi_set_cs; ctlr->transfer_one = dw_spi_transfer_one; ctlr->handle_err = dw_spi_handle_err; - if (dws->mem_ops.exec_op) { - ctlr->mem_ops = &dws->mem_ops; - ctlr->mem_caps = &dw_spi_mem_caps; - } - ctlr->max_speed_hz = dws->max_freq; - ctlr->flags = SPI_CONTROLLER_GPIO_SS; ctlr->auto_runtime_pm = true; + if (!target) { + ctlr->use_gpio_descriptors = true; + ctlr->mode_bits |= SPI_LOOP; + if (dws->set_cs) + ctlr->set_cs = dws->set_cs; + else + ctlr->set_cs = dw_spi_set_cs; + if (dws->mem_ops.exec_op) { + ctlr->mem_ops = &dws->mem_ops; + ctlr->mem_caps = &dw_spi_mem_caps; + } + ctlr->max_speed_hz = dws->max_freq; + ctlr->flags = SPI_CONTROLLER_GPIO_SS; + } else { + ctlr->target_abort = dw_spi_target_abort; + } + /* Get default rx sample delay */ device_property_read_u32(dev, "rx-sample-delay-ns", &dws->def_rx_sample_dly_ns); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index a33f246560d8..33239b4778cb 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -321,11 +321,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) struct dw_spi *dws; int ret; - if (device_property_read_bool(&pdev->dev, "spi-slave")) { - dev_warn(&pdev->dev, "spi-slave is not yet supported\n"); - return -ENODEV; - } - dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio), GFP_KERNEL); if (!dwsmmio) |