aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig10
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/fsl_qspi.c9
-rw-r--r--drivers/spi/ich.c4
-rw-r--r--drivers/spi/mvebu_a3700_spi.c41
-rw-r--r--drivers/spi/nxp_fspi.c17
-rw-r--r--drivers/spi/octeon_spi.c5
-rw-r--r--drivers/spi/renesas_rpc_spi.c3
-rw-r--r--drivers/spi/spi-qup.c803
-rw-r--r--drivers/spi/xilinx_spi.c8
-rw-r--r--drivers/spi/zynq_qspi.c84
-rw-r--r--drivers/spi/zynq_spi.c35
12 files changed, 968 insertions, 52 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5df97c80fa..f7a9852565 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -271,6 +271,16 @@ config PL022_SPI
controller. If you have an embedded system with an AMBA(R)
bus and a PL022 controller, say Y or M here.
+config SPI_QUP
+ bool "Qualcomm SPI controller with QUP interface"
+ depends on ARCH_IPQ40XX
+ help
+ Qualcomm Universal Peripheral (QUP) core is an AHB slave that
+ provides a common data path (an output FIFO and an input FIFO)
+ for serial peripheral interface (SPI) mini-core. SPI in master
+ mode supports up to 50MHz, up to four chip selects, programmable
+ data path from 4 bits to 32 bits and numerous protocol variants.
+
config RENESAS_RPC_SPI
bool "Renesas RPC SPI driver"
depends on RCAR_GEN3 || RZA1
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index b5c9ff1af8..d9b5bd9b79 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_OCTEON_SPI) += octeon_spi.o
obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
obj-$(CONFIG_PIC32_SPI) += pic32_spi.o
obj-$(CONFIG_PL022_SPI) += pl022_spi.o
+obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index eec968e5ec..128f95877f 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -24,19 +24,20 @@
*/
#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
#include <log.h>
-#include <asm/io.h>
+#include <spi.h>
+#include <spi-mem.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/libfdt.h>
#include <linux/sizes.h>
#include <linux/iopoll.h>
-#include <dm.h>
#include <linux/iopoll.h>
#include <linux/sizes.h>
#include <linux/err.h>
-#include <spi.h>
-#include <spi-mem.h>
+#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index e1336b89c5..a91cb78568 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -615,6 +615,7 @@ static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
return ret;
}
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
/**
* ich_spi_get_basics() - Get basic information about the ICH device
*
@@ -657,6 +658,7 @@ static int ich_spi_get_basics(struct udevice *bus, bool can_probe,
return ret;
}
+#endif
/**
* ich_get_mmap_bus() - Handle the get_mmap() method for a bus
@@ -946,10 +948,10 @@ static int ich_spi_child_pre_probe(struct udevice *dev)
static int ich_spi_ofdata_to_platdata(struct udevice *dev)
{
struct ich_spi_platdata *plat = dev_get_platdata(dev);
- int ret;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct ich_spi_priv *priv = dev_get_priv(dev);
+ int ret;
ret = ich_spi_get_basics(dev, true, &priv->pch, &plat->ich_version,
&plat->mmio_base);
diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c
index e860b9ec64..eb13cf349e 100644
--- a/drivers/spi/mvebu_a3700_spi.c
+++ b/drivers/spi/mvebu_a3700_spi.c
@@ -15,6 +15,7 @@
#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
+#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -27,6 +28,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define MVEBU_SPI_A3700_SPI_EN_0 BIT(16)
#define MVEBU_SPI_A3700_CLK_PRESCALE_MASK 0x1f
+#define MAX_CS_COUNT 4
/* SPI registers */
struct spi_reg {
@@ -39,16 +41,23 @@ struct spi_reg {
struct mvebu_spi_platdata {
struct spi_reg *spireg;
struct clk clk;
+ struct gpio_desc cs_gpios[MAX_CS_COUNT];
};
-static void spi_cs_activate(struct spi_reg *reg, int cs)
+static void spi_cs_activate(struct mvebu_spi_platdata *plat, int cs)
{
- setbits_le32(&reg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs]))
+ dm_gpio_set_value(&plat->cs_gpios[cs], 1);
+ else
+ setbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
}
-static void spi_cs_deactivate(struct spi_reg *reg, int cs)
+static void spi_cs_deactivate(struct mvebu_spi_platdata *plat, int cs)
{
- clrbits_le32(&reg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
+ if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&plat->cs_gpios[cs]))
+ dm_gpio_set_value(&plat->cs_gpios[cs], 0);
+ else
+ clrbits_le32(&plat->spireg->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
}
/**
@@ -150,7 +159,7 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Activate CS */
if (flags & SPI_XFER_BEGIN) {
debug("SPI: activate cs.\n");
- spi_cs_activate(reg, spi_chip_select(dev));
+ spi_cs_activate(plat, spi_chip_select(dev));
}
/* Send and/or receive */
@@ -169,7 +178,7 @@ static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen,
return ret;
debug("SPI: deactivate cs.\n");
- spi_cs_deactivate(reg, spi_chip_select(dev));
+ spi_cs_deactivate(plat, spi_chip_select(dev));
}
return 0;
@@ -247,6 +256,26 @@ static int mvebu_spi_probe(struct udevice *bus)
writel(data, &reg->cfg);
+ /* Set up CS GPIOs in device tree, if any */
+ if (CONFIG_IS_ENABLED(DM_GPIO) && gpio_get_list_count(bus, "cs-gpios") > 0) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) {
+ ret = gpio_request_by_name(bus, "cs-gpios", i, &plat->cs_gpios[i], 0);
+ if (ret < 0 || !dm_gpio_is_valid(&plat->cs_gpios[i])) {
+ /* Use the native CS function for this line */
+ continue;
+ }
+
+ ret = dm_gpio_set_dir_flags(&plat->cs_gpios[i],
+ GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
+ if (ret) {
+ dev_err(bus, "Setting cs %d error\n", i);
+ return ret;
+ }
+ }
+ }
+
return 0;
}
diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c
index c507437f2e..9661e9e10d 100644
--- a/drivers/spi/nxp_fspi.c
+++ b/drivers/spi/nxp_fspi.c
@@ -34,12 +34,13 @@
*/
#include <common.h>
-#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
#include <malloc.h>
#include <spi.h>
#include <spi-mem.h>
-#include <dm.h>
-#include <clk.h>
+#include <asm/io.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/sizes.h>
@@ -520,7 +521,7 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
fspi_writel(f, FSPI_LCKER_LOCK, f->iobase + FSPI_LCKCR);
}
-#if CONFIG_IS_ENABLED(CONFIG_CLK)
+#if CONFIG_IS_ENABLED(CLK)
static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f)
{
int ret;
@@ -808,7 +809,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
int ret, i;
u32 reg;
-#if CONFIG_IS_ENABLED(CONFIG_CLK)
+#if CONFIG_IS_ENABLED(CLK)
/* disable and unprepare clock to avoid glitch pass to controller */
nxp_fspi_clk_disable_unprep(f);
@@ -898,7 +899,7 @@ static int nxp_fspi_claim_bus(struct udevice *dev)
static int nxp_fspi_set_speed(struct udevice *bus, uint speed)
{
-#if CONFIG_IS_ENABLED(CONFIG_CLK)
+#if CONFIG_IS_ENABLED(CLK)
struct nxp_fspi *f = dev_get_priv(bus);
int ret;
@@ -924,7 +925,7 @@ static int nxp_fspi_set_mode(struct udevice *bus, uint mode)
static int nxp_fspi_ofdata_to_platdata(struct udevice *bus)
{
struct nxp_fspi *f = dev_get_priv(bus);
-#if CONFIG_IS_ENABLED(CONFIG_CLK)
+#if CONFIG_IS_ENABLED(CLK)
int ret;
#endif
@@ -950,7 +951,7 @@ static int nxp_fspi_ofdata_to_platdata(struct udevice *bus)
f->ahb_addr = map_physmem(ahb_addr, ahb_size, MAP_NOCACHE);
f->memmap_phy_size = ahb_size;
-#if CONFIG_IS_ENABLED(CONFIG_CLK)
+#if CONFIG_IS_ENABLED(CLK)
ret = clk_get_by_name(bus, "fspi_en", &f->clk_en);
if (ret) {
dev_err(bus, "failed to get fspi_en clock\n");
diff --git a/drivers/spi/octeon_spi.c b/drivers/spi/octeon_spi.c
index 83fe6330a1..7e88e5580f 100644
--- a/drivers/spi/octeon_spi.c
+++ b/drivers/spi/octeon_spi.c
@@ -519,7 +519,10 @@ static int octeon_spi_set_speed(struct udevice *bus, uint max_hz)
if (max_hz > OCTEON_SPI_MAX_CLOCK_HZ)
max_hz = OCTEON_SPI_MAX_CLOCK_HZ;
- clk_rate = clk_get_rate(&priv->clk);
+ if (device_is_compatible(bus, "cavium,thunderx-spi"))
+ clk_rate = 100000000;
+ else
+ clk_rate = clk_get_rate(&priv->clk);
if (IS_ERR_VALUE(clk_rate))
return -EINVAL;
diff --git a/drivers/spi/renesas_rpc_spi.c b/drivers/spi/renesas_rpc_spi.c
index 3ea59b8fb8..d0ff918af8 100644
--- a/drivers/spi/renesas_rpc_spi.c
+++ b/drivers/spi/renesas_rpc_spi.c
@@ -448,12 +448,13 @@ static const struct dm_spi_ops rpc_spi_ops = {
};
static const struct udevice_id rpc_spi_ids[] = {
+ { .compatible = "renesas,rpc-r7s72100" },
{ .compatible = "renesas,rpc-r8a7795" },
{ .compatible = "renesas,rpc-r8a7796" },
{ .compatible = "renesas,rpc-r8a77965" },
{ .compatible = "renesas,rpc-r8a77970" },
{ .compatible = "renesas,rpc-r8a77995" },
- { .compatible = "renesas,rpc-r7s72100" },
+ { .compatible = "renesas,rcar-gen3-rpc" },
{ }
};
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
new file mode 100644
index 0000000000..6f8df55fa5
--- /dev/null
+++ b/drivers/spi/spi-qup.c
@@ -0,0 +1,803 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Qualcomm QUP SPI controller
+ * FIFO and Block modes supported, no DMA
+ * mode support
+ *
+ * Copyright (c) 2020 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ * Author: Luka Kovacic <luka.kovacic@sartura.hr>
+ *
+ * Based on stock U-boot and Linux drivers
+ */
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <linux/delay.h>
+#include <spi.h>
+
+#define QUP_CONFIG 0x0000
+#define QUP_STATE 0x0004
+#define QUP_IO_M_MODES 0x0008
+#define QUP_SW_RESET 0x000c
+#define QUP_OPERATIONAL 0x0018
+#define QUP_ERROR_FLAGS 0x001c
+#define QUP_ERROR_FLAGS_EN 0x0020
+#define QUP_OPERATIONAL_MASK 0x0028
+#define QUP_HW_VERSION 0x0030
+#define QUP_MX_OUTPUT_CNT 0x0100
+#define QUP_OUTPUT_FIFO 0x0110
+#define QUP_MX_WRITE_CNT 0x0150
+#define QUP_MX_INPUT_CNT 0x0200
+#define QUP_MX_READ_CNT 0x0208
+#define QUP_INPUT_FIFO 0x0218
+
+#define SPI_CONFIG 0x0300
+#define SPI_IO_CONTROL 0x0304
+#define SPI_ERROR_FLAGS 0x0308
+#define SPI_ERROR_FLAGS_EN 0x030c
+
+/* QUP_CONFIG fields */
+#define QUP_CONFIG_SPI_MODE BIT(8)
+#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13)
+#define QUP_CONFIG_NO_INPUT BIT(7)
+#define QUP_CONFIG_NO_OUTPUT BIT(6)
+#define QUP_CONFIG_N 0x001f
+
+/* QUP_STATE fields */
+#define QUP_STATE_VALID BIT(2)
+#define QUP_STATE_RESET 0
+#define QUP_STATE_RUN 1
+#define QUP_STATE_PAUSE 3
+#define QUP_STATE_MASK 3
+#define QUP_STATE_CLEAR 2
+
+/* QUP_IO_M_MODES fields */
+#define QUP_IO_M_PACK_EN BIT(15)
+#define QUP_IO_M_UNPACK_EN BIT(14)
+#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12
+#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10
+#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT)
+#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT)
+
+#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0)
+#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2)
+#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5)
+#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7)
+
+#define QUP_IO_M_MODE_FIFO 0
+#define QUP_IO_M_MODE_BLOCK 1
+#define QUP_IO_M_MODE_DMOV 2
+#define QUP_IO_M_MODE_BAM 3
+
+/* QUP_OPERATIONAL fields */
+#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
+#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
+#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
+#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
+#define QUP_OP_IN_SERVICE_FLAG BIT(9)
+#define QUP_OP_OUT_SERVICE_FLAG BIT(8)
+#define QUP_OP_IN_FIFO_FULL BIT(7)
+#define QUP_OP_OUT_FIFO_FULL BIT(6)
+#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5)
+#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4)
+
+/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */
+#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5)
+#define QUP_ERROR_INPUT_UNDER_RUN BIT(4)
+#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3)
+#define QUP_ERROR_INPUT_OVER_RUN BIT(2)
+
+/* SPI_CONFIG fields */
+#define SPI_CONFIG_HS_MODE BIT(10)
+#define SPI_CONFIG_INPUT_FIRST BIT(9)
+#define SPI_CONFIG_LOOPBACK BIT(8)
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS BIT(11)
+#define SPI_IO_C_CLK_IDLE_HIGH BIT(10)
+#define SPI_IO_C_MX_CS_MODE BIT(8)
+#define SPI_IO_C_CS_N_POLARITY_0 BIT(4)
+#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2)
+#define SPI_IO_C_CS_SELECT_MASK 0x000c
+#define SPI_IO_C_TRISTATE_CS BIT(1)
+#define SPI_IO_C_NO_TRI_STATE BIT(0)
+
+/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
+#define SPI_ERROR_CLK_OVER_RUN BIT(1)
+#define SPI_ERROR_CLK_UNDER_RUN BIT(0)
+
+#define SPI_NUM_CHIPSELECTS 4
+
+#define SPI_DELAY_THRESHOLD 1
+#define SPI_DELAY_RETRY 10
+
+#define SPI_RESET_STATE 0
+#define SPI_RUN_STATE 1
+#define SPI_CORE_RESET 0
+#define SPI_CORE_RUNNING 1
+
+#define DUMMY_DATA_VAL 0
+#define TIMEOUT_CNT 100
+
+#define QUP_STATE_VALID_BIT 2
+#define QUP_CONFIG_MINI_CORE_MSK (0x0F << 8)
+#define QUP_CONFIG_MINI_CORE_SPI BIT(8)
+#define QUP_CONF_INPUT_MSK BIT(7)
+#define QUP_CONF_INPUT_ENA (0 << 7)
+#define QUP_CONF_NO_INPUT BIT(7)
+#define QUP_CONF_OUTPUT_MSK BIT(6)
+#define QUP_CONF_OUTPUT_ENA (0 << 6)
+#define QUP_CONF_NO_OUTPUT BIT(6)
+#define QUP_STATE_RUN_STATE 0x1
+#define QUP_STATE_RESET_STATE 0x0
+#define QUP_STATE_PAUSE_STATE 0x3
+#define SPI_BIT_WORD_MSK 0x1F
+#define SPI_8_BIT_WORD 0x07
+#define LOOP_BACK_MSK BIT(8)
+#define NO_LOOP_BACK (0 << 8)
+#define SLAVE_OPERATION_MSK BIT(5)
+#define SLAVE_OPERATION (0 << 5)
+#define CLK_ALWAYS_ON (0 << 9)
+#define MX_CS_MODE BIT(8)
+#define CS_POLARITY_MASK BIT(4)
+#define NO_TRI_STATE BIT(0)
+#define FORCE_CS_MSK BIT(11)
+#define FORCE_CS_EN BIT(11)
+#define FORCE_CS_DIS (0 << 11)
+#define OUTPUT_BIT_SHIFT_MSK BIT(16)
+#define OUTPUT_BIT_SHIFT_EN BIT(16)
+#define INPUT_BLOCK_MODE_MSK (0x03 << 12)
+#define INPUT_BLOCK_MODE (0x01 << 12)
+#define OUTPUT_BLOCK_MODE_MSK (0x03 << 10)
+#define OUTPUT_BLOCK_MODE (0x01 << 10)
+#define INPUT_BAM_MODE (0x3 << 12)
+#define OUTPUT_BAM_MODE (0x3 << 10)
+#define PACK_EN (0x1 << 15)
+#define UNPACK_EN (0x1 << 14)
+#define PACK_EN_MSK (0x1 << 15)
+#define UNPACK_EN_MSK (0x1 << 14)
+#define OUTPUT_SERVICE_MSK (0x1 << 8)
+#define INPUT_SERVICE_MSK (0x1 << 9)
+#define OUTPUT_SERVICE_DIS (0x1 << 8)
+#define INPUT_SERVICE_DIS (0x1 << 9)
+#define BLSP0_SPI_DEASSERT_WAIT_REG 0x0310
+#define QUP_DATA_AVAILABLE_FOR_READ BIT(5)
+#define SPI_INPUT_BLOCK_SIZE 4
+#define SPI_OUTPUT_BLOCK_SIZE 4
+#define SPI_BITLEN_MSK 0x07
+#define MAX_COUNT_SIZE 0xffff
+
+struct qup_spi_priv {
+ phys_addr_t base;
+ struct clk clk;
+ u32 num_cs;
+ struct gpio_desc cs_gpios[SPI_NUM_CHIPSELECTS];
+ bool cs_high;
+ u32 core_state;
+};
+
+static int qup_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable)
+{
+ struct qup_spi_priv *priv = dev_get_priv(dev);
+
+ debug("%s: cs=%d enable=%d\n", __func__, cs, enable);
+
+ if (cs >= SPI_NUM_CHIPSELECTS)
+ return -ENODEV;
+
+ if (!dm_gpio_is_valid(&priv->cs_gpios[cs]))
+ return -EINVAL;
+
+ if (priv->cs_high)
+ enable = !enable;
+
+ return dm_gpio_set_value(&priv->cs_gpios[cs], enable ? 1 : 0);
+}
+
+/*
+ * Function to write data to OUTPUT FIFO
+ */
+static void qup_spi_write_byte(struct udevice *dev, unsigned char data)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ /* Wait for space in the FIFO */
+ while ((readl(priv->base + QUP_OPERATIONAL) & QUP_OP_OUT_FIFO_FULL))
+ udelay(1);
+
+ /* Write the byte of data */
+ writel(data, priv->base + QUP_OUTPUT_FIFO);
+}
+
+/*
+ * Function to read data from Input FIFO
+ */
+static unsigned char qup_spi_read_byte(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ /* Wait for Data in FIFO */
+ while (!(readl(priv->base + QUP_OPERATIONAL) & QUP_DATA_AVAILABLE_FOR_READ)) {
+ printf("Stuck at FIFO data wait\n");
+ udelay(1);
+ }
+
+ /* Read a byte of data */
+ return readl(priv->base + QUP_INPUT_FIFO) & 0xff;
+}
+
+/*
+ * Function to check wheather Input or Output FIFO
+ * has data to be serviced
+ */
+static int qup_spi_check_fifo_status(struct udevice *dev, u32 reg_addr)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ unsigned int count = TIMEOUT_CNT;
+ unsigned int status_flag;
+ unsigned int val;
+
+ do {
+ val = readl(priv->base + reg_addr);
+ count--;
+ if (count == 0)
+ return -ETIMEDOUT;
+
+ status_flag = ((val & QUP_OP_OUT_SERVICE_FLAG) | (val & QUP_OP_IN_SERVICE_FLAG));
+ } while (!status_flag);
+
+ return 0;
+}
+
+/*
+ * Function to configure Input and Output enable/disable
+ */
+static void qup_spi_enable_io_config(struct udevice *dev, u32 write_cnt, u32 read_cnt)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+
+ if (write_cnt) {
+ clrsetbits_le32(priv->base + QUP_CONFIG,
+ QUP_CONF_OUTPUT_MSK, QUP_CONF_OUTPUT_ENA);
+ } else {
+ clrsetbits_le32(priv->base + QUP_CONFIG,
+ QUP_CONF_OUTPUT_MSK, QUP_CONF_NO_OUTPUT);
+ }
+
+ if (read_cnt) {
+ clrsetbits_le32(priv->base + QUP_CONFIG,
+ QUP_CONF_INPUT_MSK, QUP_CONF_INPUT_ENA);
+ } else {
+ clrsetbits_le32(priv->base + QUP_CONFIG,
+ QUP_CONF_INPUT_MSK, QUP_CONF_NO_INPUT);
+ }
+}
+
+static int check_bit_state(struct udevice *dev, u32 reg_addr, int bit_num, int val,
+ int us_delay)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ unsigned int count = TIMEOUT_CNT;
+ unsigned int bit_val = ((readl(priv->base + reg_addr) >> bit_num) & 0x01);
+
+ while (bit_val != val) {
+ count--;
+ if (count == 0)
+ return -ETIMEDOUT;
+ udelay(us_delay);
+ bit_val = ((readl(priv->base + reg_addr) >> bit_num) & 0x01);
+ }
+
+ return 0;
+}
+
+/*
+ * Check whether QUPn State is valid
+ */
+static int check_qup_state_valid(struct udevice *dev)
+{
+ return check_bit_state(dev, QUP_STATE, QUP_STATE_VALID, 1, 1);
+}
+
+/*
+ * Configure QUPn Core state
+ */
+static int qup_spi_config_spi_state(struct udevice *dev, unsigned int state)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ u32 val;
+ int ret;
+
+ ret = check_qup_state_valid(dev);
+ if (ret != 0)
+ return ret;
+
+ switch (state) {
+ case SPI_RUN_STATE:
+ /* Set the state to RUN */
+ val = ((readl(priv->base + QUP_STATE) & ~QUP_STATE_MASK)
+ | QUP_STATE_RUN);
+ writel(val, priv->base + QUP_STATE);
+ ret = check_qup_state_valid(dev);
+ if (ret != 0)
+ return ret;
+ priv->core_state = SPI_CORE_RUNNING;
+ break;
+ case SPI_RESET_STATE:
+ /* Set the state to RESET */
+ val = ((readl(priv->base + QUP_STATE) & ~QUP_STATE_MASK)
+ | QUP_STATE_RESET);
+ writel(val, priv->base + QUP_STATE);
+ ret = check_qup_state_valid(dev);
+ if (ret != 0)
+ return ret;
+ priv->core_state = SPI_CORE_RESET;
+ break;
+ default:
+ printf("Unsupported QUP SPI state: %d\n", state);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Function to read bytes number of data from the Input FIFO
+ */
+static int __qup_spi_blsp_spi_read(struct udevice *dev, u8 *data_buffer, unsigned int bytes)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ u32 val;
+ unsigned int i;
+ unsigned int read_bytes = bytes;
+ unsigned int fifo_count;
+ int ret = 0;
+ int state_config;
+
+ /* Configure no of bytes to read */
+ state_config = qup_spi_config_spi_state(dev, SPI_RESET_STATE);
+ if (state_config)
+ return state_config;
+
+ /* Configure input and output enable */
+ qup_spi_enable_io_config(dev, 0, read_bytes);
+
+ writel(bytes, priv->base + QUP_MX_INPUT_CNT);
+
+ state_config = qup_spi_config_spi_state(dev, SPI_RUN_STATE);
+ if (state_config)
+ return state_config;
+
+ while (read_bytes) {
+ ret = qup_spi_check_fifo_status(dev, QUP_OPERATIONAL);
+ if (ret != 0)
+ goto out;
+
+ val = readl(priv->base + QUP_OPERATIONAL);
+ if (val & QUP_OP_IN_SERVICE_FLAG) {
+ /*
+ * acknowledge to hw that software will
+ * read input data
+ */
+ val &= QUP_OP_IN_SERVICE_FLAG;
+ writel(val, priv->base + QUP_OPERATIONAL);
+
+ fifo_count = ((read_bytes > SPI_INPUT_BLOCK_SIZE) ?
+ SPI_INPUT_BLOCK_SIZE : read_bytes);
+
+ for (i = 0; i < fifo_count; i++) {
+ *data_buffer = qup_spi_read_byte(dev);
+ data_buffer++;
+ read_bytes--;
+ }
+ }
+ }
+
+out:
+ /*
+ * Put the SPI Core back in the Reset State
+ * to end the transfer
+ */
+ (void)qup_spi_config_spi_state(dev, SPI_RESET_STATE);
+
+ return ret;
+}
+
+static int qup_spi_blsp_spi_read(struct udevice *dev, u8 *data_buffer, unsigned int bytes)
+{
+ int length, ret;
+
+ while (bytes) {
+ length = (bytes < MAX_COUNT_SIZE) ? bytes : MAX_COUNT_SIZE;
+
+ ret = __qup_spi_blsp_spi_read(dev, data_buffer, length);
+ if (ret != 0)
+ return ret;
+
+ data_buffer += length;
+ bytes -= length;
+ }
+
+ return 0;
+}
+
+/*
+ * Function to write data to the Output FIFO
+ */
+static int __qup_blsp_spi_write(struct udevice *dev, const u8 *cmd_buffer, unsigned int bytes)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ u32 val;
+ unsigned int i;
+ unsigned int write_len = bytes;
+ unsigned int read_len = bytes;
+ unsigned int fifo_count;
+ int ret = 0;
+ int state_config;
+
+ state_config = qup_spi_config_spi_state(dev, SPI_RESET_STATE);
+ if (state_config)
+ return state_config;
+
+ writel(bytes, priv->base + QUP_MX_OUTPUT_CNT);
+ writel(bytes, priv->base + QUP_MX_INPUT_CNT);
+ state_config = qup_spi_config_spi_state(dev, SPI_RUN_STATE);
+ if (state_config)
+ return state_config;
+
+ /* Configure input and output enable */
+ qup_spi_enable_io_config(dev, write_len, read_len);
+
+ /*
+ * read_len considered to ensure that we read the dummy data for the
+ * write we performed. This is needed to ensure with WR-RD transaction
+ * to get the actual data on the subsequent read cycle that happens
+ */
+ while (write_len || read_len) {
+ ret = qup_spi_check_fifo_status(dev, QUP_OPERATIONAL);
+ if (ret != 0)
+ goto out;
+
+ val = readl(priv->base + QUP_OPERATIONAL);
+ if (val & QUP_OP_OUT_SERVICE_FLAG) {
+ /*
+ * acknowledge to hw that software will write
+ * expected output data
+ */
+ val &= QUP_OP_OUT_SERVICE_FLAG;
+ writel(val, priv->base + QUP_OPERATIONAL);
+
+ if (write_len > SPI_OUTPUT_BLOCK_SIZE)
+ fifo_count = SPI_OUTPUT_BLOCK_SIZE;
+ else
+ fifo_count = write_len;
+
+ for (i = 0; i < fifo_count; i++) {
+ /* Write actual data to output FIFO */
+ qup_spi_write_byte(dev, *cmd_buffer);
+ cmd_buffer++;
+ write_len--;
+ }
+ }
+ if (val & QUP_OP_IN_SERVICE_FLAG) {
+ /*
+ * acknowledge to hw that software
+ * will read input data
+ */
+ val &= QUP_OP_IN_SERVICE_FLAG;
+ writel(val, priv->base + QUP_OPERATIONAL);
+
+ if (read_len > SPI_INPUT_BLOCK_SIZE)
+ fifo_count = SPI_INPUT_BLOCK_SIZE;
+ else
+ fifo_count = read_len;
+
+ for (i = 0; i < fifo_count; i++) {
+ /* Read dummy data for the data written */
+ (void)qup_spi_read_byte(dev);
+
+ /* Decrement the write count after reading the
+ * dummy data from the device. This is to make
+ * sure we read dummy data before we write the
+ * data to fifo
+ */
+ read_len--;
+ }
+ }
+ }
+out:
+ /*
+ * Put the SPI Core back in the Reset State
+ * to end the transfer
+ */
+ (void)qup_spi_config_spi_state(dev, SPI_RESET_STATE);
+
+ return ret;
+}
+
+static int qup_spi_blsp_spi_write(struct udevice *dev, const u8 *cmd_buffer, unsigned int bytes)
+{
+ int length, ret;
+
+ while (bytes) {
+ length = (bytes < MAX_COUNT_SIZE) ? bytes : MAX_COUNT_SIZE;
+
+ ret = __qup_blsp_spi_write(dev, cmd_buffer, length);
+ if (ret != 0)
+ return ret;
+
+ cmd_buffer += length;
+ bytes -= length;
+ }
+
+ return 0;
+}
+
+static int qup_spi_set_speed(struct udevice *dev, uint speed)
+{
+ return 0;
+}
+
+static int qup_spi_set_mode(struct udevice *dev, uint mode)
+{
+ struct qup_spi_priv *priv = dev_get_priv(dev);
+ unsigned int clk_idle_state;
+ unsigned int input_first_mode;
+ u32 val;
+
+ switch (mode) {
+ case SPI_MODE_0:
+ clk_idle_state = 0;
+ input_first_mode = SPI_CONFIG_INPUT_FIRST;
+ break;
+ case SPI_MODE_1:
+ clk_idle_state = 0;
+ input_first_mode = 0;
+ break;
+ case SPI_MODE_2:
+ clk_idle_state = 1;
+ input_first_mode = SPI_CONFIG_INPUT_FIRST;
+ break;
+ case SPI_MODE_3:
+ clk_idle_state = 1;
+ input_first_mode = 0;
+ break;
+ default:
+ printf("Unsupported spi mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+ if (mode & SPI_CS_HIGH)
+ priv->cs_high = true;
+ else
+ priv->cs_high = false;
+
+ val = readl(priv->base + SPI_CONFIG);
+ val |= input_first_mode;
+ writel(val, priv->base + SPI_CONFIG);
+
+ val = readl(priv->base + SPI_IO_CONTROL);
+ if (clk_idle_state)
+ val |= SPI_IO_C_CLK_IDLE_HIGH;
+ else
+ val &= ~SPI_IO_C_CLK_IDLE_HIGH;
+
+ writel(val, priv->base + SPI_IO_CONTROL);
+
+ return 0;
+}
+
+static void qup_spi_reset(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+
+ /* Driver may not be probed yet */
+ if (!priv)
+ return;
+
+ writel(0x1, priv->base + QUP_SW_RESET);
+ udelay(5);
+}
+
+static int qup_spi_hw_init(struct udevice *dev)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct qup_spi_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ /* QUPn module configuration */
+ qup_spi_reset(dev);
+
+ /* Set the QUPn state */
+ ret = qup_spi_config_spi_state(dev, SPI_RESET_STATE);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure Mini core to SPI core with Input Output enabled,
+ * SPI master, N = 8 bits
+ */
+ clrsetbits_le32(priv->base + QUP_CONFIG, (QUP_CONFIG_MINI_CORE_MSK |
+ QUP_CONF_INPUT_MSK |
+ QUP_CONF_OUTPUT_MSK |
+ SPI_BIT_WORD_MSK),
+ (QUP_CONFIG_MINI_CORE_SPI |
+ QUP_CONF_INPUT_ENA |
+ QUP_CONF_OUTPUT_ENA |
+ SPI_8_BIT_WORD));
+
+ /*
+ * Configure Input first SPI protocol,
+ * SPI master mode and no loopback
+ */
+ clrsetbits_le32(priv->base + SPI_CONFIG, (LOOP_BACK_MSK |
+ SLAVE_OPERATION_MSK),
+ (NO_LOOP_BACK |
+ SLAVE_OPERATION));
+
+ /*
+ * Configure SPI IO Control Register
+ * CLK_ALWAYS_ON = 0
+ * MX_CS_MODE = 0
+ * NO_TRI_STATE = 1
+ */
+ writel((CLK_ALWAYS_ON | NO_TRI_STATE), priv->base + SPI_IO_CONTROL);
+
+ /*
+ * Configure SPI IO Modes.
+ * OUTPUT_BIT_SHIFT_EN = 1
+ * INPUT_MODE = Block Mode
+ * OUTPUT MODE = Block Mode
+ */
+
+ clrsetbits_le32(priv->base + QUP_IO_M_MODES, (OUTPUT_BIT_SHIFT_MSK |
+ INPUT_BLOCK_MODE_MSK |
+ OUTPUT_BLOCK_MODE_MSK),
+ (OUTPUT_BIT_SHIFT_EN |
+ INPUT_BLOCK_MODE |
+ OUTPUT_BLOCK_MODE));
+
+ /* Disable Error mask */
+ writel(0, priv->base + SPI_ERROR_FLAGS_EN);
+ writel(0, priv->base + QUP_ERROR_FLAGS_EN);
+ writel(0, priv->base + BLSP0_SPI_DEASSERT_WAIT_REG);
+
+ return ret;
+}
+
+static int qup_spi_claim_bus(struct udevice *dev)
+{
+ int ret;
+
+ ret = qup_spi_hw_init(dev);
+ if (ret)
+ return -EIO;
+
+ return 0;
+}
+
+static int qup_spi_release_bus(struct udevice *dev)
+{
+ /* Reset the SPI hardware */
+ qup_spi_reset(dev);
+
+ return 0;
+}
+
+static int qup_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+ unsigned int len;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ int ret = 0;
+
+ if (bitlen & SPI_BITLEN_MSK) {
+ printf("Invalid bit length\n");
+ return -EINVAL;
+ }
+
+ len = bitlen >> 3;
+
+ if (flags & SPI_XFER_BEGIN) {
+ ret = qup_spi_hw_init(dev);
+ if (ret != 0)
+ return ret;
+
+ ret = qup_spi_set_cs(bus, slave_plat->cs, false);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (dout != NULL) {
+ ret = qup_spi_blsp_spi_write(dev, txp, len);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (din != NULL) {
+ ret = qup_spi_blsp_spi_read(dev, rxp, len);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (flags & SPI_XFER_END) {
+ ret = qup_spi_set_cs(bus, slave_plat->cs, true);
+ if (ret != 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int qup_spi_probe(struct udevice *dev)
+{
+ struct qup_spi_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = clk_get_by_index(dev, 0, &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret < 0)
+ return ret;
+
+ priv->num_cs = dev_read_u32_default(dev, "num-cs", 1);
+
+ ret = gpio_request_list_by_name(dev, "cs-gpios", priv->cs_gpios,
+ priv->num_cs, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret < 0) {
+ printf("Can't get %s cs gpios: %d\n", dev->name, ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct dm_spi_ops qup_spi_ops = {
+ .claim_bus = qup_spi_claim_bus,
+ .release_bus = qup_spi_release_bus,
+ .xfer = qup_spi_xfer,
+ .set_speed = qup_spi_set_speed,
+ .set_mode = qup_spi_set_mode,
+ /*
+ * cs_info is not needed, since we require all chip selects to be
+ * in the device tree explicitly
+ */
+};
+
+static const struct udevice_id qup_spi_ids[] = {
+ { .compatible = "qcom,spi-qup-v1.1.1", },
+ { .compatible = "qcom,spi-qup-v2.1.1", },
+ { .compatible = "qcom,spi-qup-v2.2.1", },
+ { }
+};
+
+U_BOOT_DRIVER(spi_qup) = {
+ .name = "spi_qup",
+ .id = UCLASS_SPI,
+ .of_match = qup_spi_ids,
+ .ops = &qup_spi_ops,
+ .priv_auto_alloc_size = sizeof(struct qup_spi_priv),
+ .probe = qup_spi_probe,
+};
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 348630faf3..47a5571aec 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -214,7 +214,7 @@ static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes,
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
const unsigned char *txp = dout;
unsigned char *rxp = din;
- u32 reg, count;
+ u32 reg;
u32 txbytes = bytes;
u32 rxbytes = bytes;
@@ -224,10 +224,10 @@ static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes,
* it sets txp to the initial value for the normal operation.
*/
for ( ; priv->startup < 2; priv->startup++) {
- count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
+ xilinx_spi_fill_txfifo(bus, txp, txbytes);
reg = readl(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
writel(reg, &regs->spicr);
- count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
+ xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
txp = din;
if (priv->startup) {
@@ -251,7 +251,7 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
unsigned char *rxp = din;
u32 txbytes = bytes;
u32 rxbytes = bytes;
- u32 reg, count, timeout;
+ u32 reg, count;
int ret;
debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
index 3f39ef05f2..f2eddec950 100644
--- a/drivers/spi/zynq_qspi.c
+++ b/drivers/spi/zynq_qspi.c
@@ -6,8 +6,10 @@
* Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only)
*/
+#include <clk.h>
#include <common.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <log.h>
#include <malloc.h>
#include <spi.h>
@@ -105,17 +107,29 @@ static int zynq_qspi_ofdata_to_platdata(struct udevice *bus)
plat->regs = (struct zynq_qspi_regs *)fdtdec_get_addr(blob,
node, "reg");
- /* FIXME: Use 166MHz as a suitable default */
- plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
- 166666666);
- plat->speed_hz = plat->frequency / 2;
-
- debug("%s: regs=%p max-frequency=%d\n", __func__,
- plat->regs, plat->frequency);
-
return 0;
}
+/**
+ * zynq_qspi_init_hw - Initialize the hardware
+ * @priv: Pointer to the zynq_qspi_priv structure
+ *
+ * The default settings of the QSPI controller's configurable parameters on
+ * reset are
+ * - Master mode
+ * - Baud rate divisor is set to 2
+ * - Threshold value for TX FIFO not full interrupt is set to 1
+ * - Flash memory interface mode enabled
+ * - Size of the word to be transferred as 8 bit
+ * This function performs the following actions
+ * - Disable and clear all the interrupts
+ * - Enable manual slave select
+ * - Enable auto start
+ * - Deselect all the chip select lines
+ * - Set the size of the word to be transferred as 32 bit
+ * - Set the little endian mode of TX FIFO and
+ * - Enable the QSPI controller
+ */
static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv)
{
struct zynq_qspi_regs *regs = priv->regs;
@@ -159,19 +173,45 @@ static int zynq_qspi_probe(struct udevice *bus)
{
struct zynq_qspi_platdata *plat = dev_get_platdata(bus);
struct zynq_qspi_priv *priv = dev_get_priv(bus);
+ struct clk clk;
+ unsigned long clock;
+ int ret;
priv->regs = plat->regs;
priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH;
+ ret = clk_get_by_name(bus, "ref_clk", &clk);
+ if (ret < 0) {
+ dev_err(bus, "failed to get clock\n");
+ return ret;
+ }
+
+ clock = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(clock)) {
+ dev_err(bus, "failed to get rate\n");
+ return clock;
+ }
+
+ ret = clk_enable(&clk);
+ if (ret && ret != -ENOSYS) {
+ dev_err(bus, "failed to enable clock\n");
+ return ret;
+ }
+
/* init the zynq spi hw */
zynq_qspi_init_hw(priv);
+ plat->frequency = clock;
+ plat->speed_hz = plat->frequency / 2;
+
+ debug("%s: max-frequency=%d\n", __func__, plat->speed_hz);
+
return 0;
}
-/*
+/**
* zynq_qspi_read_data - Copy data to RX buffer
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi_priv structure
* @data: The 32 bit variable where data is stored
* @size: Number of bytes to be copied from data to RX buffer
*/
@@ -214,9 +254,9 @@ static void zynq_qspi_read_data(struct zynq_qspi_priv *priv, u32 data, u8 size)
priv->bytes_to_receive = 0;
}
-/*
+/**
* zynq_qspi_write_data - Copy data from TX buffer
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi_priv structure
* @data: Pointer to the 32 bit variable where data is to be copied
* @size: Number of bytes to be copied from TX buffer to data
*/
@@ -263,6 +303,11 @@ static void zynq_qspi_write_data(struct zynq_qspi_priv *priv,
priv->bytes_to_transfer = 0;
}
+/**
+ * zynq_qspi_chipselect - Select or deselect the chip select line
+ * @priv: Pointer to the zynq_qspi_priv structure
+ * @is_on: Select(1) or deselect (0) the chip select line
+ */
static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on)
{
u32 confr;
@@ -282,9 +327,10 @@ static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on)
writel(confr, &regs->cr);
}
-/*
+/**
* zynq_qspi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi_priv structure
+ * @size: Number of bytes to be copied to fifo
*/
static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size)
{
@@ -322,9 +368,9 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size)
}
}
-/*
+/**
* zynq_qspi_irq_poll - Interrupt service routine of the QSPI controller
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi structure
*
* This function handles TX empty and Mode Fault interrupts only.
* On TX empty interrupt this function reads the received data from RX FIFO and
@@ -410,11 +456,9 @@ static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv)
return 0;
}
-/*
+/**
* zynq_qspi_start_transfer - Initiates the QSPI transfer
- * @qspi: Pointer to the spi_device structure
- * @transfer: Pointer to the spi_transfer structure which provide information
- * about next transfer parameters
+ * @priv: Pointer to the zynq_qspi_priv structure
*
* This function fills the TX FIFO, starts the QSPI transfer, and waits for the
* transfer to be completed.
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index 9923931e36..cb911c34f6 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -8,10 +8,12 @@
#include <common.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <log.h>
#include <malloc.h>
#include <spi.h>
#include <time.h>
+#include <clk.h>
#include <asm/io.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -79,17 +81,10 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
plat->regs = dev_read_addr_ptr(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__,
- plat->regs, plat->frequency);
return 0;
}
@@ -128,13 +123,39 @@ static int zynq_spi_probe(struct udevice *bus)
{
struct zynq_spi_platdata *plat = dev_get_platdata(bus);
struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct clk clk;
+ unsigned long clock;
+ int ret;
priv->regs = plat->regs;
priv->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
+ ret = clk_get_by_name(bus, "ref_clk", &clk);
+ if (ret < 0) {
+ dev_err(bus, "failed to get clock\n");
+ return ret;
+ }
+
+ clock = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(clock)) {
+ dev_err(bus, "failed to get rate\n");
+ return clock;
+ }
+
+ ret = clk_enable(&clk);
+ if (ret && ret != -ENOSYS) {
+ dev_err(bus, "failed to enable clock\n");
+ return ret;
+ }
+
/* init the zynq spi hw */
zynq_spi_init_hw(priv);
+ plat->frequency = clock;
+ plat->speed_hz = plat->frequency / 2;
+
+ debug("%s: max-frequency=%d\n", __func__, plat->speed_hz);
+
return 0;
}