33// Copyright (C) 2008 Juergen Beisert
44
55#include <linux/bits.h>
6+ #include <linux/bitfield.h>
67#include <linux/clk.h>
78#include <linux/completion.h>
89#include <linux/delay.h>
1314#include <linux/io.h>
1415#include <linux/irq.h>
1516#include <linux/kernel.h>
17+ #include <linux/math.h>
18+ #include <linux/math64.h>
1619#include <linux/module.h>
20+ #include <linux/overflow.h>
1721#include <linux/pinctrl/consumer.h>
1822#include <linux/platform_device.h>
1923#include <linux/pm_runtime.h>
@@ -302,6 +306,18 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
302306#define MX51_ECSPI_STAT 0x18
303307#define MX51_ECSPI_STAT_RR (1 << 3)
304308
309+ #define MX51_ECSPI_PERIOD 0x1c
310+ #define MX51_ECSPI_PERIOD_MASK 0x7fff
311+ /*
312+ * As measured on the i.MX6, the SPI host controller inserts a 4 SPI-Clock
313+ * (SCLK) delay after each burst if the PERIOD reg is 0x0. This value will be
314+ * called MX51_ECSPI_PERIOD_MIN_DELAY_SCK.
315+ *
316+ * If the PERIOD register is != 0, the controller inserts a delay of
317+ * MX51_ECSPI_PERIOD_MIN_DELAY_SCK + register value + 1 SCLK after each burst.
318+ */
319+ #define MX51_ECSPI_PERIOD_MIN_DELAY_SCK 4
320+
305321#define MX51_ECSPI_TESTREG 0x20
306322#define MX51_ECSPI_TESTREG_LBC BIT(31)
307323
@@ -652,6 +668,7 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
652668 struct spi_device * spi , struct spi_transfer * t )
653669{
654670 u32 ctrl = readl (spi_imx -> base + MX51_ECSPI_CTRL );
671+ u64 word_delay_sck ;
655672 u32 clk ;
656673
657674 /* Clear BL field and set the right value */
@@ -683,6 +700,49 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
683700
684701 writel (ctrl , spi_imx -> base + MX51_ECSPI_CTRL );
685702
703+ /* calculate word delay in SPI Clock (SCLK) cycles */
704+ if (t -> word_delay .value == 0 ) {
705+ word_delay_sck = 0 ;
706+ } else if (t -> word_delay .unit == SPI_DELAY_UNIT_SCK ) {
707+ word_delay_sck = t -> word_delay .value ;
708+
709+ if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK )
710+ word_delay_sck = 0 ;
711+ else if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1 )
712+ word_delay_sck = 1 ;
713+ else
714+ word_delay_sck -= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1 ;
715+ } else {
716+ int word_delay_ns ;
717+
718+ word_delay_ns = spi_delay_to_ns (& t -> word_delay , t );
719+ if (word_delay_ns < 0 )
720+ return word_delay_ns ;
721+
722+ if (word_delay_ns <= mul_u64_u32_div (NSEC_PER_SEC ,
723+ MX51_ECSPI_PERIOD_MIN_DELAY_SCK ,
724+ spi_imx -> spi_bus_clk )) {
725+ word_delay_sck = 0 ;
726+ } else if (word_delay_ns <= mul_u64_u32_div (NSEC_PER_SEC ,
727+ MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1 ,
728+ spi_imx -> spi_bus_clk )) {
729+ word_delay_sck = 1 ;
730+ } else {
731+ word_delay_ns -= mul_u64_u32_div (NSEC_PER_SEC ,
732+ MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1 ,
733+ spi_imx -> spi_bus_clk );
734+
735+ word_delay_sck = DIV_U64_ROUND_UP ((u64 )word_delay_ns * spi_imx -> spi_bus_clk ,
736+ NSEC_PER_SEC );
737+ }
738+ }
739+
740+ if (!FIELD_FIT (MX51_ECSPI_PERIOD_MASK , word_delay_sck ))
741+ return - EINVAL ;
742+
743+ writel (FIELD_PREP (MX51_ECSPI_PERIOD_MASK , word_delay_sck ),
744+ spi_imx -> base + MX51_ECSPI_PERIOD );
745+
686746 return 0 ;
687747}
688748
@@ -1263,11 +1323,13 @@ static int spi_imx_setupxfer(struct spi_device *spi,
12631323
12641324 /*
12651325 * Initialize the functions for transfer. To transfer non byte-aligned
1266- * words, we have to use multiple word-size bursts, we can't use
1267- * dynamic_burst in that case.
1326+ * words, we have to use multiple word-size bursts. To insert word
1327+ * delay, the burst size has to equal the word size. We can't use
1328+ * dynamic_burst in these cases.
12681329 */
12691330 if (spi_imx -> devtype_data -> dynamic_burst && !spi_imx -> target_mode &&
12701331 !(spi -> mode & SPI_CS_WORD ) &&
1332+ !(t -> word_delay .value ) &&
12711333 (spi_imx -> bits_per_word == 8 ||
12721334 spi_imx -> bits_per_word == 16 ||
12731335 spi_imx -> bits_per_word == 32 )) {
@@ -1610,12 +1672,30 @@ static int spi_imx_pio_transfer_target(struct spi_device *spi,
16101672 return ret ;
16111673}
16121674
1675+ static unsigned int spi_imx_transfer_estimate_time_us (struct spi_transfer * transfer )
1676+ {
1677+ u64 result ;
1678+
1679+ result = DIV_U64_ROUND_CLOSEST ((u64 )USEC_PER_SEC * transfer -> len * BITS_PER_BYTE ,
1680+ transfer -> effective_speed_hz );
1681+ if (transfer -> word_delay .value ) {
1682+ unsigned int word_delay_us ;
1683+ unsigned int words ;
1684+
1685+ words = DIV_ROUND_UP (transfer -> len * BITS_PER_BYTE , transfer -> bits_per_word );
1686+ word_delay_us = DIV_ROUND_CLOSEST (spi_delay_to_ns (& transfer -> word_delay , transfer ),
1687+ NSEC_PER_USEC );
1688+ result += words * word_delay_us ;
1689+ }
1690+
1691+ return min (result , U32_MAX );
1692+ }
1693+
16131694static int spi_imx_transfer_one (struct spi_controller * controller ,
16141695 struct spi_device * spi ,
16151696 struct spi_transfer * transfer )
16161697{
16171698 struct spi_imx_data * spi_imx = spi_controller_get_devdata (spi -> controller );
1618- unsigned long hz_per_byte , byte_limit ;
16191699
16201700 spi_imx_setupxfer (spi , transfer );
16211701 transfer -> effective_speed_hz = spi_imx -> spi_bus_clk ;
@@ -1634,15 +1714,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
16341714 */
16351715 if (spi_imx -> usedma )
16361716 return spi_imx_dma_transfer (spi_imx , transfer );
1637- /*
1638- * Calculate the estimated time in us the transfer runs. Find
1639- * the number of Hz per byte per polling limit.
1640- */
1641- hz_per_byte = polling_limit_us ? ((8 + 4 ) * USEC_PER_SEC ) / polling_limit_us : 0 ;
1642- byte_limit = hz_per_byte ? transfer -> effective_speed_hz / hz_per_byte : 1 ;
16431717
16441718 /* run in polling mode for short transfers */
1645- if (transfer -> len < byte_limit )
1719+ if (transfer -> len == 1 || (polling_limit_us &&
1720+ spi_imx_transfer_estimate_time_us (transfer ) < polling_limit_us ))
16461721 return spi_imx_poll_transfer (spi , transfer );
16471722
16481723 return spi_imx_pio_transfer (spi , transfer );
0 commit comments