162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. 362306a36Sopenharmony_ci// Copyright (C) 2008 Juergen Beisert 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/bits.h> 662306a36Sopenharmony_ci#include <linux/clk.h> 762306a36Sopenharmony_ci#include <linux/completion.h> 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/dmaengine.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/irq.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/spi/spi.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/property.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/dma/imx-dma.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define DRIVER_NAME "spi_imx" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic bool use_dma = true; 3162306a36Sopenharmony_cimodule_param(use_dma, bool, 0644); 3262306a36Sopenharmony_ciMODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* define polling limits */ 3562306a36Sopenharmony_cistatic unsigned int polling_limit_us = 30; 3662306a36Sopenharmony_cimodule_param(polling_limit_us, uint, 0664); 3762306a36Sopenharmony_ciMODULE_PARM_DESC(polling_limit_us, 3862306a36Sopenharmony_ci "time in us to run a transfer in polling mode\n"); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define MXC_RPM_TIMEOUT 2000 /* 2000ms */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define MXC_CSPIRXDATA 0x00 4362306a36Sopenharmony_ci#define MXC_CSPITXDATA 0x04 4462306a36Sopenharmony_ci#define MXC_CSPICTRL 0x08 4562306a36Sopenharmony_ci#define MXC_CSPIINT 0x0c 4662306a36Sopenharmony_ci#define MXC_RESET 0x1c 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* generic defines to abstract from the different register layouts */ 4962306a36Sopenharmony_ci#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ 5062306a36Sopenharmony_ci#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ 5162306a36Sopenharmony_ci#define MXC_INT_RDR BIT(4) /* Receive date threshold interrupt */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* The maximum bytes that a sdma BD can transfer. */ 5462306a36Sopenharmony_ci#define MAX_SDMA_BD_BYTES (1 << 15) 5562306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_MAX_BURST 512 5662306a36Sopenharmony_ci/* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/ 5762306a36Sopenharmony_ci#define MX53_MAX_TRANSFER_BYTES 512 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cienum spi_imx_devtype { 6062306a36Sopenharmony_ci IMX1_CSPI, 6162306a36Sopenharmony_ci IMX21_CSPI, 6262306a36Sopenharmony_ci IMX27_CSPI, 6362306a36Sopenharmony_ci IMX31_CSPI, 6462306a36Sopenharmony_ci IMX35_CSPI, /* CSPI on all i.mx except above */ 6562306a36Sopenharmony_ci IMX51_ECSPI, /* ECSPI on i.mx51 */ 6662306a36Sopenharmony_ci IMX53_ECSPI, /* ECSPI on i.mx53 and later */ 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistruct spi_imx_data; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct spi_imx_devtype_data { 7262306a36Sopenharmony_ci void (*intctrl)(struct spi_imx_data *spi_imx, int enable); 7362306a36Sopenharmony_ci int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg); 7462306a36Sopenharmony_ci int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi); 7562306a36Sopenharmony_ci void (*trigger)(struct spi_imx_data *spi_imx); 7662306a36Sopenharmony_ci int (*rx_available)(struct spi_imx_data *spi_imx); 7762306a36Sopenharmony_ci void (*reset)(struct spi_imx_data *spi_imx); 7862306a36Sopenharmony_ci void (*setup_wml)(struct spi_imx_data *spi_imx); 7962306a36Sopenharmony_ci void (*disable)(struct spi_imx_data *spi_imx); 8062306a36Sopenharmony_ci bool has_dmamode; 8162306a36Sopenharmony_ci bool has_targetmode; 8262306a36Sopenharmony_ci unsigned int fifo_size; 8362306a36Sopenharmony_ci bool dynamic_burst; 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * ERR009165 fixed or not: 8662306a36Sopenharmony_ci * https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci bool tx_glitch_fixed; 8962306a36Sopenharmony_ci enum spi_imx_devtype devtype; 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct spi_imx_data { 9362306a36Sopenharmony_ci struct spi_controller *controller; 9462306a36Sopenharmony_ci struct device *dev; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci struct completion xfer_done; 9762306a36Sopenharmony_ci void __iomem *base; 9862306a36Sopenharmony_ci unsigned long base_phys; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci struct clk *clk_per; 10162306a36Sopenharmony_ci struct clk *clk_ipg; 10262306a36Sopenharmony_ci unsigned long spi_clk; 10362306a36Sopenharmony_ci unsigned int spi_bus_clk; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci unsigned int bits_per_word; 10662306a36Sopenharmony_ci unsigned int spi_drctl; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci unsigned int count, remainder; 10962306a36Sopenharmony_ci void (*tx)(struct spi_imx_data *spi_imx); 11062306a36Sopenharmony_ci void (*rx)(struct spi_imx_data *spi_imx); 11162306a36Sopenharmony_ci void *rx_buf; 11262306a36Sopenharmony_ci const void *tx_buf; 11362306a36Sopenharmony_ci unsigned int txfifo; /* number of words pushed in tx FIFO */ 11462306a36Sopenharmony_ci unsigned int dynamic_burst; 11562306a36Sopenharmony_ci bool rx_only; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Target mode */ 11862306a36Sopenharmony_ci bool target_mode; 11962306a36Sopenharmony_ci bool target_aborted; 12062306a36Sopenharmony_ci unsigned int target_burst; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* DMA */ 12362306a36Sopenharmony_ci bool usedma; 12462306a36Sopenharmony_ci u32 wml; 12562306a36Sopenharmony_ci struct completion dma_rx_completion; 12662306a36Sopenharmony_ci struct completion dma_tx_completion; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci const struct spi_imx_devtype_data *devtype_data; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic inline int is_imx27_cspi(struct spi_imx_data *d) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci return d->devtype_data->devtype == IMX27_CSPI; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic inline int is_imx35_cspi(struct spi_imx_data *d) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci return d->devtype_data->devtype == IMX35_CSPI; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic inline int is_imx51_ecspi(struct spi_imx_data *d) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return d->devtype_data->devtype == IMX51_ECSPI; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic inline int is_imx53_ecspi(struct spi_imx_data *d) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci return d->devtype_data->devtype == IMX53_ECSPI; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define MXC_SPI_BUF_RX(type) \ 15262306a36Sopenharmony_cistatic void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ 15362306a36Sopenharmony_ci{ \ 15462306a36Sopenharmony_ci unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); \ 15562306a36Sopenharmony_ci \ 15662306a36Sopenharmony_ci if (spi_imx->rx_buf) { \ 15762306a36Sopenharmony_ci *(type *)spi_imx->rx_buf = val; \ 15862306a36Sopenharmony_ci spi_imx->rx_buf += sizeof(type); \ 15962306a36Sopenharmony_ci } \ 16062306a36Sopenharmony_ci \ 16162306a36Sopenharmony_ci spi_imx->remainder -= sizeof(type); \ 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define MXC_SPI_BUF_TX(type) \ 16562306a36Sopenharmony_cistatic void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx) \ 16662306a36Sopenharmony_ci{ \ 16762306a36Sopenharmony_ci type val = 0; \ 16862306a36Sopenharmony_ci \ 16962306a36Sopenharmony_ci if (spi_imx->tx_buf) { \ 17062306a36Sopenharmony_ci val = *(type *)spi_imx->tx_buf; \ 17162306a36Sopenharmony_ci spi_imx->tx_buf += sizeof(type); \ 17262306a36Sopenharmony_ci } \ 17362306a36Sopenharmony_ci \ 17462306a36Sopenharmony_ci spi_imx->count -= sizeof(type); \ 17562306a36Sopenharmony_ci \ 17662306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPITXDATA); \ 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciMXC_SPI_BUF_RX(u8) 18062306a36Sopenharmony_ciMXC_SPI_BUF_TX(u8) 18162306a36Sopenharmony_ciMXC_SPI_BUF_RX(u16) 18262306a36Sopenharmony_ciMXC_SPI_BUF_TX(u16) 18362306a36Sopenharmony_ciMXC_SPI_BUF_RX(u32) 18462306a36Sopenharmony_ciMXC_SPI_BUF_TX(u32) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* First entry is reserved, second entry is valid only if SDHC_SPIEN is set 18762306a36Sopenharmony_ci * (which is currently not the case in this driver) 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 19062306a36Sopenharmony_ci 256, 384, 512, 768, 1024}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* MX21, MX27 */ 19362306a36Sopenharmony_cistatic unsigned int spi_imx_clkdiv_1(unsigned int fin, 19462306a36Sopenharmony_ci unsigned int fspi, unsigned int max, unsigned int *fres) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int i; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci for (i = 2; i < max; i++) 19962306a36Sopenharmony_ci if (fspi * mxc_clkdivs[i] >= fin) 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci *fres = fin / mxc_clkdivs[i]; 20362306a36Sopenharmony_ci return i; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* MX1, MX31, MX35, MX51 CSPI */ 20762306a36Sopenharmony_cistatic unsigned int spi_imx_clkdiv_2(unsigned int fin, 20862306a36Sopenharmony_ci unsigned int fspi, unsigned int *fres) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int i, div = 4; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 21362306a36Sopenharmony_ci if (fspi * div >= fin) 21462306a36Sopenharmony_ci goto out; 21562306a36Sopenharmony_ci div <<= 1; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciout: 21962306a36Sopenharmony_ci *fres = fin / div; 22062306a36Sopenharmony_ci return i; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int spi_imx_bytes_per_word(const int bits_per_word) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci if (bits_per_word <= 8) 22662306a36Sopenharmony_ci return 1; 22762306a36Sopenharmony_ci else if (bits_per_word <= 16) 22862306a36Sopenharmony_ci return 2; 22962306a36Sopenharmony_ci else 23062306a36Sopenharmony_ci return 4; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device *spi, 23462306a36Sopenharmony_ci struct spi_transfer *transfer) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (!use_dma || controller->fallback) 23962306a36Sopenharmony_ci return false; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (!controller->dma_rx) 24262306a36Sopenharmony_ci return false; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (spi_imx->target_mode) 24562306a36Sopenharmony_ci return false; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (transfer->len < spi_imx->devtype_data->fifo_size) 24862306a36Sopenharmony_ci return false; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci spi_imx->dynamic_burst = 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return true; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * Note the number of natively supported chip selects for MX51 is 4. Some 25762306a36Sopenharmony_ci * devices may have less actual SS pins but the register map supports 4. When 25862306a36Sopenharmony_ci * using gpio chip selects the cs values passed into the macros below can go 25962306a36Sopenharmony_ci * outside the range 0 - 3. We therefore need to limit the cs value to avoid 26062306a36Sopenharmony_ci * corrupting bits outside the allocated locations. 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * The simplest way to do this is to just mask the cs bits to 2 bits. This 26362306a36Sopenharmony_ci * still allows all 4 native chip selects to work as well as gpio chip selects 26462306a36Sopenharmony_ci * (which can use any of the 4 chip select configurations). 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci#define MX51_ECSPI_CTRL 0x08 26862306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_ENABLE (1 << 0) 26962306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_XCH (1 << 2) 27062306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_SMC (1 << 3) 27162306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4) 27262306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_DRCTL(drctl) ((drctl) << 16) 27362306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8 27462306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 27562306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_CS(cs) ((cs & 3) << 18) 27662306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_BL_OFFSET 20 27762306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20) 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG 0x0c 28062306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs & 3) + 0)) 28162306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4)) 28262306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8)) 28362306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12)) 28462306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_DATACTL(cs) (1 << ((cs & 3) + 16)) 28562306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20)) 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci#define MX51_ECSPI_INT 0x10 28862306a36Sopenharmony_ci#define MX51_ECSPI_INT_TEEN (1 << 0) 28962306a36Sopenharmony_ci#define MX51_ECSPI_INT_RREN (1 << 3) 29062306a36Sopenharmony_ci#define MX51_ECSPI_INT_RDREN (1 << 4) 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci#define MX51_ECSPI_DMA 0x14 29362306a36Sopenharmony_ci#define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f) 29462306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RX_WML(wml) (((wml) & 0x3f) << 16) 29562306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RXT_WML(wml) (((wml) & 0x3f) << 24) 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#define MX51_ECSPI_DMA_TEDEN (1 << 7) 29862306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RXDEN (1 << 23) 29962306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RXTDEN (1 << 31) 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci#define MX51_ECSPI_STAT 0x18 30262306a36Sopenharmony_ci#define MX51_ECSPI_STAT_RR (1 << 3) 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci#define MX51_ECSPI_TESTREG 0x20 30562306a36Sopenharmony_ci#define MX51_ECSPI_TESTREG_LBC BIT(31) 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (spi_imx->rx_buf) { 31262306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN 31362306a36Sopenharmony_ci unsigned int bytes_per_word; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); 31662306a36Sopenharmony_ci if (bytes_per_word == 1) 31762306a36Sopenharmony_ci swab32s(&val); 31862306a36Sopenharmony_ci else if (bytes_per_word == 2) 31962306a36Sopenharmony_ci swahw32s(&val); 32062306a36Sopenharmony_ci#endif 32162306a36Sopenharmony_ci *(u32 *)spi_imx->rx_buf = val; 32262306a36Sopenharmony_ci spi_imx->rx_buf += sizeof(u32); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci spi_imx->remainder -= sizeof(u32); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci int unaligned; 33162306a36Sopenharmony_ci u32 val; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci unaligned = spi_imx->remainder % 4; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (!unaligned) { 33662306a36Sopenharmony_ci spi_imx_buf_rx_swap_u32(spi_imx); 33762306a36Sopenharmony_ci return; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) { 34162306a36Sopenharmony_ci spi_imx_buf_rx_u16(spi_imx); 34262306a36Sopenharmony_ci return; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci val = readl(spi_imx->base + MXC_CSPIRXDATA); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci while (unaligned--) { 34862306a36Sopenharmony_ci if (spi_imx->rx_buf) { 34962306a36Sopenharmony_ci *(u8 *)spi_imx->rx_buf = (val >> (8 * unaligned)) & 0xff; 35062306a36Sopenharmony_ci spi_imx->rx_buf++; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci spi_imx->remainder--; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci u32 val = 0; 35962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN 36062306a36Sopenharmony_ci unsigned int bytes_per_word; 36162306a36Sopenharmony_ci#endif 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (spi_imx->tx_buf) { 36462306a36Sopenharmony_ci val = *(u32 *)spi_imx->tx_buf; 36562306a36Sopenharmony_ci spi_imx->tx_buf += sizeof(u32); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci spi_imx->count -= sizeof(u32); 36962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN 37062306a36Sopenharmony_ci bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (bytes_per_word == 1) 37362306a36Sopenharmony_ci swab32s(&val); 37462306a36Sopenharmony_ci else if (bytes_per_word == 2) 37562306a36Sopenharmony_ci swahw32s(&val); 37662306a36Sopenharmony_ci#endif 37762306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPITXDATA); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci int unaligned; 38362306a36Sopenharmony_ci u32 val = 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci unaligned = spi_imx->count % 4; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (!unaligned) { 38862306a36Sopenharmony_ci spi_imx_buf_tx_swap_u32(spi_imx); 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) { 39362306a36Sopenharmony_ci spi_imx_buf_tx_u16(spi_imx); 39462306a36Sopenharmony_ci return; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci while (unaligned--) { 39862306a36Sopenharmony_ci if (spi_imx->tx_buf) { 39962306a36Sopenharmony_ci val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned); 40062306a36Sopenharmony_ci spi_imx->tx_buf++; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci spi_imx->count--; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPITXDATA); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA)); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (spi_imx->rx_buf) { 41362306a36Sopenharmony_ci int n_bytes = spi_imx->target_burst % sizeof(val); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (!n_bytes) 41662306a36Sopenharmony_ci n_bytes = sizeof(val); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci memcpy(spi_imx->rx_buf, 41962306a36Sopenharmony_ci ((u8 *)&val) + sizeof(val) - n_bytes, n_bytes); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci spi_imx->rx_buf += n_bytes; 42262306a36Sopenharmony_ci spi_imx->target_burst -= n_bytes; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci spi_imx->remainder -= sizeof(u32); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci u32 val = 0; 43162306a36Sopenharmony_ci int n_bytes = spi_imx->count % sizeof(val); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (!n_bytes) 43462306a36Sopenharmony_ci n_bytes = sizeof(val); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (spi_imx->tx_buf) { 43762306a36Sopenharmony_ci memcpy(((u8 *)&val) + sizeof(val) - n_bytes, 43862306a36Sopenharmony_ci spi_imx->tx_buf, n_bytes); 43962306a36Sopenharmony_ci val = cpu_to_be32(val); 44062306a36Sopenharmony_ci spi_imx->tx_buf += n_bytes; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci spi_imx->count -= n_bytes; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPITXDATA); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* MX51 eCSPI */ 44962306a36Sopenharmony_cistatic unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx, 45062306a36Sopenharmony_ci unsigned int fspi, unsigned int *fres) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * there are two 4-bit dividers, the pre-divider divides by 45462306a36Sopenharmony_ci * $pre, the post-divider by 2^$post 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_ci unsigned int pre, post; 45762306a36Sopenharmony_ci unsigned int fin = spi_imx->spi_clk; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci fspi = min(fspi, fin); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci post = fls(fin) - fls(fspi); 46262306a36Sopenharmony_ci if (fin > fspi << post) 46362306a36Sopenharmony_ci post++; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* now we have: (fin <= fspi << post) with post being minimal */ 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci post = max(4U, post) - 4; 46862306a36Sopenharmony_ci if (unlikely(post > 0xf)) { 46962306a36Sopenharmony_ci dev_err(spi_imx->dev, "cannot set clock freq: %u (base freq: %u)\n", 47062306a36Sopenharmony_ci fspi, fin); 47162306a36Sopenharmony_ci return 0xff; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci pre = DIV_ROUND_UP(fin, fspi << post) - 1; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci dev_dbg(spi_imx->dev, "%s: fin: %u, fspi: %u, post: %u, pre: %u\n", 47762306a36Sopenharmony_ci __func__, fin, fspi, post, pre); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Resulting frequency for the SCLK line. */ 48062306a36Sopenharmony_ci *fres = (fin / (pre + 1)) >> post; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) | 48362306a36Sopenharmony_ci (post << MX51_ECSPI_CTRL_POSTDIV_OFFSET); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci unsigned int val = 0; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (enable & MXC_INT_TE) 49162306a36Sopenharmony_ci val |= MX51_ECSPI_INT_TEEN; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (enable & MXC_INT_RR) 49462306a36Sopenharmony_ci val |= MX51_ECSPI_INT_RREN; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (enable & MXC_INT_RDR) 49762306a36Sopenharmony_ci val |= MX51_ECSPI_INT_RDREN; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci writel(val, spi_imx->base + MX51_ECSPI_INT); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void mx51_ecspi_trigger(struct spi_imx_data *spi_imx) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci u32 reg; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci reg = readl(spi_imx->base + MX51_ECSPI_CTRL); 50762306a36Sopenharmony_ci reg |= MX51_ECSPI_CTRL_XCH; 50862306a36Sopenharmony_ci writel(reg, spi_imx->base + MX51_ECSPI_CTRL); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic void mx51_ecspi_disable(struct spi_imx_data *spi_imx) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci u32 ctrl; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); 51662306a36Sopenharmony_ci ctrl &= ~MX51_ECSPI_CTRL_ENABLE; 51762306a36Sopenharmony_ci writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int mx51_ecspi_channel(const struct spi_device *spi) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci if (!spi_get_csgpiod(spi, 0)) 52362306a36Sopenharmony_ci return spi_get_chipselect(spi, 0); 52462306a36Sopenharmony_ci return spi->controller->unused_native_cs; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, 52862306a36Sopenharmony_ci struct spi_message *msg) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct spi_device *spi = msg->spi; 53162306a36Sopenharmony_ci struct spi_transfer *xfer; 53262306a36Sopenharmony_ci u32 ctrl = MX51_ECSPI_CTRL_ENABLE; 53362306a36Sopenharmony_ci u32 min_speed_hz = ~0U; 53462306a36Sopenharmony_ci u32 testreg, delay; 53562306a36Sopenharmony_ci u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); 53662306a36Sopenharmony_ci u32 current_cfg = cfg; 53762306a36Sopenharmony_ci int channel = mx51_ecspi_channel(spi); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* set Host or Target mode */ 54062306a36Sopenharmony_ci if (spi_imx->target_mode) 54162306a36Sopenharmony_ci ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK; 54262306a36Sopenharmony_ci else 54362306a36Sopenharmony_ci ctrl |= MX51_ECSPI_CTRL_MODE_MASK; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* 54662306a36Sopenharmony_ci * Enable SPI_RDY handling (falling edge/level triggered). 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci if (spi->mode & SPI_READY) 54962306a36Sopenharmony_ci ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* set chip select to use */ 55262306a36Sopenharmony_ci ctrl |= MX51_ECSPI_CTRL_CS(channel); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* 55562306a36Sopenharmony_ci * The ctrl register must be written first, with the EN bit set other 55662306a36Sopenharmony_ci * registers must not be written to. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci testreg = readl(spi_imx->base + MX51_ECSPI_TESTREG); 56162306a36Sopenharmony_ci if (spi->mode & SPI_LOOP) 56262306a36Sopenharmony_ci testreg |= MX51_ECSPI_TESTREG_LBC; 56362306a36Sopenharmony_ci else 56462306a36Sopenharmony_ci testreg &= ~MX51_ECSPI_TESTREG_LBC; 56562306a36Sopenharmony_ci writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * eCSPI burst completion by Chip Select signal in Target mode 56962306a36Sopenharmony_ci * is not functional for imx53 Soc, config SPI burst completed when 57062306a36Sopenharmony_ci * BURST_LENGTH + 1 bits are received 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci if (spi_imx->target_mode && is_imx53_ecspi(spi_imx)) 57362306a36Sopenharmony_ci cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(channel); 57462306a36Sopenharmony_ci else 57562306a36Sopenharmony_ci cfg |= MX51_ECSPI_CONFIG_SBBCTRL(channel); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) { 57862306a36Sopenharmony_ci cfg |= MX51_ECSPI_CONFIG_SCLKPOL(channel); 57962306a36Sopenharmony_ci cfg |= MX51_ECSPI_CONFIG_SCLKCTL(channel); 58062306a36Sopenharmony_ci } else { 58162306a36Sopenharmony_ci cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(channel); 58262306a36Sopenharmony_ci cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(channel); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (spi->mode & SPI_MOSI_IDLE_LOW) 58662306a36Sopenharmony_ci cfg |= MX51_ECSPI_CONFIG_DATACTL(channel); 58762306a36Sopenharmony_ci else 58862306a36Sopenharmony_ci cfg &= ~MX51_ECSPI_CONFIG_DATACTL(channel); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (spi->mode & SPI_CS_HIGH) 59162306a36Sopenharmony_ci cfg |= MX51_ECSPI_CONFIG_SSBPOL(channel); 59262306a36Sopenharmony_ci else 59362306a36Sopenharmony_ci cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(channel); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (cfg == current_cfg) 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* 60162306a36Sopenharmony_ci * Wait until the changes in the configuration register CONFIGREG 60262306a36Sopenharmony_ci * propagate into the hardware. It takes exactly one tick of the 60362306a36Sopenharmony_ci * SCLK clock, but we will wait two SCLK clock just to be sure. The 60462306a36Sopenharmony_ci * effect of the delay it takes for the hardware to apply changes 60562306a36Sopenharmony_ci * is noticable if the SCLK clock run very slow. In such a case, if 60662306a36Sopenharmony_ci * the polarity of SCLK should be inverted, the GPIO ChipSelect might 60762306a36Sopenharmony_ci * be asserted before the SCLK polarity changes, which would disrupt 60862306a36Sopenharmony_ci * the SPI communication as the device on the other end would consider 60962306a36Sopenharmony_ci * the change of SCLK polarity as a clock tick already. 61062306a36Sopenharmony_ci * 61162306a36Sopenharmony_ci * Because spi_imx->spi_bus_clk is only set in prepare_message 61262306a36Sopenharmony_ci * callback, iterate over all the transfers in spi_message, find the 61362306a36Sopenharmony_ci * one with lowest bus frequency, and use that bus frequency for the 61462306a36Sopenharmony_ci * delay calculation. In case all transfers have speed_hz == 0, then 61562306a36Sopenharmony_ci * min_speed_hz is ~0 and the resulting delay is zero. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci list_for_each_entry(xfer, &msg->transfers, transfer_list) { 61862306a36Sopenharmony_ci if (!xfer->speed_hz) 61962306a36Sopenharmony_ci continue; 62062306a36Sopenharmony_ci min_speed_hz = min(xfer->speed_hz, min_speed_hz); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci delay = (2 * 1000000) / min_speed_hz; 62462306a36Sopenharmony_ci if (likely(delay < 10)) /* SCLK is faster than 200 kHz */ 62562306a36Sopenharmony_ci udelay(delay); 62662306a36Sopenharmony_ci else /* SCLK is _very_ slow */ 62762306a36Sopenharmony_ci usleep_range(delay, delay + 10); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return 0; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic void mx51_configure_cpha(struct spi_imx_data *spi_imx, 63362306a36Sopenharmony_ci struct spi_device *spi) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci bool cpha = (spi->mode & SPI_CPHA); 63662306a36Sopenharmony_ci bool flip_cpha = (spi->mode & SPI_RX_CPHA_FLIP) && spi_imx->rx_only; 63762306a36Sopenharmony_ci u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); 63862306a36Sopenharmony_ci int channel = mx51_ecspi_channel(spi); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Flip cpha logical value iff flip_cpha */ 64162306a36Sopenharmony_ci cpha ^= flip_cpha; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (cpha) 64462306a36Sopenharmony_ci cfg |= MX51_ECSPI_CONFIG_SCLKPHA(channel); 64562306a36Sopenharmony_ci else 64662306a36Sopenharmony_ci cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(channel); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, 65262306a36Sopenharmony_ci struct spi_device *spi) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); 65562306a36Sopenharmony_ci u32 clk; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Clear BL field and set the right value */ 65862306a36Sopenharmony_ci ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; 65962306a36Sopenharmony_ci if (spi_imx->target_mode && is_imx53_ecspi(spi_imx)) 66062306a36Sopenharmony_ci ctrl |= (spi_imx->target_burst * 8 - 1) 66162306a36Sopenharmony_ci << MX51_ECSPI_CTRL_BL_OFFSET; 66262306a36Sopenharmony_ci else { 66362306a36Sopenharmony_ci if (spi_imx->usedma) { 66462306a36Sopenharmony_ci ctrl |= (spi_imx->bits_per_word - 1) 66562306a36Sopenharmony_ci << MX51_ECSPI_CTRL_BL_OFFSET; 66662306a36Sopenharmony_ci } else { 66762306a36Sopenharmony_ci if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST) 66862306a36Sopenharmony_ci ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1) 66962306a36Sopenharmony_ci << MX51_ECSPI_CTRL_BL_OFFSET; 67062306a36Sopenharmony_ci else 67162306a36Sopenharmony_ci ctrl |= (spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word, 67262306a36Sopenharmony_ci BITS_PER_BYTE) * spi_imx->bits_per_word - 1) 67362306a36Sopenharmony_ci << MX51_ECSPI_CTRL_BL_OFFSET; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* set clock speed */ 67862306a36Sopenharmony_ci ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET | 67962306a36Sopenharmony_ci 0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET); 68062306a36Sopenharmony_ci ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk); 68162306a36Sopenharmony_ci spi_imx->spi_bus_clk = clk; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci mx51_configure_cpha(spi_imx, spi); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* 68662306a36Sopenharmony_ci * ERR009165: work in XHC mode instead of SMC as PIO on the chips 68762306a36Sopenharmony_ci * before i.mx6ul. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci if (spi_imx->usedma && spi_imx->devtype_data->tx_glitch_fixed) 69062306a36Sopenharmony_ci ctrl |= MX51_ECSPI_CTRL_SMC; 69162306a36Sopenharmony_ci else 69262306a36Sopenharmony_ci ctrl &= ~MX51_ECSPI_CTRL_SMC; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void mx51_setup_wml(struct spi_imx_data *spi_imx) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci u32 tx_wml = 0; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (spi_imx->devtype_data->tx_glitch_fixed) 70462306a36Sopenharmony_ci tx_wml = spi_imx->wml; 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * Configure the DMA register: setup the watermark 70762306a36Sopenharmony_ci * and enable DMA request. 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) | 71062306a36Sopenharmony_ci MX51_ECSPI_DMA_TX_WML(tx_wml) | 71162306a36Sopenharmony_ci MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) | 71262306a36Sopenharmony_ci MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN | 71362306a36Sopenharmony_ci MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci return readl(spi_imx->base + MX51_ECSPI_STAT) & MX51_ECSPI_STAT_RR; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void mx51_ecspi_reset(struct spi_imx_data *spi_imx) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci /* drain receive buffer */ 72462306a36Sopenharmony_ci while (mx51_ecspi_rx_available(spi_imx)) 72562306a36Sopenharmony_ci readl(spi_imx->base + MXC_CSPIRXDATA); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci#define MX31_INTREG_TEEN (1 << 0) 72962306a36Sopenharmony_ci#define MX31_INTREG_RREN (1 << 3) 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci#define MX31_CSPICTRL_ENABLE (1 << 0) 73262306a36Sopenharmony_ci#define MX31_CSPICTRL_HOST (1 << 1) 73362306a36Sopenharmony_ci#define MX31_CSPICTRL_XCH (1 << 2) 73462306a36Sopenharmony_ci#define MX31_CSPICTRL_SMC (1 << 3) 73562306a36Sopenharmony_ci#define MX31_CSPICTRL_POL (1 << 4) 73662306a36Sopenharmony_ci#define MX31_CSPICTRL_PHA (1 << 5) 73762306a36Sopenharmony_ci#define MX31_CSPICTRL_SSCTL (1 << 6) 73862306a36Sopenharmony_ci#define MX31_CSPICTRL_SSPOL (1 << 7) 73962306a36Sopenharmony_ci#define MX31_CSPICTRL_BC_SHIFT 8 74062306a36Sopenharmony_ci#define MX35_CSPICTRL_BL_SHIFT 20 74162306a36Sopenharmony_ci#define MX31_CSPICTRL_CS_SHIFT 24 74262306a36Sopenharmony_ci#define MX35_CSPICTRL_CS_SHIFT 12 74362306a36Sopenharmony_ci#define MX31_CSPICTRL_DR_SHIFT 16 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci#define MX31_CSPI_DMAREG 0x10 74662306a36Sopenharmony_ci#define MX31_DMAREG_RH_DEN (1<<4) 74762306a36Sopenharmony_ci#define MX31_DMAREG_TH_DEN (1<<1) 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci#define MX31_CSPISTATUS 0x14 75062306a36Sopenharmony_ci#define MX31_STATUS_RR (1 << 3) 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci#define MX31_CSPI_TESTREG 0x1C 75362306a36Sopenharmony_ci#define MX31_TEST_LBC (1 << 14) 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/* These functions also work for the i.MX35, but be aware that 75662306a36Sopenharmony_ci * the i.MX35 has a slightly different register layout for bits 75762306a36Sopenharmony_ci * we do not use here. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_cistatic void mx31_intctrl(struct spi_imx_data *spi_imx, int enable) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci unsigned int val = 0; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (enable & MXC_INT_TE) 76462306a36Sopenharmony_ci val |= MX31_INTREG_TEEN; 76562306a36Sopenharmony_ci if (enable & MXC_INT_RR) 76662306a36Sopenharmony_ci val |= MX31_INTREG_RREN; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPIINT); 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic void mx31_trigger(struct spi_imx_data *spi_imx) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci unsigned int reg; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci reg = readl(spi_imx->base + MXC_CSPICTRL); 77662306a36Sopenharmony_ci reg |= MX31_CSPICTRL_XCH; 77762306a36Sopenharmony_ci writel(reg, spi_imx->base + MXC_CSPICTRL); 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int mx31_prepare_message(struct spi_imx_data *spi_imx, 78162306a36Sopenharmony_ci struct spi_message *msg) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int mx31_prepare_transfer(struct spi_imx_data *spi_imx, 78762306a36Sopenharmony_ci struct spi_device *spi) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST; 79062306a36Sopenharmony_ci unsigned int clk; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) << 79362306a36Sopenharmony_ci MX31_CSPICTRL_DR_SHIFT; 79462306a36Sopenharmony_ci spi_imx->spi_bus_clk = clk; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (is_imx35_cspi(spi_imx)) { 79762306a36Sopenharmony_ci reg |= (spi_imx->bits_per_word - 1) << MX35_CSPICTRL_BL_SHIFT; 79862306a36Sopenharmony_ci reg |= MX31_CSPICTRL_SSCTL; 79962306a36Sopenharmony_ci } else { 80062306a36Sopenharmony_ci reg |= (spi_imx->bits_per_word - 1) << MX31_CSPICTRL_BC_SHIFT; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (spi->mode & SPI_CPHA) 80462306a36Sopenharmony_ci reg |= MX31_CSPICTRL_PHA; 80562306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) 80662306a36Sopenharmony_ci reg |= MX31_CSPICTRL_POL; 80762306a36Sopenharmony_ci if (spi->mode & SPI_CS_HIGH) 80862306a36Sopenharmony_ci reg |= MX31_CSPICTRL_SSPOL; 80962306a36Sopenharmony_ci if (!spi_get_csgpiod(spi, 0)) 81062306a36Sopenharmony_ci reg |= (spi_get_chipselect(spi, 0)) << 81162306a36Sopenharmony_ci (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : 81262306a36Sopenharmony_ci MX31_CSPICTRL_CS_SHIFT); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (spi_imx->usedma) 81562306a36Sopenharmony_ci reg |= MX31_CSPICTRL_SMC; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci writel(reg, spi_imx->base + MXC_CSPICTRL); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci reg = readl(spi_imx->base + MX31_CSPI_TESTREG); 82062306a36Sopenharmony_ci if (spi->mode & SPI_LOOP) 82162306a36Sopenharmony_ci reg |= MX31_TEST_LBC; 82262306a36Sopenharmony_ci else 82362306a36Sopenharmony_ci reg &= ~MX31_TEST_LBC; 82462306a36Sopenharmony_ci writel(reg, spi_imx->base + MX31_CSPI_TESTREG); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (spi_imx->usedma) { 82762306a36Sopenharmony_ci /* 82862306a36Sopenharmony_ci * configure DMA requests when RXFIFO is half full and 82962306a36Sopenharmony_ci * when TXFIFO is half empty 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ci writel(MX31_DMAREG_RH_DEN | MX31_DMAREG_TH_DEN, 83262306a36Sopenharmony_ci spi_imx->base + MX31_CSPI_DMAREG); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci return 0; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int mx31_rx_available(struct spi_imx_data *spi_imx) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic void mx31_reset(struct spi_imx_data *spi_imx) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci /* drain receive buffer */ 84662306a36Sopenharmony_ci while (readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR) 84762306a36Sopenharmony_ci readl(spi_imx->base + MXC_CSPIRXDATA); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci#define MX21_INTREG_RR (1 << 4) 85162306a36Sopenharmony_ci#define MX21_INTREG_TEEN (1 << 9) 85262306a36Sopenharmony_ci#define MX21_INTREG_RREN (1 << 13) 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci#define MX21_CSPICTRL_POL (1 << 5) 85562306a36Sopenharmony_ci#define MX21_CSPICTRL_PHA (1 << 6) 85662306a36Sopenharmony_ci#define MX21_CSPICTRL_SSPOL (1 << 8) 85762306a36Sopenharmony_ci#define MX21_CSPICTRL_XCH (1 << 9) 85862306a36Sopenharmony_ci#define MX21_CSPICTRL_ENABLE (1 << 10) 85962306a36Sopenharmony_ci#define MX21_CSPICTRL_HOST (1 << 11) 86062306a36Sopenharmony_ci#define MX21_CSPICTRL_DR_SHIFT 14 86162306a36Sopenharmony_ci#define MX21_CSPICTRL_CS_SHIFT 19 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void mx21_intctrl(struct spi_imx_data *spi_imx, int enable) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci unsigned int val = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (enable & MXC_INT_TE) 86862306a36Sopenharmony_ci val |= MX21_INTREG_TEEN; 86962306a36Sopenharmony_ci if (enable & MXC_INT_RR) 87062306a36Sopenharmony_ci val |= MX21_INTREG_RREN; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPIINT); 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic void mx21_trigger(struct spi_imx_data *spi_imx) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci unsigned int reg; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci reg = readl(spi_imx->base + MXC_CSPICTRL); 88062306a36Sopenharmony_ci reg |= MX21_CSPICTRL_XCH; 88162306a36Sopenharmony_ci writel(reg, spi_imx->base + MXC_CSPICTRL); 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int mx21_prepare_message(struct spi_imx_data *spi_imx, 88562306a36Sopenharmony_ci struct spi_message *msg) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic int mx21_prepare_transfer(struct spi_imx_data *spi_imx, 89162306a36Sopenharmony_ci struct spi_device *spi) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST; 89462306a36Sopenharmony_ci unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; 89562306a36Sopenharmony_ci unsigned int clk; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->spi_bus_clk, max, &clk) 89862306a36Sopenharmony_ci << MX21_CSPICTRL_DR_SHIFT; 89962306a36Sopenharmony_ci spi_imx->spi_bus_clk = clk; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci reg |= spi_imx->bits_per_word - 1; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (spi->mode & SPI_CPHA) 90462306a36Sopenharmony_ci reg |= MX21_CSPICTRL_PHA; 90562306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) 90662306a36Sopenharmony_ci reg |= MX21_CSPICTRL_POL; 90762306a36Sopenharmony_ci if (spi->mode & SPI_CS_HIGH) 90862306a36Sopenharmony_ci reg |= MX21_CSPICTRL_SSPOL; 90962306a36Sopenharmony_ci if (!spi_get_csgpiod(spi, 0)) 91062306a36Sopenharmony_ci reg |= spi_get_chipselect(spi, 0) << MX21_CSPICTRL_CS_SHIFT; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci writel(reg, spi_imx->base + MXC_CSPICTRL); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic int mx21_rx_available(struct spi_imx_data *spi_imx) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci return readl(spi_imx->base + MXC_CSPIINT) & MX21_INTREG_RR; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic void mx21_reset(struct spi_imx_data *spi_imx) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci writel(1, spi_imx->base + MXC_RESET); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci#define MX1_INTREG_RR (1 << 3) 92862306a36Sopenharmony_ci#define MX1_INTREG_TEEN (1 << 8) 92962306a36Sopenharmony_ci#define MX1_INTREG_RREN (1 << 11) 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci#define MX1_CSPICTRL_POL (1 << 4) 93262306a36Sopenharmony_ci#define MX1_CSPICTRL_PHA (1 << 5) 93362306a36Sopenharmony_ci#define MX1_CSPICTRL_XCH (1 << 8) 93462306a36Sopenharmony_ci#define MX1_CSPICTRL_ENABLE (1 << 9) 93562306a36Sopenharmony_ci#define MX1_CSPICTRL_HOST (1 << 10) 93662306a36Sopenharmony_ci#define MX1_CSPICTRL_DR_SHIFT 13 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic void mx1_intctrl(struct spi_imx_data *spi_imx, int enable) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci unsigned int val = 0; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (enable & MXC_INT_TE) 94362306a36Sopenharmony_ci val |= MX1_INTREG_TEEN; 94462306a36Sopenharmony_ci if (enable & MXC_INT_RR) 94562306a36Sopenharmony_ci val |= MX1_INTREG_RREN; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci writel(val, spi_imx->base + MXC_CSPIINT); 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic void mx1_trigger(struct spi_imx_data *spi_imx) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci unsigned int reg; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci reg = readl(spi_imx->base + MXC_CSPICTRL); 95562306a36Sopenharmony_ci reg |= MX1_CSPICTRL_XCH; 95662306a36Sopenharmony_ci writel(reg, spi_imx->base + MXC_CSPICTRL); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int mx1_prepare_message(struct spi_imx_data *spi_imx, 96062306a36Sopenharmony_ci struct spi_message *msg) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic int mx1_prepare_transfer(struct spi_imx_data *spi_imx, 96662306a36Sopenharmony_ci struct spi_device *spi) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST; 96962306a36Sopenharmony_ci unsigned int clk; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) << 97262306a36Sopenharmony_ci MX1_CSPICTRL_DR_SHIFT; 97362306a36Sopenharmony_ci spi_imx->spi_bus_clk = clk; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci reg |= spi_imx->bits_per_word - 1; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (spi->mode & SPI_CPHA) 97862306a36Sopenharmony_ci reg |= MX1_CSPICTRL_PHA; 97962306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) 98062306a36Sopenharmony_ci reg |= MX1_CSPICTRL_POL; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci writel(reg, spi_imx->base + MXC_CSPICTRL); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return 0; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic int mx1_rx_available(struct spi_imx_data *spi_imx) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic void mx1_reset(struct spi_imx_data *spi_imx) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci writel(1, spi_imx->base + MXC_RESET); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx1_cspi_devtype_data = { 99862306a36Sopenharmony_ci .intctrl = mx1_intctrl, 99962306a36Sopenharmony_ci .prepare_message = mx1_prepare_message, 100062306a36Sopenharmony_ci .prepare_transfer = mx1_prepare_transfer, 100162306a36Sopenharmony_ci .trigger = mx1_trigger, 100262306a36Sopenharmony_ci .rx_available = mx1_rx_available, 100362306a36Sopenharmony_ci .reset = mx1_reset, 100462306a36Sopenharmony_ci .fifo_size = 8, 100562306a36Sopenharmony_ci .has_dmamode = false, 100662306a36Sopenharmony_ci .dynamic_burst = false, 100762306a36Sopenharmony_ci .has_targetmode = false, 100862306a36Sopenharmony_ci .devtype = IMX1_CSPI, 100962306a36Sopenharmony_ci}; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx21_cspi_devtype_data = { 101262306a36Sopenharmony_ci .intctrl = mx21_intctrl, 101362306a36Sopenharmony_ci .prepare_message = mx21_prepare_message, 101462306a36Sopenharmony_ci .prepare_transfer = mx21_prepare_transfer, 101562306a36Sopenharmony_ci .trigger = mx21_trigger, 101662306a36Sopenharmony_ci .rx_available = mx21_rx_available, 101762306a36Sopenharmony_ci .reset = mx21_reset, 101862306a36Sopenharmony_ci .fifo_size = 8, 101962306a36Sopenharmony_ci .has_dmamode = false, 102062306a36Sopenharmony_ci .dynamic_burst = false, 102162306a36Sopenharmony_ci .has_targetmode = false, 102262306a36Sopenharmony_ci .devtype = IMX21_CSPI, 102362306a36Sopenharmony_ci}; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx27_cspi_devtype_data = { 102662306a36Sopenharmony_ci /* i.mx27 cspi shares the functions with i.mx21 one */ 102762306a36Sopenharmony_ci .intctrl = mx21_intctrl, 102862306a36Sopenharmony_ci .prepare_message = mx21_prepare_message, 102962306a36Sopenharmony_ci .prepare_transfer = mx21_prepare_transfer, 103062306a36Sopenharmony_ci .trigger = mx21_trigger, 103162306a36Sopenharmony_ci .rx_available = mx21_rx_available, 103262306a36Sopenharmony_ci .reset = mx21_reset, 103362306a36Sopenharmony_ci .fifo_size = 8, 103462306a36Sopenharmony_ci .has_dmamode = false, 103562306a36Sopenharmony_ci .dynamic_burst = false, 103662306a36Sopenharmony_ci .has_targetmode = false, 103762306a36Sopenharmony_ci .devtype = IMX27_CSPI, 103862306a36Sopenharmony_ci}; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx31_cspi_devtype_data = { 104162306a36Sopenharmony_ci .intctrl = mx31_intctrl, 104262306a36Sopenharmony_ci .prepare_message = mx31_prepare_message, 104362306a36Sopenharmony_ci .prepare_transfer = mx31_prepare_transfer, 104462306a36Sopenharmony_ci .trigger = mx31_trigger, 104562306a36Sopenharmony_ci .rx_available = mx31_rx_available, 104662306a36Sopenharmony_ci .reset = mx31_reset, 104762306a36Sopenharmony_ci .fifo_size = 8, 104862306a36Sopenharmony_ci .has_dmamode = false, 104962306a36Sopenharmony_ci .dynamic_burst = false, 105062306a36Sopenharmony_ci .has_targetmode = false, 105162306a36Sopenharmony_ci .devtype = IMX31_CSPI, 105262306a36Sopenharmony_ci}; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx35_cspi_devtype_data = { 105562306a36Sopenharmony_ci /* i.mx35 and later cspi shares the functions with i.mx31 one */ 105662306a36Sopenharmony_ci .intctrl = mx31_intctrl, 105762306a36Sopenharmony_ci .prepare_message = mx31_prepare_message, 105862306a36Sopenharmony_ci .prepare_transfer = mx31_prepare_transfer, 105962306a36Sopenharmony_ci .trigger = mx31_trigger, 106062306a36Sopenharmony_ci .rx_available = mx31_rx_available, 106162306a36Sopenharmony_ci .reset = mx31_reset, 106262306a36Sopenharmony_ci .fifo_size = 8, 106362306a36Sopenharmony_ci .has_dmamode = true, 106462306a36Sopenharmony_ci .dynamic_burst = false, 106562306a36Sopenharmony_ci .has_targetmode = false, 106662306a36Sopenharmony_ci .devtype = IMX35_CSPI, 106762306a36Sopenharmony_ci}; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx51_ecspi_devtype_data = { 107062306a36Sopenharmony_ci .intctrl = mx51_ecspi_intctrl, 107162306a36Sopenharmony_ci .prepare_message = mx51_ecspi_prepare_message, 107262306a36Sopenharmony_ci .prepare_transfer = mx51_ecspi_prepare_transfer, 107362306a36Sopenharmony_ci .trigger = mx51_ecspi_trigger, 107462306a36Sopenharmony_ci .rx_available = mx51_ecspi_rx_available, 107562306a36Sopenharmony_ci .reset = mx51_ecspi_reset, 107662306a36Sopenharmony_ci .setup_wml = mx51_setup_wml, 107762306a36Sopenharmony_ci .fifo_size = 64, 107862306a36Sopenharmony_ci .has_dmamode = true, 107962306a36Sopenharmony_ci .dynamic_burst = true, 108062306a36Sopenharmony_ci .has_targetmode = true, 108162306a36Sopenharmony_ci .disable = mx51_ecspi_disable, 108262306a36Sopenharmony_ci .devtype = IMX51_ECSPI, 108362306a36Sopenharmony_ci}; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx53_ecspi_devtype_data = { 108662306a36Sopenharmony_ci .intctrl = mx51_ecspi_intctrl, 108762306a36Sopenharmony_ci .prepare_message = mx51_ecspi_prepare_message, 108862306a36Sopenharmony_ci .prepare_transfer = mx51_ecspi_prepare_transfer, 108962306a36Sopenharmony_ci .trigger = mx51_ecspi_trigger, 109062306a36Sopenharmony_ci .rx_available = mx51_ecspi_rx_available, 109162306a36Sopenharmony_ci .reset = mx51_ecspi_reset, 109262306a36Sopenharmony_ci .fifo_size = 64, 109362306a36Sopenharmony_ci .has_dmamode = true, 109462306a36Sopenharmony_ci .has_targetmode = true, 109562306a36Sopenharmony_ci .disable = mx51_ecspi_disable, 109662306a36Sopenharmony_ci .devtype = IMX53_ECSPI, 109762306a36Sopenharmony_ci}; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx6ul_ecspi_devtype_data = { 110062306a36Sopenharmony_ci .intctrl = mx51_ecspi_intctrl, 110162306a36Sopenharmony_ci .prepare_message = mx51_ecspi_prepare_message, 110262306a36Sopenharmony_ci .prepare_transfer = mx51_ecspi_prepare_transfer, 110362306a36Sopenharmony_ci .trigger = mx51_ecspi_trigger, 110462306a36Sopenharmony_ci .rx_available = mx51_ecspi_rx_available, 110562306a36Sopenharmony_ci .reset = mx51_ecspi_reset, 110662306a36Sopenharmony_ci .setup_wml = mx51_setup_wml, 110762306a36Sopenharmony_ci .fifo_size = 64, 110862306a36Sopenharmony_ci .has_dmamode = true, 110962306a36Sopenharmony_ci .dynamic_burst = true, 111062306a36Sopenharmony_ci .has_targetmode = true, 111162306a36Sopenharmony_ci .tx_glitch_fixed = true, 111262306a36Sopenharmony_ci .disable = mx51_ecspi_disable, 111362306a36Sopenharmony_ci .devtype = IMX51_ECSPI, 111462306a36Sopenharmony_ci}; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic const struct of_device_id spi_imx_dt_ids[] = { 111762306a36Sopenharmony_ci { .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, }, 111862306a36Sopenharmony_ci { .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, }, 111962306a36Sopenharmony_ci { .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, }, 112062306a36Sopenharmony_ci { .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, }, 112162306a36Sopenharmony_ci { .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, }, 112262306a36Sopenharmony_ci { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, }, 112362306a36Sopenharmony_ci { .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, }, 112462306a36Sopenharmony_ci { .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, }, 112562306a36Sopenharmony_ci { /* sentinel */ } 112662306a36Sopenharmony_ci}; 112762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, spi_imx_dt_ids); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci u32 ctrl; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); 113462306a36Sopenharmony_ci ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; 113562306a36Sopenharmony_ci ctrl |= ((n_bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET); 113662306a36Sopenharmony_ci writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic void spi_imx_push(struct spi_imx_data *spi_imx) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci unsigned int burst_len; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci /* 114462306a36Sopenharmony_ci * Reload the FIFO when the remaining bytes to be transferred in the 114562306a36Sopenharmony_ci * current burst is 0. This only applies when bits_per_word is a 114662306a36Sopenharmony_ci * multiple of 8. 114762306a36Sopenharmony_ci */ 114862306a36Sopenharmony_ci if (!spi_imx->remainder) { 114962306a36Sopenharmony_ci if (spi_imx->dynamic_burst) { 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* We need to deal unaligned data first */ 115262306a36Sopenharmony_ci burst_len = spi_imx->count % MX51_ECSPI_CTRL_MAX_BURST; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (!burst_len) 115562306a36Sopenharmony_ci burst_len = MX51_ECSPI_CTRL_MAX_BURST; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci spi_imx_set_burst_len(spi_imx, burst_len * 8); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci spi_imx->remainder = burst_len; 116062306a36Sopenharmony_ci } else { 116162306a36Sopenharmony_ci spi_imx->remainder = spi_imx_bytes_per_word(spi_imx->bits_per_word); 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) { 116662306a36Sopenharmony_ci if (!spi_imx->count) 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci if (spi_imx->dynamic_burst && 116962306a36Sopenharmony_ci spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder, 4)) 117062306a36Sopenharmony_ci break; 117162306a36Sopenharmony_ci spi_imx->tx(spi_imx); 117262306a36Sopenharmony_ci spi_imx->txfifo++; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!spi_imx->target_mode) 117662306a36Sopenharmony_ci spi_imx->devtype_data->trigger(spi_imx); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic irqreturn_t spi_imx_isr(int irq, void *dev_id) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct spi_imx_data *spi_imx = dev_id; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci while (spi_imx->txfifo && 118462306a36Sopenharmony_ci spi_imx->devtype_data->rx_available(spi_imx)) { 118562306a36Sopenharmony_ci spi_imx->rx(spi_imx); 118662306a36Sopenharmony_ci spi_imx->txfifo--; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (spi_imx->count) { 119062306a36Sopenharmony_ci spi_imx_push(spi_imx); 119162306a36Sopenharmony_ci return IRQ_HANDLED; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci if (spi_imx->txfifo) { 119562306a36Sopenharmony_ci /* No data left to push, but still waiting for rx data, 119662306a36Sopenharmony_ci * enable receive data available interrupt. 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci spi_imx->devtype_data->intctrl( 119962306a36Sopenharmony_ci spi_imx, MXC_INT_RR); 120062306a36Sopenharmony_ci return IRQ_HANDLED; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci spi_imx->devtype_data->intctrl(spi_imx, 0); 120462306a36Sopenharmony_ci complete(&spi_imx->xfer_done); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return IRQ_HANDLED; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int spi_imx_dma_configure(struct spi_controller *controller) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci int ret; 121262306a36Sopenharmony_ci enum dma_slave_buswidth buswidth; 121362306a36Sopenharmony_ci struct dma_slave_config rx = {}, tx = {}; 121462306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) { 121762306a36Sopenharmony_ci case 4: 121862306a36Sopenharmony_ci buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci case 2: 122162306a36Sopenharmony_ci buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci case 1: 122462306a36Sopenharmony_ci buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci default: 122762306a36Sopenharmony_ci return -EINVAL; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci tx.direction = DMA_MEM_TO_DEV; 123162306a36Sopenharmony_ci tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA; 123262306a36Sopenharmony_ci tx.dst_addr_width = buswidth; 123362306a36Sopenharmony_ci tx.dst_maxburst = spi_imx->wml; 123462306a36Sopenharmony_ci ret = dmaengine_slave_config(controller->dma_tx, &tx); 123562306a36Sopenharmony_ci if (ret) { 123662306a36Sopenharmony_ci dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret); 123762306a36Sopenharmony_ci return ret; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci rx.direction = DMA_DEV_TO_MEM; 124162306a36Sopenharmony_ci rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA; 124262306a36Sopenharmony_ci rx.src_addr_width = buswidth; 124362306a36Sopenharmony_ci rx.src_maxburst = spi_imx->wml; 124462306a36Sopenharmony_ci ret = dmaengine_slave_config(controller->dma_rx, &rx); 124562306a36Sopenharmony_ci if (ret) { 124662306a36Sopenharmony_ci dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret); 124762306a36Sopenharmony_ci return ret; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci return 0; 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic int spi_imx_setupxfer(struct spi_device *spi, 125462306a36Sopenharmony_ci struct spi_transfer *t) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci if (!t) 125962306a36Sopenharmony_ci return 0; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (!t->speed_hz) { 126262306a36Sopenharmony_ci if (!spi->max_speed_hz) { 126362306a36Sopenharmony_ci dev_err(&spi->dev, "no speed_hz provided!\n"); 126462306a36Sopenharmony_ci return -EINVAL; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci dev_dbg(&spi->dev, "using spi->max_speed_hz!\n"); 126762306a36Sopenharmony_ci spi_imx->spi_bus_clk = spi->max_speed_hz; 126862306a36Sopenharmony_ci } else 126962306a36Sopenharmony_ci spi_imx->spi_bus_clk = t->speed_hz; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci spi_imx->bits_per_word = t->bits_per_word; 127262306a36Sopenharmony_ci spi_imx->count = t->len; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* 127562306a36Sopenharmony_ci * Initialize the functions for transfer. To transfer non byte-aligned 127662306a36Sopenharmony_ci * words, we have to use multiple word-size bursts, we can't use 127762306a36Sopenharmony_ci * dynamic_burst in that case. 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode && 128062306a36Sopenharmony_ci !(spi->mode & SPI_CS_WORD) && 128162306a36Sopenharmony_ci (spi_imx->bits_per_word == 8 || 128262306a36Sopenharmony_ci spi_imx->bits_per_word == 16 || 128362306a36Sopenharmony_ci spi_imx->bits_per_word == 32)) { 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci spi_imx->rx = spi_imx_buf_rx_swap; 128662306a36Sopenharmony_ci spi_imx->tx = spi_imx_buf_tx_swap; 128762306a36Sopenharmony_ci spi_imx->dynamic_burst = 1; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci } else { 129062306a36Sopenharmony_ci if (spi_imx->bits_per_word <= 8) { 129162306a36Sopenharmony_ci spi_imx->rx = spi_imx_buf_rx_u8; 129262306a36Sopenharmony_ci spi_imx->tx = spi_imx_buf_tx_u8; 129362306a36Sopenharmony_ci } else if (spi_imx->bits_per_word <= 16) { 129462306a36Sopenharmony_ci spi_imx->rx = spi_imx_buf_rx_u16; 129562306a36Sopenharmony_ci spi_imx->tx = spi_imx_buf_tx_u16; 129662306a36Sopenharmony_ci } else { 129762306a36Sopenharmony_ci spi_imx->rx = spi_imx_buf_rx_u32; 129862306a36Sopenharmony_ci spi_imx->tx = spi_imx_buf_tx_u32; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci spi_imx->dynamic_burst = 0; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (spi_imx_can_dma(spi_imx->controller, spi, t)) 130462306a36Sopenharmony_ci spi_imx->usedma = true; 130562306a36Sopenharmony_ci else 130662306a36Sopenharmony_ci spi_imx->usedma = false; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci spi_imx->rx_only = ((t->tx_buf == NULL) 130962306a36Sopenharmony_ci || (t->tx_buf == spi->controller->dummy_tx)); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (is_imx53_ecspi(spi_imx) && spi_imx->target_mode) { 131262306a36Sopenharmony_ci spi_imx->rx = mx53_ecspi_rx_target; 131362306a36Sopenharmony_ci spi_imx->tx = mx53_ecspi_tx_target; 131462306a36Sopenharmony_ci spi_imx->target_burst = t->len; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci spi_imx->devtype_data->prepare_transfer(spi_imx, spi); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci return 0; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic void spi_imx_sdma_exit(struct spi_imx_data *spi_imx) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci struct spi_controller *controller = spi_imx->controller; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (controller->dma_rx) { 132762306a36Sopenharmony_ci dma_release_channel(controller->dma_rx); 132862306a36Sopenharmony_ci controller->dma_rx = NULL; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (controller->dma_tx) { 133262306a36Sopenharmony_ci dma_release_channel(controller->dma_tx); 133362306a36Sopenharmony_ci controller->dma_tx = NULL; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, 133862306a36Sopenharmony_ci struct spi_controller *controller) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci int ret; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci spi_imx->wml = spi_imx->devtype_data->fifo_size / 2; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* Prepare for TX DMA: */ 134562306a36Sopenharmony_ci controller->dma_tx = dma_request_chan(dev, "tx"); 134662306a36Sopenharmony_ci if (IS_ERR(controller->dma_tx)) { 134762306a36Sopenharmony_ci ret = PTR_ERR(controller->dma_tx); 134862306a36Sopenharmony_ci dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret); 134962306a36Sopenharmony_ci controller->dma_tx = NULL; 135062306a36Sopenharmony_ci goto err; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci /* Prepare for RX : */ 135462306a36Sopenharmony_ci controller->dma_rx = dma_request_chan(dev, "rx"); 135562306a36Sopenharmony_ci if (IS_ERR(controller->dma_rx)) { 135662306a36Sopenharmony_ci ret = PTR_ERR(controller->dma_rx); 135762306a36Sopenharmony_ci dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret); 135862306a36Sopenharmony_ci controller->dma_rx = NULL; 135962306a36Sopenharmony_ci goto err; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci init_completion(&spi_imx->dma_rx_completion); 136362306a36Sopenharmony_ci init_completion(&spi_imx->dma_tx_completion); 136462306a36Sopenharmony_ci controller->can_dma = spi_imx_can_dma; 136562306a36Sopenharmony_ci controller->max_dma_len = MAX_SDMA_BD_BYTES; 136662306a36Sopenharmony_ci spi_imx->controller->flags = SPI_CONTROLLER_MUST_RX | 136762306a36Sopenharmony_ci SPI_CONTROLLER_MUST_TX; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci return 0; 137062306a36Sopenharmony_cierr: 137162306a36Sopenharmony_ci spi_imx_sdma_exit(spi_imx); 137262306a36Sopenharmony_ci return ret; 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic void spi_imx_dma_rx_callback(void *cookie) 137662306a36Sopenharmony_ci{ 137762306a36Sopenharmony_ci struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci complete(&spi_imx->dma_rx_completion); 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_cistatic void spi_imx_dma_tx_callback(void *cookie) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci complete(&spi_imx->dma_tx_completion); 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci unsigned long timeout = 0; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* Time with actual data transfer and CS change delay related to HW */ 139462306a36Sopenharmony_ci timeout = (8 + 4) * size / spi_imx->spi_bus_clk; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* Add extra second for scheduler related activities */ 139762306a36Sopenharmony_ci timeout += 1; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* Double calculated timeout */ 140062306a36Sopenharmony_ci return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC); 140162306a36Sopenharmony_ci} 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, 140462306a36Sopenharmony_ci struct spi_transfer *transfer) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc_tx, *desc_rx; 140762306a36Sopenharmony_ci unsigned long transfer_timeout; 140862306a36Sopenharmony_ci unsigned long timeout; 140962306a36Sopenharmony_ci struct spi_controller *controller = spi_imx->controller; 141062306a36Sopenharmony_ci struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; 141162306a36Sopenharmony_ci struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents); 141262306a36Sopenharmony_ci unsigned int bytes_per_word, i; 141362306a36Sopenharmony_ci int ret; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci /* Get the right burst length from the last sg to ensure no tail data */ 141662306a36Sopenharmony_ci bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); 141762306a36Sopenharmony_ci for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { 141862306a36Sopenharmony_ci if (!(sg_dma_len(last_sg) % (i * bytes_per_word))) 141962306a36Sopenharmony_ci break; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci /* Use 1 as wml in case no available burst length got */ 142262306a36Sopenharmony_ci if (i == 0) 142362306a36Sopenharmony_ci i = 1; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci spi_imx->wml = i; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci ret = spi_imx_dma_configure(controller); 142862306a36Sopenharmony_ci if (ret) 142962306a36Sopenharmony_ci goto dma_failure_no_start; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (!spi_imx->devtype_data->setup_wml) { 143262306a36Sopenharmony_ci dev_err(spi_imx->dev, "No setup_wml()?\n"); 143362306a36Sopenharmony_ci ret = -EINVAL; 143462306a36Sopenharmony_ci goto dma_failure_no_start; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci spi_imx->devtype_data->setup_wml(spi_imx); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci /* 143962306a36Sopenharmony_ci * The TX DMA setup starts the transfer, so make sure RX is configured 144062306a36Sopenharmony_ci * before TX. 144162306a36Sopenharmony_ci */ 144262306a36Sopenharmony_ci desc_rx = dmaengine_prep_slave_sg(controller->dma_rx, 144362306a36Sopenharmony_ci rx->sgl, rx->nents, DMA_DEV_TO_MEM, 144462306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 144562306a36Sopenharmony_ci if (!desc_rx) { 144662306a36Sopenharmony_ci ret = -EINVAL; 144762306a36Sopenharmony_ci goto dma_failure_no_start; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci desc_rx->callback = spi_imx_dma_rx_callback; 145162306a36Sopenharmony_ci desc_rx->callback_param = (void *)spi_imx; 145262306a36Sopenharmony_ci dmaengine_submit(desc_rx); 145362306a36Sopenharmony_ci reinit_completion(&spi_imx->dma_rx_completion); 145462306a36Sopenharmony_ci dma_async_issue_pending(controller->dma_rx); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci desc_tx = dmaengine_prep_slave_sg(controller->dma_tx, 145762306a36Sopenharmony_ci tx->sgl, tx->nents, DMA_MEM_TO_DEV, 145862306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 145962306a36Sopenharmony_ci if (!desc_tx) { 146062306a36Sopenharmony_ci dmaengine_terminate_all(controller->dma_tx); 146162306a36Sopenharmony_ci dmaengine_terminate_all(controller->dma_rx); 146262306a36Sopenharmony_ci return -EINVAL; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci desc_tx->callback = spi_imx_dma_tx_callback; 146662306a36Sopenharmony_ci desc_tx->callback_param = (void *)spi_imx; 146762306a36Sopenharmony_ci dmaengine_submit(desc_tx); 146862306a36Sopenharmony_ci reinit_completion(&spi_imx->dma_tx_completion); 146962306a36Sopenharmony_ci dma_async_issue_pending(controller->dma_tx); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* Wait SDMA to finish the data transfer.*/ 147462306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion, 147562306a36Sopenharmony_ci transfer_timeout); 147662306a36Sopenharmony_ci if (!timeout) { 147762306a36Sopenharmony_ci dev_err(spi_imx->dev, "I/O Error in DMA TX\n"); 147862306a36Sopenharmony_ci dmaengine_terminate_all(controller->dma_tx); 147962306a36Sopenharmony_ci dmaengine_terminate_all(controller->dma_rx); 148062306a36Sopenharmony_ci return -ETIMEDOUT; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&spi_imx->dma_rx_completion, 148462306a36Sopenharmony_ci transfer_timeout); 148562306a36Sopenharmony_ci if (!timeout) { 148662306a36Sopenharmony_ci dev_err(&controller->dev, "I/O Error in DMA RX\n"); 148762306a36Sopenharmony_ci spi_imx->devtype_data->reset(spi_imx); 148862306a36Sopenharmony_ci dmaengine_terminate_all(controller->dma_rx); 148962306a36Sopenharmony_ci return -ETIMEDOUT; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci return 0; 149362306a36Sopenharmony_ci/* fallback to pio */ 149462306a36Sopenharmony_cidma_failure_no_start: 149562306a36Sopenharmony_ci transfer->error |= SPI_TRANS_FAIL_NO_START; 149662306a36Sopenharmony_ci return ret; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_cistatic int spi_imx_pio_transfer(struct spi_device *spi, 150062306a36Sopenharmony_ci struct spi_transfer *transfer) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); 150362306a36Sopenharmony_ci unsigned long transfer_timeout; 150462306a36Sopenharmony_ci unsigned long timeout; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci spi_imx->tx_buf = transfer->tx_buf; 150762306a36Sopenharmony_ci spi_imx->rx_buf = transfer->rx_buf; 150862306a36Sopenharmony_ci spi_imx->count = transfer->len; 150962306a36Sopenharmony_ci spi_imx->txfifo = 0; 151062306a36Sopenharmony_ci spi_imx->remainder = 0; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci reinit_completion(&spi_imx->xfer_done); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci spi_imx_push(spi_imx); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&spi_imx->xfer_done, 152162306a36Sopenharmony_ci transfer_timeout); 152262306a36Sopenharmony_ci if (!timeout) { 152362306a36Sopenharmony_ci dev_err(&spi->dev, "I/O Error in PIO\n"); 152462306a36Sopenharmony_ci spi_imx->devtype_data->reset(spi_imx); 152562306a36Sopenharmony_ci return -ETIMEDOUT; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci return 0; 152962306a36Sopenharmony_ci} 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_cistatic int spi_imx_poll_transfer(struct spi_device *spi, 153262306a36Sopenharmony_ci struct spi_transfer *transfer) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); 153562306a36Sopenharmony_ci unsigned long timeout; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci spi_imx->tx_buf = transfer->tx_buf; 153862306a36Sopenharmony_ci spi_imx->rx_buf = transfer->rx_buf; 153962306a36Sopenharmony_ci spi_imx->count = transfer->len; 154062306a36Sopenharmony_ci spi_imx->txfifo = 0; 154162306a36Sopenharmony_ci spi_imx->remainder = 0; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci /* fill in the fifo before timeout calculations if we are 154462306a36Sopenharmony_ci * interrupted here, then the data is getting transferred by 154562306a36Sopenharmony_ci * the HW while we are interrupted 154662306a36Sopenharmony_ci */ 154762306a36Sopenharmony_ci spi_imx_push(spi_imx); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci timeout = spi_imx_calculate_timeout(spi_imx, transfer->len) + jiffies; 155062306a36Sopenharmony_ci while (spi_imx->txfifo) { 155162306a36Sopenharmony_ci /* RX */ 155262306a36Sopenharmony_ci while (spi_imx->txfifo && 155362306a36Sopenharmony_ci spi_imx->devtype_data->rx_available(spi_imx)) { 155462306a36Sopenharmony_ci spi_imx->rx(spi_imx); 155562306a36Sopenharmony_ci spi_imx->txfifo--; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci /* TX */ 155962306a36Sopenharmony_ci if (spi_imx->count) { 156062306a36Sopenharmony_ci spi_imx_push(spi_imx); 156162306a36Sopenharmony_ci continue; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci if (spi_imx->txfifo && 156562306a36Sopenharmony_ci time_after(jiffies, timeout)) { 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci dev_err_ratelimited(&spi->dev, 156862306a36Sopenharmony_ci "timeout period reached: jiffies: %lu- falling back to interrupt mode\n", 156962306a36Sopenharmony_ci jiffies - timeout); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* fall back to interrupt mode */ 157262306a36Sopenharmony_ci return spi_imx_pio_transfer(spi, transfer); 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci return 0; 157762306a36Sopenharmony_ci} 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_cistatic int spi_imx_pio_transfer_target(struct spi_device *spi, 158062306a36Sopenharmony_ci struct spi_transfer *transfer) 158162306a36Sopenharmony_ci{ 158262306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); 158362306a36Sopenharmony_ci int ret = 0; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (is_imx53_ecspi(spi_imx) && 158662306a36Sopenharmony_ci transfer->len > MX53_MAX_TRANSFER_BYTES) { 158762306a36Sopenharmony_ci dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n", 158862306a36Sopenharmony_ci MX53_MAX_TRANSFER_BYTES); 158962306a36Sopenharmony_ci return -EMSGSIZE; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci spi_imx->tx_buf = transfer->tx_buf; 159362306a36Sopenharmony_ci spi_imx->rx_buf = transfer->rx_buf; 159462306a36Sopenharmony_ci spi_imx->count = transfer->len; 159562306a36Sopenharmony_ci spi_imx->txfifo = 0; 159662306a36Sopenharmony_ci spi_imx->remainder = 0; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci reinit_completion(&spi_imx->xfer_done); 159962306a36Sopenharmony_ci spi_imx->target_aborted = false; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci spi_imx_push(spi_imx); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci if (wait_for_completion_interruptible(&spi_imx->xfer_done) || 160662306a36Sopenharmony_ci spi_imx->target_aborted) { 160762306a36Sopenharmony_ci dev_dbg(&spi->dev, "interrupted\n"); 160862306a36Sopenharmony_ci ret = -EINTR; 160962306a36Sopenharmony_ci } 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci /* ecspi has a HW issue when works in Target mode, 161262306a36Sopenharmony_ci * after 64 words writtern to TXFIFO, even TXFIFO becomes empty, 161362306a36Sopenharmony_ci * ECSPI_TXDATA keeps shift out the last word data, 161462306a36Sopenharmony_ci * so we have to disable ECSPI when in target mode after the 161562306a36Sopenharmony_ci * transfer completes 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci if (spi_imx->devtype_data->disable) 161862306a36Sopenharmony_ci spi_imx->devtype_data->disable(spi_imx); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci return ret; 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cistatic int spi_imx_transfer_one(struct spi_controller *controller, 162462306a36Sopenharmony_ci struct spi_device *spi, 162562306a36Sopenharmony_ci struct spi_transfer *transfer) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); 162862306a36Sopenharmony_ci unsigned long hz_per_byte, byte_limit; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci spi_imx_setupxfer(spi, transfer); 163162306a36Sopenharmony_ci transfer->effective_speed_hz = spi_imx->spi_bus_clk; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* flush rxfifo before transfer */ 163462306a36Sopenharmony_ci while (spi_imx->devtype_data->rx_available(spi_imx)) 163562306a36Sopenharmony_ci readl(spi_imx->base + MXC_CSPIRXDATA); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (spi_imx->target_mode) 163862306a36Sopenharmony_ci return spi_imx_pio_transfer_target(spi, transfer); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci /* 164162306a36Sopenharmony_ci * If we decided in spi_imx_can_dma() that we want to do a DMA 164262306a36Sopenharmony_ci * transfer, the SPI transfer has already been mapped, so we 164362306a36Sopenharmony_ci * have to do the DMA transfer here. 164462306a36Sopenharmony_ci */ 164562306a36Sopenharmony_ci if (spi_imx->usedma) 164662306a36Sopenharmony_ci return spi_imx_dma_transfer(spi_imx, transfer); 164762306a36Sopenharmony_ci /* 164862306a36Sopenharmony_ci * Calculate the estimated time in us the transfer runs. Find 164962306a36Sopenharmony_ci * the number of Hz per byte per polling limit. 165062306a36Sopenharmony_ci */ 165162306a36Sopenharmony_ci hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0; 165262306a36Sopenharmony_ci byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* run in polling mode for short transfers */ 165562306a36Sopenharmony_ci if (transfer->len < byte_limit) 165662306a36Sopenharmony_ci return spi_imx_poll_transfer(spi, transfer); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci return spi_imx_pio_transfer(spi, transfer); 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic int spi_imx_setup(struct spi_device *spi) 166262306a36Sopenharmony_ci{ 166362306a36Sopenharmony_ci dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, 166462306a36Sopenharmony_ci spi->mode, spi->bits_per_word, spi->max_speed_hz); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci return 0; 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cistatic void spi_imx_cleanup(struct spi_device *spi) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_cistatic int 167462306a36Sopenharmony_cispi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); 167762306a36Sopenharmony_ci int ret; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(spi_imx->dev); 168062306a36Sopenharmony_ci if (ret < 0) { 168162306a36Sopenharmony_ci dev_err(spi_imx->dev, "failed to enable clock\n"); 168262306a36Sopenharmony_ci return ret; 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci ret = spi_imx->devtype_data->prepare_message(spi_imx, msg); 168662306a36Sopenharmony_ci if (ret) { 168762306a36Sopenharmony_ci pm_runtime_mark_last_busy(spi_imx->dev); 168862306a36Sopenharmony_ci pm_runtime_put_autosuspend(spi_imx->dev); 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci return ret; 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic int 169562306a36Sopenharmony_cispi_imx_unprepare_message(struct spi_controller *controller, struct spi_message *msg) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci pm_runtime_mark_last_busy(spi_imx->dev); 170062306a36Sopenharmony_ci pm_runtime_put_autosuspend(spi_imx->dev); 170162306a36Sopenharmony_ci return 0; 170262306a36Sopenharmony_ci} 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_cistatic int spi_imx_target_abort(struct spi_controller *controller) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci spi_imx->target_aborted = true; 170962306a36Sopenharmony_ci complete(&spi_imx->xfer_done); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci return 0; 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_cistatic int spi_imx_probe(struct platform_device *pdev) 171562306a36Sopenharmony_ci{ 171662306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 171762306a36Sopenharmony_ci struct spi_controller *controller; 171862306a36Sopenharmony_ci struct spi_imx_data *spi_imx; 171962306a36Sopenharmony_ci struct resource *res; 172062306a36Sopenharmony_ci int ret, irq, spi_drctl; 172162306a36Sopenharmony_ci const struct spi_imx_devtype_data *devtype_data = 172262306a36Sopenharmony_ci of_device_get_match_data(&pdev->dev); 172362306a36Sopenharmony_ci bool target_mode; 172462306a36Sopenharmony_ci u32 val; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci target_mode = devtype_data->has_targetmode && 172762306a36Sopenharmony_ci of_property_read_bool(np, "spi-slave"); 172862306a36Sopenharmony_ci if (target_mode) 172962306a36Sopenharmony_ci controller = spi_alloc_target(&pdev->dev, 173062306a36Sopenharmony_ci sizeof(struct spi_imx_data)); 173162306a36Sopenharmony_ci else 173262306a36Sopenharmony_ci controller = spi_alloc_host(&pdev->dev, 173362306a36Sopenharmony_ci sizeof(struct spi_imx_data)); 173462306a36Sopenharmony_ci if (!controller) 173562306a36Sopenharmony_ci return -ENOMEM; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl); 173862306a36Sopenharmony_ci if ((ret < 0) || (spi_drctl >= 0x3)) { 173962306a36Sopenharmony_ci /* '11' is reserved */ 174062306a36Sopenharmony_ci spi_drctl = 0; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci platform_set_drvdata(pdev, controller); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); 174662306a36Sopenharmony_ci controller->bus_num = np ? -1 : pdev->id; 174762306a36Sopenharmony_ci controller->use_gpio_descriptors = true; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci spi_imx = spi_controller_get_devdata(controller); 175062306a36Sopenharmony_ci spi_imx->controller = controller; 175162306a36Sopenharmony_ci spi_imx->dev = &pdev->dev; 175262306a36Sopenharmony_ci spi_imx->target_mode = target_mode; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci spi_imx->devtype_data = devtype_data; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci /* 175762306a36Sopenharmony_ci * Get number of chip selects from device properties. This can be 175862306a36Sopenharmony_ci * coming from device tree or boardfiles, if it is not defined, 175962306a36Sopenharmony_ci * a default value of 3 chip selects will be used, as all the legacy 176062306a36Sopenharmony_ci * board files have <= 3 chip selects. 176162306a36Sopenharmony_ci */ 176262306a36Sopenharmony_ci if (!device_property_read_u32(&pdev->dev, "num-cs", &val)) 176362306a36Sopenharmony_ci controller->num_chipselect = val; 176462306a36Sopenharmony_ci else 176562306a36Sopenharmony_ci controller->num_chipselect = 3; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci controller->transfer_one = spi_imx_transfer_one; 176862306a36Sopenharmony_ci controller->setup = spi_imx_setup; 176962306a36Sopenharmony_ci controller->cleanup = spi_imx_cleanup; 177062306a36Sopenharmony_ci controller->prepare_message = spi_imx_prepare_message; 177162306a36Sopenharmony_ci controller->unprepare_message = spi_imx_unprepare_message; 177262306a36Sopenharmony_ci controller->target_abort = spi_imx_target_abort; 177362306a36Sopenharmony_ci controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS | 177462306a36Sopenharmony_ci SPI_MOSI_IDLE_LOW; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || 177762306a36Sopenharmony_ci is_imx53_ecspi(spi_imx)) 177862306a36Sopenharmony_ci controller->mode_bits |= SPI_LOOP | SPI_READY; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) 178162306a36Sopenharmony_ci controller->mode_bits |= SPI_RX_CPHA_FLIP; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci if (is_imx51_ecspi(spi_imx) && 178462306a36Sopenharmony_ci device_property_read_u32(&pdev->dev, "cs-gpios", NULL)) 178562306a36Sopenharmony_ci /* 178662306a36Sopenharmony_ci * When using HW-CS implementing SPI_CS_WORD can be done by just 178762306a36Sopenharmony_ci * setting the burst length to the word size. This is 178862306a36Sopenharmony_ci * considerably faster than manually controlling the CS. 178962306a36Sopenharmony_ci */ 179062306a36Sopenharmony_ci controller->mode_bits |= SPI_CS_WORD; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) { 179362306a36Sopenharmony_ci controller->max_native_cs = 4; 179462306a36Sopenharmony_ci controller->flags |= SPI_CONTROLLER_GPIO_SS; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci spi_imx->spi_drctl = spi_drctl; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci init_completion(&spi_imx->xfer_done); 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci spi_imx->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 180262306a36Sopenharmony_ci if (IS_ERR(spi_imx->base)) { 180362306a36Sopenharmony_ci ret = PTR_ERR(spi_imx->base); 180462306a36Sopenharmony_ci goto out_controller_put; 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci spi_imx->base_phys = res->start; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 180962306a36Sopenharmony_ci if (irq < 0) { 181062306a36Sopenharmony_ci ret = irq; 181162306a36Sopenharmony_ci goto out_controller_put; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, spi_imx_isr, 0, 181562306a36Sopenharmony_ci dev_name(&pdev->dev), spi_imx); 181662306a36Sopenharmony_ci if (ret) { 181762306a36Sopenharmony_ci dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret); 181862306a36Sopenharmony_ci goto out_controller_put; 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 182262306a36Sopenharmony_ci if (IS_ERR(spi_imx->clk_ipg)) { 182362306a36Sopenharmony_ci ret = PTR_ERR(spi_imx->clk_ipg); 182462306a36Sopenharmony_ci goto out_controller_put; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci spi_imx->clk_per = devm_clk_get(&pdev->dev, "per"); 182862306a36Sopenharmony_ci if (IS_ERR(spi_imx->clk_per)) { 182962306a36Sopenharmony_ci ret = PTR_ERR(spi_imx->clk_per); 183062306a36Sopenharmony_ci goto out_controller_put; 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci ret = clk_prepare_enable(spi_imx->clk_per); 183462306a36Sopenharmony_ci if (ret) 183562306a36Sopenharmony_ci goto out_controller_put; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci ret = clk_prepare_enable(spi_imx->clk_ipg); 183862306a36Sopenharmony_ci if (ret) 183962306a36Sopenharmony_ci goto out_put_per; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(spi_imx->dev, MXC_RPM_TIMEOUT); 184262306a36Sopenharmony_ci pm_runtime_use_autosuspend(spi_imx->dev); 184362306a36Sopenharmony_ci pm_runtime_get_noresume(spi_imx->dev); 184462306a36Sopenharmony_ci pm_runtime_set_active(spi_imx->dev); 184562306a36Sopenharmony_ci pm_runtime_enable(spi_imx->dev); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); 184862306a36Sopenharmony_ci /* 184962306a36Sopenharmony_ci * Only validated on i.mx35 and i.mx6 now, can remove the constraint 185062306a36Sopenharmony_ci * if validated on other chips. 185162306a36Sopenharmony_ci */ 185262306a36Sopenharmony_ci if (spi_imx->devtype_data->has_dmamode) { 185362306a36Sopenharmony_ci ret = spi_imx_sdma_init(&pdev->dev, spi_imx, controller); 185462306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 185562306a36Sopenharmony_ci goto out_runtime_pm_put; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (ret < 0) 185862306a36Sopenharmony_ci dev_dbg(&pdev->dev, "dma setup error %d, use pio\n", 185962306a36Sopenharmony_ci ret); 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci spi_imx->devtype_data->reset(spi_imx); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci spi_imx->devtype_data->intctrl(spi_imx, 0); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci controller->dev.of_node = pdev->dev.of_node; 186762306a36Sopenharmony_ci ret = spi_register_controller(controller); 186862306a36Sopenharmony_ci if (ret) { 186962306a36Sopenharmony_ci dev_err_probe(&pdev->dev, ret, "register controller failed\n"); 187062306a36Sopenharmony_ci goto out_register_controller; 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci pm_runtime_mark_last_busy(spi_imx->dev); 187462306a36Sopenharmony_ci pm_runtime_put_autosuspend(spi_imx->dev); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci return ret; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ciout_register_controller: 187962306a36Sopenharmony_ci if (spi_imx->devtype_data->has_dmamode) 188062306a36Sopenharmony_ci spi_imx_sdma_exit(spi_imx); 188162306a36Sopenharmony_ciout_runtime_pm_put: 188262306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(spi_imx->dev); 188362306a36Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 188462306a36Sopenharmony_ci pm_runtime_disable(spi_imx->dev); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci clk_disable_unprepare(spi_imx->clk_ipg); 188762306a36Sopenharmony_ciout_put_per: 188862306a36Sopenharmony_ci clk_disable_unprepare(spi_imx->clk_per); 188962306a36Sopenharmony_ciout_controller_put: 189062306a36Sopenharmony_ci spi_controller_put(controller); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return ret; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic void spi_imx_remove(struct platform_device *pdev) 189662306a36Sopenharmony_ci{ 189762306a36Sopenharmony_ci struct spi_controller *controller = platform_get_drvdata(pdev); 189862306a36Sopenharmony_ci struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller); 189962306a36Sopenharmony_ci int ret; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci spi_unregister_controller(controller); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci ret = pm_runtime_get_sync(spi_imx->dev); 190462306a36Sopenharmony_ci if (ret >= 0) 190562306a36Sopenharmony_ci writel(0, spi_imx->base + MXC_CSPICTRL); 190662306a36Sopenharmony_ci else 190762306a36Sopenharmony_ci dev_warn(spi_imx->dev, "failed to enable clock, skip hw disable\n"); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(spi_imx->dev); 191062306a36Sopenharmony_ci pm_runtime_put_sync(spi_imx->dev); 191162306a36Sopenharmony_ci pm_runtime_disable(spi_imx->dev); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci spi_imx_sdma_exit(spi_imx); 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic int __maybe_unused spi_imx_runtime_resume(struct device *dev) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci struct spi_controller *controller = dev_get_drvdata(dev); 191962306a36Sopenharmony_ci struct spi_imx_data *spi_imx; 192062306a36Sopenharmony_ci int ret; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci spi_imx = spi_controller_get_devdata(controller); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci ret = clk_prepare_enable(spi_imx->clk_per); 192562306a36Sopenharmony_ci if (ret) 192662306a36Sopenharmony_ci return ret; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci ret = clk_prepare_enable(spi_imx->clk_ipg); 192962306a36Sopenharmony_ci if (ret) { 193062306a36Sopenharmony_ci clk_disable_unprepare(spi_imx->clk_per); 193162306a36Sopenharmony_ci return ret; 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci return 0; 193562306a36Sopenharmony_ci} 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_cistatic int __maybe_unused spi_imx_runtime_suspend(struct device *dev) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci struct spi_controller *controller = dev_get_drvdata(dev); 194062306a36Sopenharmony_ci struct spi_imx_data *spi_imx; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci spi_imx = spi_controller_get_devdata(controller); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci clk_disable_unprepare(spi_imx->clk_per); 194562306a36Sopenharmony_ci clk_disable_unprepare(spi_imx->clk_ipg); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci return 0; 194862306a36Sopenharmony_ci} 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_cistatic int __maybe_unused spi_imx_suspend(struct device *dev) 195162306a36Sopenharmony_ci{ 195262306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 195362306a36Sopenharmony_ci return 0; 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic int __maybe_unused spi_imx_resume(struct device *dev) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 195962306a36Sopenharmony_ci return 0; 196062306a36Sopenharmony_ci} 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_cistatic const struct dev_pm_ops imx_spi_pm = { 196362306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend, 196462306a36Sopenharmony_ci spi_imx_runtime_resume, NULL) 196562306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume) 196662306a36Sopenharmony_ci}; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_cistatic struct platform_driver spi_imx_driver = { 196962306a36Sopenharmony_ci .driver = { 197062306a36Sopenharmony_ci .name = DRIVER_NAME, 197162306a36Sopenharmony_ci .of_match_table = spi_imx_dt_ids, 197262306a36Sopenharmony_ci .pm = &imx_spi_pm, 197362306a36Sopenharmony_ci }, 197462306a36Sopenharmony_ci .probe = spi_imx_probe, 197562306a36Sopenharmony_ci .remove_new = spi_imx_remove, 197662306a36Sopenharmony_ci}; 197762306a36Sopenharmony_cimodule_platform_driver(spi_imx_driver); 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ciMODULE_DESCRIPTION("i.MX SPI Controller driver"); 198062306a36Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer, Pengutronix"); 198162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 198262306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME); 1983