[PATCH v1 03/11] spi: dw: update SPI_CTRLR0 register

From: Changhuang Liang

Date: Thu Jul 09 2026 - 04:30:35 EST


From: Sudip Mukherjee <sudip.mukherjee@xxxxxxxxxx>

If the SPI transfer is being done in enhanced mode then SPI_CTRLR0
register needs to be updated to mention the instruction length, address
length, address and instruction transfer format, wait cycles. And, we
also need to enable clock stretching.

Signed-off-by: Sudip Mukherjee <sudip.mukherjee@xxxxxxxxxx>
Co-developed-by: Changhuang Liang <changhuang.liang@xxxxxxxxxxxxxxxx>
Signed-off-by: Changhuang Liang <changhuang.liang@xxxxxxxxxxxxxxxx>
---
drivers/spi/spi-dw-core.c | 15 ++++++++++++---
drivers/spi/spi-dw.h | 17 ++++++++++++++++-
2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index bd41e1b4dba7..fabfdf4ef604 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -313,7 +313,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
}

void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
- struct dw_spi_cfg *cfg)
+ struct dw_spi_cfg *cfg, struct dw_spi_enh_cfg *enh_cfg)
{
struct dw_spi_chip_data *chip = spi_get_ctldata(spi);
u32 cr0 = chip->cr0;
@@ -366,6 +366,15 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
dws->cur_rx_sample_dly = chip->rx_sample_dly;
}
+
+ if (enh_cfg) {
+ cr0 = DW_SPI_ENH_CTRLR0_CLK_STRETCH_EN;
+ cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_WAIT_CYCLE_MASK, enh_cfg->wait_c);
+ cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_INST_L_MASK, enh_cfg->inst_l);
+ cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_ADDR_L_MASK, enh_cfg->addr_l);
+ cr0 |= FIELD_PREP(DW_SPI_ENH_CTRLR0_TRANS_TYPE_MASK, enh_cfg->trans_t);
+ dw_writel(dws, DW_SPI_SPI_CTRLR0, cr0);
+ }
}
EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, "SPI_DW_CORE");

@@ -451,7 +460,7 @@ static int dw_spi_transfer_one(struct spi_controller *ctlr,

dw_spi_enable_chip(dws, 0);

- dw_spi_update_config(dws, spi, &cfg);
+ dw_spi_update_config(dws, spi, &cfg, NULL);

transfer->effective_speed_hz = dws->current_freq;

@@ -718,7 +727,7 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)

dw_spi_enable_chip(dws, 0);

- dw_spi_update_config(dws, mem->spi, &cfg);
+ dw_spi_update_config(dws, mem->spi, &cfg, NULL);

dw_spi_mask_intr(dws, 0xff);

diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 19cf1b1a5d4f..16a8c7ab7364 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -63,6 +63,7 @@
#define DW_SPI_VERSION 0x5c
#define DW_SPI_DR 0x60
#define DW_SPI_RX_SAMPLE_DLY 0xf0
+#define DW_SPI_SPI_CTRLR0 0xf4
#define DW_SPI_CS_OVERRIDE 0xf4

/* Bit fields in CTRLR0 (DWC APB SSI) */
@@ -127,6 +128,13 @@
#define DW_SPI_DMACR_RDMAE BIT(0)
#define DW_SPI_DMACR_TDMAE BIT(1)

+/* Bit fields in SPI_CTRLR0 */
+#define DW_SPI_ENH_CTRLR0_CLK_STRETCH_EN BIT(30)
+#define DW_SPI_ENH_CTRLR0_WAIT_CYCLE_MASK GENMASK(15, 11)
+#define DW_SPI_ENH_CTRLR0_INST_L_MASK GENMASK(9, 8)
+#define DW_SPI_ENH_CTRLR0_ADDR_L_MASK GENMASK(5, 2)
+#define DW_SPI_ENH_CTRLR0_TRANS_TYPE_MASK GENMASK(1, 0)
+
/* Mem/DMA operations helpers */
#define DW_SPI_WAIT_RETRIES 5
#define DW_SPI_BUF_SIZE \
@@ -144,6 +152,13 @@ struct dw_spi_cfg {
u8 spi_frf;
};

+struct dw_spi_enh_cfg {
+ u8 wait_c;
+ u8 inst_l;
+ u8 addr_l;
+ u8 trans_t;
+};
+
struct dw_spi;
struct dw_spi_dma_ops {
int (*dma_init)(struct device *dev, struct dw_spi *dws);
@@ -294,7 +309,7 @@ static inline void dw_spi_shutdown_chip(struct dw_spi *dws)

extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
extern void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
- struct dw_spi_cfg *cfg);
+ struct dw_spi_cfg *cfg, struct dw_spi_enh_cfg *enh_cfg);
extern int dw_spi_check_status(struct dw_spi *dws, bool raw);
extern int dw_spi_add_controller(struct device *dev, struct dw_spi *dws);
extern void dw_spi_remove_controller(struct dw_spi *dws);
--
2.25.1