From 10c1ded452719931e87b4a550ab2d6a68f138fc4 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Sat, 27 Jun 2020 10:22:03 -0500 Subject: [PATCH] drivers: spi: Add optional delays to mcux dspi and lpspi drivers Adds optional device tree properties to set delays between spi chip select assert/deassert and clock edges in the mcux dspi and lpspi drivers. If these properties are not set, then the minimum supported delays are used. Verified that tests/drivers/spi/spi_loopback/ still passes on mimxrt1050_evk (lpspi driver) and frdm_k64f (dspi driver). Measured with a scope that the pcs-sck-delay and sck-pcs-delay times on the first spi transaction in the test are reduced from 7.82 us to 20 ns on mimxrt1050_evk. Signed-off-by: Maureen Helm --- drivers/spi/spi_mcux_dspi.c | 28 +++++++++++++++++++++----- drivers/spi/spi_mcux_lpspi.c | 16 +++++++++++++++ dts/bindings/spi/nxp,imx-lpspi.yaml | 21 +++++++++++++++++++ dts/bindings/spi/nxp,kinetis-dspi.yaml | 21 +++++++++++++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi_mcux_dspi.c b/drivers/spi/spi_mcux_dspi.c index 9b406dc07d5..a57df2ccc40 100644 --- a/drivers/spi/spi_mcux_dspi.c +++ b/drivers/spi/spi_mcux_dspi.c @@ -23,6 +23,9 @@ struct spi_mcux_config { char *clock_name; clock_control_subsys_t clock_subsys; void (*irq_config_func)(struct device *dev); + uint32_t pcs_sck_delay; + uint32_t sck_pcs_delay; + uint32_t transfer_delay; }; struct spi_mcux_data { @@ -133,6 +136,8 @@ static int spi_mcux_configure(struct device *dev, uint32_t clock_freq; uint32_t word_size; + dspi_master_ctar_config_t *ctar_config = &master_config.ctarConfig; + if (spi_context_configured(&data->ctx, spi_cfg)) { /* This configuration is already in use */ return 0; @@ -153,24 +158,28 @@ static int spi_mcux_configure(struct device *dev, return -EINVAL; } - master_config.ctarConfig.bitsPerFrame = word_size; + ctar_config->bitsPerFrame = word_size; - master_config.ctarConfig.cpol = + ctar_config->cpol = (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) ? kDSPI_ClockPolarityActiveLow : kDSPI_ClockPolarityActiveHigh; - master_config.ctarConfig.cpha = + ctar_config->cpha = (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPHA) ? kDSPI_ClockPhaseSecondEdge : kDSPI_ClockPhaseFirstEdge; - master_config.ctarConfig.direction = + ctar_config->direction = (spi_cfg->operation & SPI_TRANSFER_LSB) ? kDSPI_LsbFirst : kDSPI_MsbFirst; - master_config.ctarConfig.baudRate = spi_cfg->frequency; + ctar_config->baudRate = spi_cfg->frequency; + + ctar_config->pcsToSckDelayInNanoSec = config->pcs_sck_delay; + ctar_config->lastSckToPcsDelayInNanoSec = config->sck_pcs_delay; + ctar_config->betweenTransferDelayInNanoSec = config->transfer_delay; clock_dev = device_get_binding(config->clock_name); if (clock_dev == NULL) { @@ -285,6 +294,15 @@ static const struct spi_driver_api spi_mcux_driver_api = { .clock_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL(id, name), \ .irq_config_func = spi_mcux_config_func_##id, \ + .pcs_sck_delay = UTIL_AND( \ + DT_INST_NODE_HAS_PROP(id, pcs_sck_delay), \ + DT_INST_PROP(id, pcs_sck_delay)), \ + .sck_pcs_delay = UTIL_AND( \ + DT_INST_NODE_HAS_PROP(id, sck_pcs_delay), \ + DT_INST_PROP(id, sck_pcs_delay)), \ + .transfer_delay = UTIL_AND( \ + DT_INST_NODE_HAS_PROP(id, transfer_delay), \ + DT_INST_PROP(id, transfer_delay)), \ }; \ static struct spi_mcux_data spi_mcux_data_##id = { \ SPI_CONTEXT_INIT_LOCK(spi_mcux_data_##id, ctx), \ diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index b2525fe4c1b..f91e6c8acba 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -25,6 +25,9 @@ struct spi_mcux_config { char *clock_name; clock_control_subsys_t clock_subsys; void (*irq_config_func)(struct device *dev); + uint32_t pcs_sck_delay; + uint32_t sck_pcs_delay; + uint32_t transfer_delay; }; struct spi_mcux_data { @@ -173,6 +176,10 @@ static int spi_mcux_configure(struct device *dev, master_config.baudRate = spi_cfg->frequency; + master_config.pcsToSckDelayInNanoSec = config->pcs_sck_delay; + master_config.lastSckToPcsDelayInNanoSec = config->sck_pcs_delay; + master_config.betweenTransferDelayInNanoSec = config->transfer_delay; + clock_dev = device_get_binding(config->clock_name); if (clock_dev == NULL) { return -EINVAL; @@ -284,6 +291,15 @@ static const struct spi_driver_api spi_mcux_driver_api = { .clock_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ .irq_config_func = spi_mcux_config_func_##n, \ + .pcs_sck_delay = UTIL_AND( \ + DT_INST_NODE_HAS_PROP(n, pcs_sck_delay), \ + DT_INST_PROP(n, pcs_sck_delay)), \ + .sck_pcs_delay = UTIL_AND( \ + DT_INST_NODE_HAS_PROP(n, sck_pcs_delay), \ + DT_INST_PROP(n, sck_pcs_delay)), \ + .transfer_delay = UTIL_AND( \ + DT_INST_NODE_HAS_PROP(n, transfer_delay), \ + DT_INST_PROP(n, transfer_delay)), \ }; \ \ static struct spi_mcux_data spi_mcux_data_##n = { \ diff --git a/dts/bindings/spi/nxp,imx-lpspi.yaml b/dts/bindings/spi/nxp,imx-lpspi.yaml index 44c13052a68..48804a863a5 100644 --- a/dts/bindings/spi/nxp,imx-lpspi.yaml +++ b/dts/bindings/spi/nxp,imx-lpspi.yaml @@ -16,3 +16,24 @@ properties: clocks: required: true + + pcs-sck-delay: + type: int + required: false + description: | + Delay in nanoseconds from the chip select assert to the first clock + edge. If not set, the minimum supported delay is used. + + sck-pcs-delay: + type: int + required: false + description: | + Delay in nanoseconds from the last clock edge to the chip select + deassert. If not set, the minimum supported delay is used. + + transfer-delay: + type: int + required: false + description: | + Delay in nanoseconds from the chip select deassert to the next chip + select assert. If not set, the minimum supported delay is used. diff --git a/dts/bindings/spi/nxp,kinetis-dspi.yaml b/dts/bindings/spi/nxp,kinetis-dspi.yaml index 592b825dabc..e09771cb200 100644 --- a/dts/bindings/spi/nxp,kinetis-dspi.yaml +++ b/dts/bindings/spi/nxp,kinetis-dspi.yaml @@ -16,3 +16,24 @@ properties: clocks: required: true + + pcs-sck-delay: + type: int + required: false + description: | + Delay in nanoseconds from the chip select assert to the first clock + edge. If not set, the minimum supported delay is used. + + sck-pcs-delay: + type: int + required: false + description: | + Delay in nanoseconds from the last clock edge to the chip select + deassert. If not set, the minimum supported delay is used. + + transfer-delay: + type: int + required: false + description: | + Delay in nanoseconds from the chip select deassert to the next chip + select assert. If not set, the minimum supported delay is used.