[U-Boot] [PATCH v5 4/5] mips: ath79: add spi driver

Signed-off-by: Wills Wang wills.wang@live.com ---
Changes in v5: - remove ar933x_spi_platdata - Import document "spi-ath79.txt" from kernel - Add delay for bitbang operation
Changes in v4: - Use get_bus_freq instead of hardcode in SPI driver
Changes in v3: - Convert spi driver to driver model - Same code style convertion
Changes in v2: - Add a compatible spi driver
arch/mips/mach-ath79/Kconfig | 1 + doc/device-tree-bindings/spi/spi-ath79.txt | 19 +++ drivers/spi/Kconfig | 8 ++ drivers/spi/Makefile | 1 + drivers/spi/ath79_spi.c | 210 +++++++++++++++++++++++++++++ 5 files changed, 239 insertions(+) create mode 100644 doc/device-tree-bindings/spi/spi-ath79.txt create mode 100644 drivers/spi/ath79_spi.c
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART + select ATH79_SPI help This supports QCA/Atheros ar933x family SOCs.
diff --git a/doc/device-tree-bindings/spi/spi-ath79.txt b/doc/device-tree-bindings/spi/spi-ath79.txt new file mode 100644 index 0000000..3fd9d67 --- /dev/null +++ b/doc/device-tree-bindings/spi/spi-ath79.txt @@ -0,0 +1,19 @@ +Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller + +Required properties: +- compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback. +- reg: Base address and size of the controllers memory area +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Child nodes as per the generic SPI binding. + +Example: + + spi@1f000000 { + compatible = "qca,ar9132-spi", "qca,ar7100-spi"; + reg = <0x1f000000 0x10>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2cdb110..0ab2741 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -23,6 +23,14 @@ config ALTERA_SPI IP core. Please find details on the "Embedded Peripherals IP User Guide" of Altera.
+config ATH79_SPI + bool "Atheros SPI driver" + help + Enable the Atheros ar7xxx/ar9xxx SoC SPI driver, it was used + to access SPI NOR flash and other SPI peripherals. This driver + uses driver model and requires a device tree binding to operate. + please refer to doc/device-tree-bindings/spi/spi-ath79.txt. + config CADENCE_QSPI bool "Cadence QSPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3eca745..7fb2926 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,6 +17,7 @@ endif
obj-$(CONFIG_ALTERA_SPI) += altera_spi.o obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o +obj-$(CONFIG_ATH79_SPI) += ath79_spi.o obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o obj-$(CONFIG_BFIN_SPI) += bfin_spi.o diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c new file mode 100644 index 0000000..0bedadb --- /dev/null +++ b/drivers/spi/ath79_spi.c @@ -0,0 +1,210 @@ +/* + * (C) Copyright 2015 + * Wills Wang, wills.wang@live.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <spi.h> +#include <dm.h> +#include <div64.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/types.h> +#include <mach/ar71xx_regs.h> + +/* CLOCK_DIVIDER = 3 (SPI clock = 200 / 8 ~ 25 MHz) */ +#define SPI_CLK_DIV(x) (((x) >> 1) - 1) + +struct ath79_spi_priv { + void __iomem *regs; +}; + +static inline u32 ath79_spi_read(struct udevice *bus, u32 offset) +{ + struct ath79_spi_priv *priv = dev_get_priv(bus); + return readl(priv->regs + offset); +} + +static inline void ath79_spi_write(struct udevice *bus, + u32 val, u32 offset) +{ + struct ath79_spi_priv *priv = dev_get_priv(bus); + writel(val, priv->regs + offset); +} + +static inline void ath79_spi_delay(int max_hz) +{ + uint64_t tick = get_tbclk(); + + do_div(tick, max_hz); + tick = get_ticks() + tick + 1; /* get current timestamp */ + while (get_ticks() < tick) /* loop till event */ + /*NOP*/; +} + +static int ath79_spi_claim_bus(struct udevice *dev) +{ + return 0; +} + +static int ath79_spi_release_bus(struct udevice *dev) +{ + return 0; +} + +static int ath79_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev); + uint8_t *rx = din; + const uint8_t *tx = dout; + uint8_t curbyte, curbitlen, restbits; + uint32_t bytes = bitlen / 8; + uint32_t out; + uint32_t in; + + if (flags & SPI_XFER_BEGIN) { + ath79_spi_write(bus, AR71XX_SPI_FS_GPIO, AR71XX_SPI_REG_FS); + ath79_spi_write(bus, AR71XX_SPI_IOC_CS_ALL, AR71XX_SPI_REG_IOC); + } + + restbits = (bitlen % 8); + if (restbits) + bytes++; + + out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs)); + while (bytes > 0) { + bytes--; + curbyte = 0; + if (tx) + curbyte = *tx++; + + if (restbits && !bytes) { + curbitlen = restbits; + curbyte <<= 8 - restbits; + } else { + curbitlen = 8; + } + + for (curbyte <<= (8 - curbitlen); curbitlen; curbitlen--) { + if (curbyte & 0x80) + out |= AR71XX_SPI_IOC_DO; + else + out &= ~(AR71XX_SPI_IOC_DO); + + ath79_spi_write(bus, out, AR71XX_SPI_REG_IOC); + ath79_spi_delay(slave->max_hz); + ath79_spi_write(bus, out | AR71XX_SPI_IOC_CLK, + AR71XX_SPI_REG_IOC); + ath79_spi_delay(slave->max_hz); + curbyte <<= 1; + } + + if (!bytes) + ath79_spi_write(bus, out, AR71XX_SPI_REG_IOC); + + in = ath79_spi_read(bus, AR71XX_SPI_REG_RDS); + if (rx) { + if (restbits && !bytes) + *rx++ = (in << (8 - restbits)); + else + *rx++ = in; + } + } + + if (flags & SPI_XFER_END) { + ath79_spi_write(bus, AR71XX_SPI_IOC_CS(slave->cs), + AR71XX_SPI_REG_IOC); + ath79_spi_write(bus, AR71XX_SPI_IOC_CS_ALL, AR71XX_SPI_REG_IOC); + ath79_spi_write(bus, 0, AR71XX_SPI_REG_FS); + } + + return 0; +} + + +static int ath79_spi_set_speed(struct udevice *bus, uint speed) +{ + u32 val, div = 0; + + if (speed) + div = get_bus_freq(0) / speed; + + if (div > 63) + div = 63; + + if (div < 5) + div = 5; + + ath79_spi_write(bus, AR71XX_SPI_FS_GPIO, AR71XX_SPI_REG_FS); + val = ath79_spi_read(bus, AR71XX_SPI_REG_CTRL); + val &= ~AR71XX_SPI_CTRL_DIV_MASK; + val |= SPI_CLK_DIV(div); + ath79_spi_write(bus, val, AR71XX_SPI_REG_CTRL); + ath79_spi_write(bus, 0, AR71XX_SPI_REG_FS); + return 0; +} + +static int ath79_spi_set_mode(struct udevice *bus, uint mode) +{ + return 0; +} + +static int ath79_spi_probe(struct udevice *bus) +{ + struct ath79_spi_priv *priv = dev_get_priv(bus); + fdt_addr_t addr; + + addr = dev_get_addr(bus); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = map_physmem(addr, + AR71XX_SPI_SIZE, + MAP_NOCACHE); + + /* Init SPI Hardware, disable remap, set clock */ + ath79_spi_write(bus, AR71XX_SPI_FS_GPIO, AR71XX_SPI_REG_FS); + ath79_spi_write(bus, AR71XX_SPI_CTRL_RD | SPI_CLK_DIV(8), + AR71XX_SPI_REG_CTRL); + ath79_spi_write(bus, 0, AR71XX_SPI_REG_FS); + + return 0; +} + +static int ath79_cs_info(struct udevice *bus, uint cs, + struct spi_cs_info *info) +{ + /* Always allow activity on CS 0/1/2 */ + if (cs >= 3) + return -ENODEV; + + return 0; +} + +static const struct dm_spi_ops ath79_spi_ops = { + .claim_bus = ath79_spi_claim_bus, + .release_bus = ath79_spi_release_bus, + .xfer = ath79_spi_xfer, + .set_speed = ath79_spi_set_speed, + .set_mode = ath79_spi_set_mode, + .cs_info = ath79_cs_info, +}; + +static const struct udevice_id ath79_spi_ids[] = { + { .compatible = "qca,ar7100-spi" }, + {} +}; + +U_BOOT_DRIVER(ath79_spi) = { + .name = "ath79_spi", + .id = UCLASS_SPI, + .of_match = ath79_spi_ids, + .ops = &ath79_spi_ops, + .priv_auto_alloc_size = sizeof(struct ath79_spi_priv), + .probe = ath79_spi_probe, +};

Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
Best regards, Thomas

On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Best regards, Marek Vasut

Hi Marek,
On 2015年12月29日 21:25, Marek Vasut wrote:
On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Sorry, my mistake. Just realized that we don't have nano delay yet. The code above is fine.
Best regards, Thomas

On Wednesday, December 30, 2015 at 12:46:23 AM, Thomas Chou wrote:
Hi Marek,
On 2015年12月29日 21:25, Marek Vasut wrote:
On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Sorry, my mistake. Just realized that we don't have nano delay yet. The code above is fine.
Just skimming through the code, it seems like bitbanging the SPI using the generic soft-spi driver might be easier ;-/
Best regards, Marek Vasut

Hi Marek and Wills,
On 2015年12月30日 08:51, Marek Vasut wrote:
Just skimming through the code, it seems like bitbanging the SPI using the generic soft-spi driver might be easier ;-/
I read the data sheet and Linux driver. Now I have clearer picture of this device. In serial flash mode, it reads like CFI flash. But we need to switch to bitbanging mode to write flash. In bitbanging, we have shift in data as word read. Though the cs, clk and dout are gpio. And the soft-spi of u-boot won't fit well.
So the current ath79_spi_delay() is fine. as we don't have ndelay() in u-boot yet. But the set_speed() code is for serial flash mode, and does not apply to bitbanging mode. You should save the result of do_div(tick, max_hz) to priv data, because dividing can take some time. You may trim the count with rrw_delay like that of Linux driver for more accurate timing.
BTW, the usage of uint8_t,uint32_t and uint64_t is deprecated. Please change them to u8, u32 and u64. It will be helpful to run checkpatch.pl.
Thanks a lot for your work.
Best regards, Thomas

On Wed, 30 Dec 2015 01:51:47 +0100 Marek Vasut marex@denx.de wrote:
On Wednesday, December 30, 2015 at 12:46:23 AM, Thomas Chou wrote:
Hi Marek,
On 2015年12月29日 21:25, Marek Vasut wrote:
On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Sorry, my mistake. Just realized that we don't have nano delay yet. The code above is fine.
Just skimming through the code, it seems like bitbanging the SPI using the generic soft-spi driver might be easier ;-/
AR9331 SPI controller has special shift register for reading received data, so you have no need in reading every single receiving MISO bit with separate gpio access, this can give a small speedup. Next, in openwrt tree there is a dirty-hacky ath79-spi linux kernel patch for very impressive SPI flash read speedup (2 MiB/s instead of 20 KiB/s, I have no precise bandwidth results at the moment). So for better performance it is reasonable to have separate ath79-spi driver.
-- Best regards, Antony Pavlov

On Wednesday, December 30, 2015 at 09:32:52 AM, Antony Pavlov wrote:
On Wed, 30 Dec 2015 01:51:47 +0100
Marek Vasut marex@denx.de wrote:
On Wednesday, December 30, 2015 at 12:46:23 AM, Thomas Chou wrote:
Hi Marek,
On 2015年12月29日 21:25, Marek Vasut wrote:
On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Sorry, my mistake. Just realized that we don't have nano delay yet. The code above is fine.
Just skimming through the code, it seems like bitbanging the SPI using the generic soft-spi driver might be easier ;-/
AR9331 SPI controller has special shift register for reading received data, so you have no need in reading every single receiving MISO bit with separate gpio access, this can give a small speedup. Next, in openwrt tree there is a dirty-hacky ath79-spi linux kernel patch for very impressive SPI flash read speedup (2 MiB/s instead of 20 KiB/s, I have no precise bandwidth results at the moment). So for better performance it is reasonable to have separate ath79-spi driver.
OK
Best regards, Marek Vasut

On 12/29/2015 09:25 PM, Marek Vasut wrote:
On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Does get_timer() return time in milliseconds?
Best regards, Marek Vasut

On Wednesday, December 30, 2015 at 02:35:01 AM, Wills Wang wrote:
On 12/29/2015 09:25 PM, Marek Vasut wrote:
On Tuesday, December 29, 2015 at 02:00:27 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X
select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
You mean get_timer() based delay loop, yes ?
Does get_timer() return time in milliseconds?
Yes, but there's also timer_get_us() .
Best regards, Marek Vasut

On 12/29/2015 09:00 PM, Thomas Chou wrote:
Hi Wills,
On 2015年12月29日 19:17, Wills Wang wrote:
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig index 1d92a5b..b5668e9 100644 --- a/arch/mips/mach-ath79/Kconfig +++ b/arch/mips/mach-ath79/Kconfig @@ -15,6 +15,7 @@ config SOC_AR933X select SYS_MIPS_CACHE_INIT_RAM_LOAD select MIPS_TUNE_24KC select AR933X_UART
- select ATH79_SPI
Both AR933X_UART and ATH79_SPI should not be selected with mach Kconfig. They should go with board defconfig.
Ok.
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
+static inline void ath79_spi_delay(int max_hz) +{
- uint64_t tick = get_tbclk();
- do_div(tick, max_hz);
- tick = get_ticks() + tick + 1; /* get current timestamp */
- while (get_ticks() < tick) /* loop till event */
/*NOP*/;
+}
Use udelay() instead.
The minimum interval is 1usec if using udelay(), the max speed of SPI was really limited to 1MHz.
Best regards, Thomas
participants (4)
-
Antony Pavlov
-
Marek Vasut
-
Thomas Chou
-
Wills Wang