spi: meson-spicc: setup IO line delay
Now the controller can support frequencies higher than 30MHz, we need the setup the I/O line delays in regard of the SPI clock frequency. Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Link: https://lore.kernel.org/r/20200312133131.26430-7-narmstrong@baylibre.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Родитель
8791068dab
Коммит
f27bff479e
|
@ -106,7 +106,21 @@
|
|||
#define SPICC_SWAP_RO BIT(14) /* RX FIFO Data Swap Read-Only */
|
||||
#define SPICC_SWAP_W1 BIT(15) /* RX FIFO Data Swap Write-Only */
|
||||
#define SPICC_DLYCTL_RO_MASK GENMASK(20, 15) /* Delay Control Read-Only */
|
||||
#define SPICC_DLYCTL_W1_MASK GENMASK(21, 16) /* Delay Control Write-Only */
|
||||
#define SPICC_MO_DELAY_MASK GENMASK(17, 16) /* Master Output Delay */
|
||||
#define SPICC_MO_NO_DELAY 0
|
||||
#define SPICC_MO_DELAY_1_CYCLE 1
|
||||
#define SPICC_MO_DELAY_2_CYCLE 2
|
||||
#define SPICC_MO_DELAY_3_CYCLE 3
|
||||
#define SPICC_MI_DELAY_MASK GENMASK(19, 18) /* Master Input Delay */
|
||||
#define SPICC_MI_NO_DELAY 0
|
||||
#define SPICC_MI_DELAY_1_CYCLE 1
|
||||
#define SPICC_MI_DELAY_2_CYCLE 2
|
||||
#define SPICC_MI_DELAY_3_CYCLE 3
|
||||
#define SPICC_MI_CAP_DELAY_MASK GENMASK(21, 20) /* Master Capture Delay */
|
||||
#define SPICC_CAP_AHEAD_2_CYCLE 0
|
||||
#define SPICC_CAP_AHEAD_1_CYCLE 1
|
||||
#define SPICC_CAP_NO_DELAY 2
|
||||
#define SPICC_CAP_DELAY_1_CYCLE 3
|
||||
#define SPICC_FIFORST_RO_MASK GENMASK(22, 21) /* FIFO Softreset Read-Only */
|
||||
#define SPICC_FIFORST_W1_MASK GENMASK(23, 22) /* FIFO Softreset Write-Only */
|
||||
|
||||
|
@ -328,6 +342,49 @@ static irqreturn_t meson_spicc_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc)
|
||||
{
|
||||
u32 div, hz;
|
||||
u32 mi_delay, cap_delay;
|
||||
u32 conf;
|
||||
|
||||
if (spicc->data->has_enhance_clk_div) {
|
||||
div = FIELD_GET(SPICC_ENH_DATARATE_MASK,
|
||||
readl_relaxed(spicc->base + SPICC_ENH_CTL0));
|
||||
div++;
|
||||
div <<= 1;
|
||||
} else {
|
||||
div = FIELD_GET(SPICC_DATARATE_MASK,
|
||||
readl_relaxed(spicc->base + SPICC_CONREG));
|
||||
div += 2;
|
||||
div = 1 << div;
|
||||
}
|
||||
|
||||
mi_delay = SPICC_MI_NO_DELAY;
|
||||
cap_delay = SPICC_CAP_AHEAD_2_CYCLE;
|
||||
hz = clk_get_rate(spicc->clk);
|
||||
|
||||
if (hz >= 100000000)
|
||||
cap_delay = SPICC_CAP_DELAY_1_CYCLE;
|
||||
else if (hz >= 80000000)
|
||||
cap_delay = SPICC_CAP_NO_DELAY;
|
||||
else if (hz >= 40000000)
|
||||
cap_delay = SPICC_CAP_AHEAD_1_CYCLE;
|
||||
else if (div >= 16)
|
||||
mi_delay = SPICC_MI_DELAY_3_CYCLE;
|
||||
else if (div >= 8)
|
||||
mi_delay = SPICC_MI_DELAY_2_CYCLE;
|
||||
else if (div >= 6)
|
||||
mi_delay = SPICC_MI_DELAY_1_CYCLE;
|
||||
|
||||
conf = readl_relaxed(spicc->base + SPICC_TESTREG);
|
||||
conf &= ~(SPICC_MO_DELAY_MASK | SPICC_MI_DELAY_MASK
|
||||
| SPICC_MI_CAP_DELAY_MASK);
|
||||
conf |= FIELD_PREP(SPICC_MI_DELAY_MASK, mi_delay);
|
||||
conf |= FIELD_PREP(SPICC_MI_CAP_DELAY_MASK, cap_delay);
|
||||
writel_relaxed(conf, spicc->base + SPICC_TESTREG);
|
||||
}
|
||||
|
||||
static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
|
@ -346,6 +403,8 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
|
|||
writel_relaxed(conf, spicc->base + SPICC_CONREG);
|
||||
|
||||
clk_set_rate(spicc->clk, xfer->speed_hz);
|
||||
|
||||
meson_spicc_auto_io_delay(spicc);
|
||||
}
|
||||
|
||||
static int meson_spicc_transfer_one(struct spi_master *master,
|
||||
|
|
Загрузка…
Ссылка в новой задаче