mirror of https://github.com/torvalds/linux.git
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>
This commit is contained in:
parent
b926b15547
commit
fe8cc44dd1
|
|
@ -332,6 +332,9 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
||||||
|
|
||||||
dw_writel(dws, DW_SPI_CTRLR0, cr0);
|
dw_writel(dws, DW_SPI_CTRLR0, cr0);
|
||||||
|
|
||||||
|
if (spi_controller_is_target(dws->ctlr))
|
||||||
|
return;
|
||||||
|
|
||||||
if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD ||
|
if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD ||
|
||||||
cfg->tmode == DW_SPI_CTRLR0_TMOD_RO)
|
cfg->tmode == DW_SPI_CTRLR0_TMOD_RO)
|
||||||
dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dw_spi_handle_err(struct spi_controller *ctlr,
|
static inline void dw_spi_abort(struct spi_controller *ctlr)
|
||||||
struct spi_message *msg)
|
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = spi_controller_get_devdata(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);
|
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)
|
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)
|
if (op->data.dir == SPI_MEM_DATA_IN)
|
||||||
|
|
@ -834,6 +849,10 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
|
||||||
DW_SPI_GET_BYTE(dws->ver, 1));
|
DW_SPI_GET_BYTE(dws->ver, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
* 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.
|
* driver didn't set it up. There can be up to 16 lines configured.
|
||||||
|
|
@ -847,6 +866,7 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
|
||||||
|
|
||||||
dws->num_cs = hweight16(ser);
|
dws->num_cs = hweight16(ser);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to detect the FIFO depth if not set by interface driver,
|
* Try to detect the FIFO depth if not set by interface driver,
|
||||||
|
|
@ -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)
|
int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
struct spi_controller *ctlr;
|
struct spi_controller *ctlr;
|
||||||
|
bool target;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!dws)
|
if (!dws)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
target = device_property_read_bool(dev, "spi-slave");
|
||||||
|
if (target)
|
||||||
|
ctlr = spi_alloc_target(dev, 0);
|
||||||
|
else
|
||||||
ctlr = spi_alloc_host(dev, 0);
|
ctlr = spi_alloc_host(dev, 0);
|
||||||
|
|
||||||
if (!ctlr)
|
if (!ctlr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
@ -929,8 +955,7 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
|
||||||
|
|
||||||
dw_spi_init_mem_ops(dws);
|
dw_spi_init_mem_ops(dws);
|
||||||
|
|
||||||
ctlr->use_gpio_descriptors = true;
|
ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||||
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
|
|
||||||
if (dws->caps & DW_SPI_CAP_DFS32)
|
if (dws->caps & DW_SPI_CAP_DFS32)
|
||||||
ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||||
else
|
else
|
||||||
|
|
@ -939,19 +964,26 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
|
||||||
ctlr->num_chipselect = dws->num_cs;
|
ctlr->num_chipselect = dws->num_cs;
|
||||||
ctlr->setup = dw_spi_setup;
|
ctlr->setup = dw_spi_setup;
|
||||||
ctlr->cleanup = dw_spi_cleanup;
|
ctlr->cleanup = dw_spi_cleanup;
|
||||||
|
ctlr->transfer_one = dw_spi_transfer_one;
|
||||||
|
ctlr->handle_err = dw_spi_handle_err;
|
||||||
|
ctlr->auto_runtime_pm = true;
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
ctlr->use_gpio_descriptors = true;
|
||||||
|
ctlr->mode_bits |= SPI_LOOP;
|
||||||
if (dws->set_cs)
|
if (dws->set_cs)
|
||||||
ctlr->set_cs = dws->set_cs;
|
ctlr->set_cs = dws->set_cs;
|
||||||
else
|
else
|
||||||
ctlr->set_cs = dw_spi_set_cs;
|
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) {
|
if (dws->mem_ops.exec_op) {
|
||||||
ctlr->mem_ops = &dws->mem_ops;
|
ctlr->mem_ops = &dws->mem_ops;
|
||||||
ctlr->mem_caps = &dw_spi_mem_caps;
|
ctlr->mem_caps = &dw_spi_mem_caps;
|
||||||
}
|
}
|
||||||
ctlr->max_speed_hz = dws->max_freq;
|
ctlr->max_speed_hz = dws->max_freq;
|
||||||
ctlr->flags = SPI_CONTROLLER_GPIO_SS;
|
ctlr->flags = SPI_CONTROLLER_GPIO_SS;
|
||||||
ctlr->auto_runtime_pm = true;
|
} else {
|
||||||
|
ctlr->target_abort = dw_spi_target_abort;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get default rx sample delay */
|
/* Get default rx sample delay */
|
||||||
device_property_read_u32(dev, "rx-sample-delay-ns",
|
device_property_read_u32(dev, "rx-sample-delay-ns",
|
||||||
|
|
|
||||||
|
|
@ -321,11 +321,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||||
struct dw_spi *dws;
|
struct dw_spi *dws;
|
||||||
int ret;
|
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),
|
dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!dwsmmio)
|
if (!dwsmmio)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue