diff options
Diffstat (limited to 'drivers/spi/spi-imx.c')
| -rw-r--r-- | drivers/spi/spi-imx.c | 214 |
1 files changed, 157 insertions, 57 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 1439883326cf..b8b79bb7fec3 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -3,6 +3,7 @@ // Copyright (C) 2008 Juergen Beisert #include <linux/bits.h> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -13,7 +14,10 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> +#include <linux/math.h> +#include <linux/math64.h> #include <linux/module.h> +#include <linux/overflow.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -38,6 +42,7 @@ MODULE_PARM_DESC(polling_limit_us, "time in us to run a transfer in polling mode\n"); #define MXC_RPM_TIMEOUT 2000 /* 2000ms */ +#define MXC_SPI_DEFAULT_SPEED 500000 /* 500KHz */ #define MXC_CSPIRXDATA 0x00 #define MXC_CSPITXDATA 0x04 @@ -71,7 +76,8 @@ struct spi_imx_data; struct spi_imx_devtype_data { void (*intctrl)(struct spi_imx_data *spi_imx, int enable); int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg); - int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi); + int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi, + struct spi_transfer *t); void (*trigger)(struct spi_imx_data *spi_imx); int (*rx_available)(struct spi_imx_data *spi_imx); void (*reset)(struct spi_imx_data *spi_imx); @@ -301,6 +307,18 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device #define MX51_ECSPI_STAT 0x18 #define MX51_ECSPI_STAT_RR (1 << 3) +#define MX51_ECSPI_PERIOD 0x1c +#define MX51_ECSPI_PERIOD_MASK 0x7fff +/* + * As measured on the i.MX6, the SPI host controller inserts a 4 SPI-Clock + * (SCLK) delay after each burst if the PERIOD reg is 0x0. This value will be + * called MX51_ECSPI_PERIOD_MIN_DELAY_SCK. + * + * If the PERIOD register is != 0, the controller inserts a delay of + * MX51_ECSPI_PERIOD_MIN_DELAY_SCK + register value + 1 SCLK after each burst. + */ +#define MX51_ECSPI_PERIOD_MIN_DELAY_SCK 4 + #define MX51_ECSPI_TESTREG 0x20 #define MX51_ECSPI_TESTREG_LBC BIT(31) @@ -407,8 +425,15 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx) { - u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA)); + u32 val = readl(spi_imx->base + MXC_CSPIRXDATA); +#ifdef __LITTLE_ENDIAN + unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + if (bytes_per_word == 1) + swab32s(&val); + else if (bytes_per_word == 2) + swahw32s(&val); +#endif if (spi_imx->rx_buf) { int n_bytes = spi_imx->target_burst % sizeof(val); @@ -429,6 +454,9 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx) { u32 val = 0; int n_bytes = spi_imx->count % sizeof(val); +#ifdef __LITTLE_ENDIAN + unsigned int bytes_per_word; +#endif if (!n_bytes) n_bytes = sizeof(val); @@ -436,12 +464,18 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx) if (spi_imx->tx_buf) { memcpy(((u8 *)&val) + sizeof(val) - n_bytes, spi_imx->tx_buf, n_bytes); - val = cpu_to_be32(val); spi_imx->tx_buf += n_bytes; } spi_imx->count -= n_bytes; +#ifdef __LITTLE_ENDIAN + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + if (bytes_per_word == 1) + swab32s(&val); + else if (bytes_per_word == 2) + swahw32s(&val); +#endif writel(val, spi_imx->base + MXC_CSPITXDATA); } @@ -503,9 +537,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx) { u32 reg; - reg = readl(spi_imx->base + MX51_ECSPI_CTRL); - reg |= MX51_ECSPI_CTRL_XCH; - writel(reg, spi_imx->base + MX51_ECSPI_CTRL); + if (spi_imx->usedma) { + reg = readl(spi_imx->base + MX51_ECSPI_DMA); + reg |= MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN; + writel(reg, spi_imx->base + MX51_ECSPI_DMA); + } else { + reg = readl(spi_imx->base + MX51_ECSPI_CTRL); + reg |= MX51_ECSPI_CTRL_XCH; + writel(reg, spi_imx->base + MX51_ECSPI_CTRL); + } } static void mx51_ecspi_disable(struct spi_imx_data *spi_imx) @@ -569,7 +609,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, * is not functional for imx53 Soc, config SPI burst completed when * BURST_LENGTH + 1 bits are received */ - if (spi_imx->target_mode && is_imx53_ecspi(spi_imx)) + if (spi_imx->target_mode) cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(channel); else cfg |= MX51_ECSPI_CONFIG_SBBCTRL(channel); @@ -649,14 +689,15 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx, } static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + u64 word_delay_sck; u32 clk; /* Clear BL field and set the right value */ ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; - if (spi_imx->target_mode && is_imx53_ecspi(spi_imx)) + if (spi_imx->target_mode) ctrl |= (spi_imx->target_burst * 8 - 1) << MX51_ECSPI_CTRL_BL_OFFSET; else { @@ -667,8 +708,11 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, /* set clock speed */ ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET | 0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET); - ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk); - spi_imx->spi_bus_clk = clk; + + if (!spi_imx->target_mode) { + ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk); + spi_imx->spi_bus_clk = clk; + } mx51_configure_cpha(spi_imx, spi); @@ -683,6 +727,49 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); + /* calculate word delay in SPI Clock (SCLK) cycles */ + if (t->word_delay.value == 0) { + word_delay_sck = 0; + } else if (t->word_delay.unit == SPI_DELAY_UNIT_SCK) { + word_delay_sck = t->word_delay.value; + + if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK) + word_delay_sck = 0; + else if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1) + word_delay_sck = 1; + else + word_delay_sck -= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1; + } else { + int word_delay_ns; + + word_delay_ns = spi_delay_to_ns(&t->word_delay, t); + if (word_delay_ns < 0) + return word_delay_ns; + + if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK, + spi_imx->spi_bus_clk)) { + word_delay_sck = 0; + } else if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1, + spi_imx->spi_bus_clk)) { + word_delay_sck = 1; + } else { + word_delay_ns -= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1, + spi_imx->spi_bus_clk); + + word_delay_sck = DIV_U64_ROUND_UP((u64)word_delay_ns * spi_imx->spi_bus_clk, + NSEC_PER_SEC); + } + } + + if (!FIELD_FIT(MX51_ECSPI_PERIOD_MASK, word_delay_sck)) + return -EINVAL; + + writel(FIELD_PREP(MX51_ECSPI_PERIOD_MASK, word_delay_sck), + spi_imx->base + MX51_ECSPI_PERIOD); + return 0; } @@ -699,7 +786,6 @@ static void mx51_setup_wml(struct spi_imx_data *spi_imx) writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) | MX51_ECSPI_DMA_TX_WML(tx_wml) | MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) | - MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN | MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA); } @@ -774,7 +860,7 @@ static int mx31_prepare_message(struct spi_imx_data *spi_imx, } static int mx31_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST; unsigned int clk; @@ -878,7 +964,7 @@ static int mx21_prepare_message(struct spi_imx_data *spi_imx, } static int mx21_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; @@ -953,7 +1039,7 @@ static int mx1_prepare_message(struct spi_imx_data *spi_imx, } static int mx1_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST; unsigned int clk; @@ -1248,26 +1334,31 @@ static int spi_imx_setupxfer(struct spi_device *spi, if (!t) return 0; - if (!t->speed_hz) { - if (!spi->max_speed_hz) { - dev_err(&spi->dev, "no speed_hz provided!\n"); - return -EINVAL; + if (!spi_imx->target_mode) { + if (!t->speed_hz) { + if (!spi->max_speed_hz) { + dev_err(&spi->dev, "no speed_hz provided!\n"); + return -EINVAL; + } + dev_dbg(&spi->dev, "using spi->max_speed_hz!\n"); + spi_imx->spi_bus_clk = spi->max_speed_hz; + } else { + spi_imx->spi_bus_clk = t->speed_hz; } - dev_dbg(&spi->dev, "using spi->max_speed_hz!\n"); - spi_imx->spi_bus_clk = spi->max_speed_hz; - } else - spi_imx->spi_bus_clk = t->speed_hz; + } spi_imx->bits_per_word = t->bits_per_word; spi_imx->count = t->len; /* * Initialize the functions for transfer. To transfer non byte-aligned - * words, we have to use multiple word-size bursts, we can't use - * dynamic_burst in that case. + * words, we have to use multiple word-size bursts. To insert word + * delay, the burst size has to equal the word size. We can't use + * dynamic_burst in these cases. */ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode && !(spi->mode & SPI_CS_WORD) && + !(t->word_delay.value) && (spi_imx->bits_per_word == 8 || spi_imx->bits_per_word == 16 || spi_imx->bits_per_word == 32)) { @@ -1298,13 +1389,13 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->rx_only = ((t->tx_buf == NULL) || (t->tx_buf == spi->controller->dummy_tx)); - if (is_imx53_ecspi(spi_imx) && spi_imx->target_mode) { + if (spi_imx->target_mode) { spi_imx->rx = mx53_ecspi_rx_target; spi_imx->tx = mx53_ecspi_tx_target; spi_imx->target_burst = t->len; } - spi_imx->devtype_data->prepare_transfer(spi_imx, spi); + spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t); return 0; } @@ -1387,7 +1478,7 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size) timeout += 1; /* Double calculated timeout */ - return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC); + return secs_to_jiffies(2 * timeout); } static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, @@ -1458,6 +1549,8 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, reinit_completion(&spi_imx->dma_tx_completion); dma_async_issue_pending(controller->dma_tx); + spi_imx->devtype_data->trigger(spi_imx); + transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); /* Wait SDMA to finish the data transfer.*/ @@ -1572,8 +1665,7 @@ static int spi_imx_pio_transfer_target(struct spi_device *spi, struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); int ret = 0; - if (is_imx53_ecspi(spi_imx) && - transfer->len > MX53_MAX_TRANSFER_BYTES) { + if (transfer->len > MX53_MAX_TRANSFER_BYTES) { dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n", MX53_MAX_TRANSFER_BYTES); return -EMSGSIZE; @@ -1610,14 +1702,35 @@ static int spi_imx_pio_transfer_target(struct spi_device *spi, return ret; } +static unsigned int spi_imx_transfer_estimate_time_us(struct spi_transfer *transfer) +{ + u64 result; + + result = DIV_U64_ROUND_CLOSEST((u64)USEC_PER_SEC * transfer->len * BITS_PER_BYTE, + transfer->effective_speed_hz); + if (transfer->word_delay.value) { + unsigned int word_delay_us; + unsigned int words; + + words = DIV_ROUND_UP(transfer->len * BITS_PER_BYTE, transfer->bits_per_word); + word_delay_us = DIV_ROUND_CLOSEST(spi_delay_to_ns(&transfer->word_delay, transfer), + NSEC_PER_USEC); + result += (u64)words * word_delay_us; + } + + return min(result, U32_MAX); +} + static int spi_imx_transfer_one(struct spi_controller *controller, struct spi_device *spi, struct spi_transfer *transfer) { + int ret; struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); - unsigned long hz_per_byte, byte_limit; - spi_imx_setupxfer(spi, transfer); + ret = spi_imx_setupxfer(spi, transfer); + if (ret < 0) + return ret; transfer->effective_speed_hz = spi_imx->spi_bus_clk; /* flush rxfifo before transfer */ @@ -1634,15 +1747,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller, */ if (spi_imx->usedma) return spi_imx_dma_transfer(spi_imx, transfer); - /* - * Calculate the estimated time in us the transfer runs. Find - * the number of Hz per byte per polling limit. - */ - hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0; - byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1; /* run in polling mode for short transfers */ - if (transfer->len < byte_limit) + if (transfer->len == 1 || (polling_limit_us && + spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us)) return spi_imx_poll_transfer(spi, transfer); return spi_imx_pio_transfer(spi, transfer); @@ -1656,10 +1764,6 @@ static int spi_imx_setup(struct spi_device *spi) return 0; } -static void spi_imx_cleanup(struct spi_device *spi) -{ -} - static int spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg) { @@ -1674,7 +1778,6 @@ spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *m ret = spi_imx->devtype_data->prepare_message(spi_imx, msg); if (ret) { - pm_runtime_mark_last_busy(spi_imx->dev); pm_runtime_put_autosuspend(spi_imx->dev); } @@ -1686,7 +1789,6 @@ spi_imx_unprepare_message(struct spi_controller *controller, struct spi_message { struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); - pm_runtime_mark_last_busy(spi_imx->dev); pm_runtime_put_autosuspend(spi_imx->dev); return 0; } @@ -1756,10 +1858,10 @@ static int spi_imx_probe(struct platform_device *pdev) controller->transfer_one = spi_imx_transfer_one; controller->setup = spi_imx_setup; - controller->cleanup = spi_imx_cleanup; controller->prepare_message = spi_imx_prepare_message; controller->unprepare_message = spi_imx_unprepare_message; controller->target_abort = spi_imx_target_abort; + spi_imx->spi_bus_clk = MXC_SPI_DEFAULT_SPEED; controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS | SPI_MOSI_IDLE_LOW; @@ -1860,7 +1962,6 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_register_controller; } - pm_runtime_mark_last_busy(spi_imx->dev); pm_runtime_put_autosuspend(spi_imx->dev); return ret; @@ -1870,8 +1971,8 @@ out_register_controller: spi_imx_sdma_exit(spi_imx); out_runtime_pm_put: pm_runtime_dont_use_autosuspend(spi_imx->dev); - pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(spi_imx->dev); + pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(spi_imx->clk_ipg); out_put_per: @@ -1903,7 +2004,7 @@ static void spi_imx_remove(struct platform_device *pdev) spi_imx_sdma_exit(spi_imx); } -static int __maybe_unused spi_imx_runtime_resume(struct device *dev) +static int spi_imx_runtime_resume(struct device *dev) { struct spi_controller *controller = dev_get_drvdata(dev); struct spi_imx_data *spi_imx; @@ -1924,7 +2025,7 @@ static int __maybe_unused spi_imx_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) +static int spi_imx_runtime_suspend(struct device *dev) { struct spi_controller *controller = dev_get_drvdata(dev); struct spi_imx_data *spi_imx; @@ -1937,32 +2038,31 @@ static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused spi_imx_suspend(struct device *dev) +static int spi_imx_suspend(struct device *dev) { pinctrl_pm_select_sleep_state(dev); return 0; } -static int __maybe_unused spi_imx_resume(struct device *dev) +static int spi_imx_resume(struct device *dev) { pinctrl_pm_select_default_state(dev); return 0; } static const struct dev_pm_ops imx_spi_pm = { - SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend, - spi_imx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume) + RUNTIME_PM_OPS(spi_imx_runtime_suspend, spi_imx_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume) }; static struct platform_driver spi_imx_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = spi_imx_dt_ids, - .pm = &imx_spi_pm, + .pm = pm_ptr(&imx_spi_pm), }, .probe = spi_imx_probe, - .remove_new = spi_imx_remove, + .remove = spi_imx_remove, }; module_platform_driver(spi_imx_driver); |
