X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fspi%2Fzynq_spi.c;h=2a02942d413ec751db5cb14367fd7c155fc5cf87;hb=cce289a928583a64db6ec8f813cc7884ae62c213;hp=09ae1be7e9875ed4d6acd2d7d0eae810561fefdb;hpb=23ef5aea849ce2252086a4f79dde8205afc56a00;p=oweals%2Fu-boot.git diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 09ae1be7e9..2a02942d41 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2013 Xilinx, Inc. * (C) Copyright 2015 Jagan Teki * * Xilinx Zynq PS SPI controller driver (master mode only) - * - * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -56,6 +55,8 @@ struct zynq_spi_platdata { struct zynq_spi_regs *regs; u32 frequency; /* input frequency */ u32 speed_hz; + uint deactivate_delay_us; /* Delay to wait after deactivate */ + uint activate_delay_us; /* Delay to wait after activate */ }; /* zynq spi priv */ @@ -63,6 +64,7 @@ struct zynq_spi_priv { struct zynq_spi_regs *regs; u8 cs; u8 mode; + ulong last_transaction_us; /* Time of last transaction end */ u8 fifo_depth; u32 freq; /* required frequency */ }; @@ -71,13 +73,17 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus) { struct zynq_spi_platdata *plat = bus->platdata; const void *blob = gd->fdt_blob; - int node = bus->of_offset; + int node = dev_of_offset(bus); - plat->regs = (struct zynq_spi_regs *)dev_get_addr(bus); + plat->regs = (struct zynq_spi_regs *)devfdt_get_addr(bus); /* FIXME: Use 250MHz as a suitable default */ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", 250000000); + plat->deactivate_delay_us = fdtdec_get_int(blob, node, + "spi-deactivate-delay", 0); + plat->activate_delay_us = fdtdec_get_int(blob, node, + "spi-activate-delay", 0); plat->speed_hz = plat->frequency / 2; debug("%s: regs=%p max-frequency=%d\n", __func__, @@ -92,7 +98,8 @@ static void zynq_spi_init_hw(struct zynq_spi_priv *priv) u32 confr; /* Disable SPI */ - writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr); + confr = ZYNQ_SPI_ENR_SPI_EN_MASK; + writel(~confr, ®s->enr); /* Disable Interrupts */ writel(ZYNQ_SPI_IXR_ALL_MASK, ®s->idr); @@ -132,10 +139,19 @@ static int zynq_spi_probe(struct udevice *bus) static void spi_cs_activate(struct udevice *dev) { struct udevice *bus = dev->parent; + struct zynq_spi_platdata *plat = bus->platdata; struct zynq_spi_priv *priv = dev_get_priv(bus); struct zynq_spi_regs *regs = priv->regs; u32 cr; + /* If it's too soon to do another transaction, wait */ + if (plat->deactivate_delay_us && priv->last_transaction_us) { + ulong delay_us; /* The delay completed so far */ + delay_us = timer_get_us() - priv->last_transaction_us; + if (delay_us < plat->deactivate_delay_us) + udelay(plat->deactivate_delay_us - delay_us); + } + clrbits_le32(®s->cr, ZYNQ_SPI_CR_CS_MASK); cr = readl(®s->cr); /* @@ -146,15 +162,23 @@ static void spi_cs_activate(struct udevice *dev) */ cr |= (~(1 << priv->cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK; writel(cr, ®s->cr); + + if (plat->activate_delay_us) + udelay(plat->activate_delay_us); } static void spi_cs_deactivate(struct udevice *dev) { struct udevice *bus = dev->parent; + struct zynq_spi_platdata *plat = bus->platdata; struct zynq_spi_priv *priv = dev_get_priv(bus); struct zynq_spi_regs *regs = priv->regs; setbits_le32(®s->cr, ZYNQ_SPI_CR_CS_MASK); + + /* Remember time of this transaction so we can honour the bus delay */ + if (plat->deactivate_delay_us) + priv->last_transaction_us = timer_get_us(); } static int zynq_spi_claim_bus(struct udevice *dev) @@ -173,8 +197,10 @@ static int zynq_spi_release_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct zynq_spi_priv *priv = dev_get_priv(bus); struct zynq_spi_regs *regs = priv->regs; + u32 confr; - writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, ®s->enr); + confr = ZYNQ_SPI_ENR_SPI_EN_MASK; + writel(~confr, ®s->enr); return 0; } @@ -230,7 +256,7 @@ static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Read the data from RX FIFO */ status = readl(®s->isr); - while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) { + while ((status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) && rx_len) { buf = readl(®s->rxdr); if (rx_buf) *rx_buf++ = buf;