summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/spi-dw-core.c26
-rw-r--r--drivers/spi/spi-dw.h3
2 files changed, 29 insertions, 0 deletions
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 323c66c5db50..55afdcee7d2b 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
+#include <linux/of.h>
#include "spi-dw.h"
@@ -26,6 +27,8 @@ struct chip_data {
u16 clk_div; /* baud rate divider */
u32 speed_hz; /* baud rate */
+
+ u32 rx_sample_dly; /* RX sample delay */
};
#ifdef CONFIG_DEBUG_FS
@@ -52,6 +55,7 @@ static const struct debugfs_reg32 dw_spi_dbgfs_regs[] = {
DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
+ DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY),
};
static int dw_spi_debugfs_init(struct dw_spi *dws)
@@ -328,6 +332,12 @@ static int dw_spi_transfer_one(struct spi_controller *master,
if (master->can_dma && master->can_dma(master, spi, transfer))
dws->dma_mapped = master->cur_msg_mapped;
+ /* Update RX sample delay if required */
+ if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
+ dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
+ dws->cur_rx_sample_dly = chip->rx_sample_dly;
+ }
+
/* For poll mode just disable all interrupts */
spi_mask_intr(dws, 0xff);
@@ -380,10 +390,22 @@ static int dw_spi_setup(struct spi_device *spi)
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (!chip) {
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
+ u32 rx_sample_dly_ns;
+
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;
spi_set_ctldata(spi, chip);
+ /* Get specific / default rx-sample-delay */
+ if (device_property_read_u32(&spi->dev,
+ "rx-sample-delay-ns",
+ &rx_sample_dly_ns) != 0)
+ /* Use default controller value */
+ rx_sample_dly_ns = dws->def_rx_sample_dly_ns;
+ chip->rx_sample_dly = DIV_ROUND_CLOSEST(rx_sample_dly_ns,
+ NSEC_PER_SEC /
+ dws->max_freq);
}
chip->tmode = SPI_TMOD_TR;
@@ -472,6 +494,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (dws->set_cs)
master->set_cs = dws->set_cs;
+ /* Get default rx sample delay */
+ device_property_read_u32(dev, "rx-sample-delay-ns",
+ &dws->def_rx_sample_dly_ns);
+
/* Basic HW init */
spi_hw_init(dev, dws);
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 151ba316619e..90dfd21622d6 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -34,6 +34,7 @@
#define DW_SPI_IDR 0x58
#define DW_SPI_VERSION 0x5c
#define DW_SPI_DR 0x60
+#define DW_SPI_RX_SAMPLE_DLY 0xf0
#define DW_SPI_CS_OVERRIDE 0xf4
/* Bit fields in CTRLR0 */
@@ -140,6 +141,8 @@ struct dw_spi {
u8 n_bytes; /* current is a 1/2 bytes op */
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
u32 current_freq; /* frequency in hz */
+ u32 cur_rx_sample_dly;
+ u32 def_rx_sample_dly_ns;
/* DMA info */
struct dma_chan *txchan;