162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// spi-uniphier.c - Socionext UniPhier SPI controller driver 362306a36Sopenharmony_ci// Copyright 2012 Panasonic Corporation 462306a36Sopenharmony_ci// Copyright 2016-2018 Socionext Inc. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/bitfield.h> 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/dmaengine.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/spi/spi.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/unaligned.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define SSI_TIMEOUT_MS 2000 2162306a36Sopenharmony_ci#define SSI_POLL_TIMEOUT_US 200 2262306a36Sopenharmony_ci#define SSI_MAX_CLK_DIVIDER 254 2362306a36Sopenharmony_ci#define SSI_MIN_CLK_DIVIDER 4 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct uniphier_spi_priv { 2662306a36Sopenharmony_ci void __iomem *base; 2762306a36Sopenharmony_ci dma_addr_t base_dma_addr; 2862306a36Sopenharmony_ci struct clk *clk; 2962306a36Sopenharmony_ci struct spi_master *master; 3062306a36Sopenharmony_ci struct completion xfer_done; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci int error; 3362306a36Sopenharmony_ci unsigned int tx_bytes; 3462306a36Sopenharmony_ci unsigned int rx_bytes; 3562306a36Sopenharmony_ci const u8 *tx_buf; 3662306a36Sopenharmony_ci u8 *rx_buf; 3762306a36Sopenharmony_ci atomic_t dma_busy; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci bool is_save_param; 4062306a36Sopenharmony_ci u8 bits_per_word; 4162306a36Sopenharmony_ci u16 mode; 4262306a36Sopenharmony_ci u32 speed_hz; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SSI_CTL 0x00 4662306a36Sopenharmony_ci#define SSI_CTL_EN BIT(0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define SSI_CKS 0x04 4962306a36Sopenharmony_ci#define SSI_CKS_CKRAT_MASK GENMASK(7, 0) 5062306a36Sopenharmony_ci#define SSI_CKS_CKPHS BIT(14) 5162306a36Sopenharmony_ci#define SSI_CKS_CKINIT BIT(13) 5262306a36Sopenharmony_ci#define SSI_CKS_CKDLY BIT(12) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define SSI_TXWDS 0x08 5562306a36Sopenharmony_ci#define SSI_TXWDS_WDLEN_MASK GENMASK(13, 8) 5662306a36Sopenharmony_ci#define SSI_TXWDS_TDTF_MASK GENMASK(7, 6) 5762306a36Sopenharmony_ci#define SSI_TXWDS_DTLEN_MASK GENMASK(5, 0) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define SSI_RXWDS 0x0c 6062306a36Sopenharmony_ci#define SSI_RXWDS_DTLEN_MASK GENMASK(5, 0) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define SSI_FPS 0x10 6362306a36Sopenharmony_ci#define SSI_FPS_FSPOL BIT(15) 6462306a36Sopenharmony_ci#define SSI_FPS_FSTRT BIT(14) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define SSI_SR 0x14 6762306a36Sopenharmony_ci#define SSI_SR_BUSY BIT(7) 6862306a36Sopenharmony_ci#define SSI_SR_RNE BIT(0) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define SSI_IE 0x18 7162306a36Sopenharmony_ci#define SSI_IE_TCIE BIT(4) 7262306a36Sopenharmony_ci#define SSI_IE_RCIE BIT(3) 7362306a36Sopenharmony_ci#define SSI_IE_TXRE BIT(2) 7462306a36Sopenharmony_ci#define SSI_IE_RXRE BIT(1) 7562306a36Sopenharmony_ci#define SSI_IE_RORIE BIT(0) 7662306a36Sopenharmony_ci#define SSI_IE_ALL_MASK GENMASK(4, 0) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define SSI_IS 0x1c 7962306a36Sopenharmony_ci#define SSI_IS_RXRS BIT(9) 8062306a36Sopenharmony_ci#define SSI_IS_RCID BIT(3) 8162306a36Sopenharmony_ci#define SSI_IS_RORID BIT(0) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define SSI_IC 0x1c 8462306a36Sopenharmony_ci#define SSI_IC_TCIC BIT(4) 8562306a36Sopenharmony_ci#define SSI_IC_RCIC BIT(3) 8662306a36Sopenharmony_ci#define SSI_IC_RORIC BIT(0) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define SSI_FC 0x20 8962306a36Sopenharmony_ci#define SSI_FC_TXFFL BIT(12) 9062306a36Sopenharmony_ci#define SSI_FC_TXFTH_MASK GENMASK(11, 8) 9162306a36Sopenharmony_ci#define SSI_FC_RXFFL BIT(4) 9262306a36Sopenharmony_ci#define SSI_FC_RXFTH_MASK GENMASK(3, 0) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define SSI_TXDR 0x24 9562306a36Sopenharmony_ci#define SSI_RXDR 0x24 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define SSI_FIFO_DEPTH 8U 9862306a36Sopenharmony_ci#define SSI_FIFO_BURST_NUM 1 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define SSI_DMA_RX_BUSY BIT(1) 10162306a36Sopenharmony_ci#define SSI_DMA_TX_BUSY BIT(0) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline unsigned int bytes_per_word(unsigned int bits) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return bits <= 8 ? 1 : (bits <= 16 ? 2 : 4); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic inline void uniphier_spi_irq_enable(struct uniphier_spi_priv *priv, 10962306a36Sopenharmony_ci u32 mask) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci u32 val; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci val = readl(priv->base + SSI_IE); 11462306a36Sopenharmony_ci val |= mask; 11562306a36Sopenharmony_ci writel(val, priv->base + SSI_IE); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline void uniphier_spi_irq_disable(struct uniphier_spi_priv *priv, 11962306a36Sopenharmony_ci u32 mask) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci u32 val; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci val = readl(priv->base + SSI_IE); 12462306a36Sopenharmony_ci val &= ~mask; 12562306a36Sopenharmony_ci writel(val, priv->base + SSI_IE); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void uniphier_spi_set_mode(struct spi_device *spi) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); 13162306a36Sopenharmony_ci u32 val1, val2; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * clock setting 13562306a36Sopenharmony_ci * CKPHS capture timing. 0:rising edge, 1:falling edge 13662306a36Sopenharmony_ci * CKINIT clock initial level. 0:low, 1:high 13762306a36Sopenharmony_ci * CKDLY clock delay. 0:no delay, 1:delay depending on FSTRT 13862306a36Sopenharmony_ci * (FSTRT=0: 1 clock, FSTRT=1: 0.5 clock) 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * frame setting 14162306a36Sopenharmony_ci * FSPOL frame signal porarity. 0: low, 1: high 14262306a36Sopenharmony_ci * FSTRT start frame timing 14362306a36Sopenharmony_ci * 0: rising edge of clock, 1: falling edge of clock 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci switch (spi->mode & SPI_MODE_X_MASK) { 14662306a36Sopenharmony_ci case SPI_MODE_0: 14762306a36Sopenharmony_ci /* CKPHS=1, CKINIT=0, CKDLY=1, FSTRT=0 */ 14862306a36Sopenharmony_ci val1 = SSI_CKS_CKPHS | SSI_CKS_CKDLY; 14962306a36Sopenharmony_ci val2 = 0; 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case SPI_MODE_1: 15262306a36Sopenharmony_ci /* CKPHS=0, CKINIT=0, CKDLY=0, FSTRT=1 */ 15362306a36Sopenharmony_ci val1 = 0; 15462306a36Sopenharmony_ci val2 = SSI_FPS_FSTRT; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci case SPI_MODE_2: 15762306a36Sopenharmony_ci /* CKPHS=0, CKINIT=1, CKDLY=1, FSTRT=1 */ 15862306a36Sopenharmony_ci val1 = SSI_CKS_CKINIT | SSI_CKS_CKDLY; 15962306a36Sopenharmony_ci val2 = SSI_FPS_FSTRT; 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case SPI_MODE_3: 16262306a36Sopenharmony_ci /* CKPHS=1, CKINIT=1, CKDLY=0, FSTRT=0 */ 16362306a36Sopenharmony_ci val1 = SSI_CKS_CKPHS | SSI_CKS_CKINIT; 16462306a36Sopenharmony_ci val2 = 0; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (!(spi->mode & SPI_CS_HIGH)) 16962306a36Sopenharmony_ci val2 |= SSI_FPS_FSPOL; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci writel(val1, priv->base + SSI_CKS); 17262306a36Sopenharmony_ci writel(val2, priv->base + SSI_FPS); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci val1 = 0; 17562306a36Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) 17662306a36Sopenharmony_ci val1 |= FIELD_PREP(SSI_TXWDS_TDTF_MASK, 1); 17762306a36Sopenharmony_ci writel(val1, priv->base + SSI_TXWDS); 17862306a36Sopenharmony_ci writel(val1, priv->base + SSI_RXWDS); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void uniphier_spi_set_transfer_size(struct spi_device *spi, int size) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); 18462306a36Sopenharmony_ci u32 val; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci val = readl(priv->base + SSI_TXWDS); 18762306a36Sopenharmony_ci val &= ~(SSI_TXWDS_WDLEN_MASK | SSI_TXWDS_DTLEN_MASK); 18862306a36Sopenharmony_ci val |= FIELD_PREP(SSI_TXWDS_WDLEN_MASK, size); 18962306a36Sopenharmony_ci val |= FIELD_PREP(SSI_TXWDS_DTLEN_MASK, size); 19062306a36Sopenharmony_ci writel(val, priv->base + SSI_TXWDS); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci val = readl(priv->base + SSI_RXWDS); 19362306a36Sopenharmony_ci val &= ~SSI_RXWDS_DTLEN_MASK; 19462306a36Sopenharmony_ci val |= FIELD_PREP(SSI_RXWDS_DTLEN_MASK, size); 19562306a36Sopenharmony_ci writel(val, priv->base + SSI_RXWDS); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void uniphier_spi_set_baudrate(struct spi_device *spi, 19962306a36Sopenharmony_ci unsigned int speed) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); 20262306a36Sopenharmony_ci u32 val, ckdiv; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * the supported rates are even numbers from 4 to 254. (4,6,8...254) 20662306a36Sopenharmony_ci * round up as we look for equal or less speed 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci ckdiv = DIV_ROUND_UP(clk_get_rate(priv->clk), speed); 20962306a36Sopenharmony_ci ckdiv = round_up(ckdiv, 2); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci val = readl(priv->base + SSI_CKS); 21262306a36Sopenharmony_ci val &= ~SSI_CKS_CKRAT_MASK; 21362306a36Sopenharmony_ci val |= ckdiv & SSI_CKS_CKRAT_MASK; 21462306a36Sopenharmony_ci writel(val, priv->base + SSI_CKS); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void uniphier_spi_setup_transfer(struct spi_device *spi, 21862306a36Sopenharmony_ci struct spi_transfer *t) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); 22162306a36Sopenharmony_ci u32 val; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci priv->error = 0; 22462306a36Sopenharmony_ci priv->tx_buf = t->tx_buf; 22562306a36Sopenharmony_ci priv->rx_buf = t->rx_buf; 22662306a36Sopenharmony_ci priv->tx_bytes = priv->rx_bytes = t->len; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!priv->is_save_param || priv->mode != spi->mode) { 22962306a36Sopenharmony_ci uniphier_spi_set_mode(spi); 23062306a36Sopenharmony_ci priv->mode = spi->mode; 23162306a36Sopenharmony_ci priv->is_save_param = false; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) { 23562306a36Sopenharmony_ci uniphier_spi_set_transfer_size(spi, t->bits_per_word); 23662306a36Sopenharmony_ci priv->bits_per_word = t->bits_per_word; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!priv->is_save_param || priv->speed_hz != t->speed_hz) { 24062306a36Sopenharmony_ci uniphier_spi_set_baudrate(spi, t->speed_hz); 24162306a36Sopenharmony_ci priv->speed_hz = t->speed_hz; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci priv->is_save_param = true; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* reset FIFOs */ 24762306a36Sopenharmony_ci val = SSI_FC_TXFFL | SSI_FC_RXFFL; 24862306a36Sopenharmony_ci writel(val, priv->base + SSI_FC); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void uniphier_spi_send(struct uniphier_spi_priv *priv) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int wsize; 25462306a36Sopenharmony_ci u32 val = 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes); 25762306a36Sopenharmony_ci priv->tx_bytes -= wsize; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (priv->tx_buf) { 26062306a36Sopenharmony_ci switch (wsize) { 26162306a36Sopenharmony_ci case 1: 26262306a36Sopenharmony_ci val = *priv->tx_buf; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case 2: 26562306a36Sopenharmony_ci val = get_unaligned_le16(priv->tx_buf); 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci case 4: 26862306a36Sopenharmony_ci val = get_unaligned_le32(priv->tx_buf); 26962306a36Sopenharmony_ci break; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci priv->tx_buf += wsize; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci writel(val, priv->base + SSI_TXDR); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void uniphier_spi_recv(struct uniphier_spi_priv *priv) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int rsize; 28162306a36Sopenharmony_ci u32 val; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes); 28462306a36Sopenharmony_ci priv->rx_bytes -= rsize; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci val = readl(priv->base + SSI_RXDR); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (priv->rx_buf) { 28962306a36Sopenharmony_ci switch (rsize) { 29062306a36Sopenharmony_ci case 1: 29162306a36Sopenharmony_ci *priv->rx_buf = val; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci case 2: 29462306a36Sopenharmony_ci put_unaligned_le16(val, priv->rx_buf); 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case 4: 29762306a36Sopenharmony_ci put_unaligned_le32(val, priv->rx_buf); 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci priv->rx_buf += rsize; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic void uniphier_spi_set_fifo_threshold(struct uniphier_spi_priv *priv, 30662306a36Sopenharmony_ci unsigned int threshold) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci u32 val; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci val = readl(priv->base + SSI_FC); 31162306a36Sopenharmony_ci val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); 31262306a36Sopenharmony_ci val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold); 31362306a36Sopenharmony_ci val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold); 31462306a36Sopenharmony_ci writel(val, priv->base + SSI_FC); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unsigned int fifo_threshold, fill_words; 32062306a36Sopenharmony_ci unsigned int bpw = bytes_per_word(priv->bits_per_word); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bpw); 32362306a36Sopenharmony_ci fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci uniphier_spi_set_fifo_threshold(priv, fifo_threshold); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci fill_words = fifo_threshold - 32862306a36Sopenharmony_ci DIV_ROUND_UP(priv->rx_bytes - priv->tx_bytes, bpw); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci while (fill_words--) 33162306a36Sopenharmony_ci uniphier_spi_send(priv); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void uniphier_spi_set_cs(struct spi_device *spi, bool enable) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); 33762306a36Sopenharmony_ci u32 val; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci val = readl(priv->base + SSI_FPS); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (enable) 34262306a36Sopenharmony_ci val |= SSI_FPS_FSPOL; 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci val &= ~SSI_FPS_FSPOL; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci writel(val, priv->base + SSI_FPS); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic bool uniphier_spi_can_dma(struct spi_master *master, 35062306a36Sopenharmony_ci struct spi_device *spi, 35162306a36Sopenharmony_ci struct spi_transfer *t) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 35462306a36Sopenharmony_ci unsigned int bpw = bytes_per_word(priv->bits_per_word); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if ((!master->dma_tx && !master->dma_rx) 35762306a36Sopenharmony_ci || (!master->dma_tx && t->tx_buf) 35862306a36Sopenharmony_ci || (!master->dma_rx && t->rx_buf)) 35962306a36Sopenharmony_ci return false; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void uniphier_spi_dma_rxcb(void *data) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct spi_master *master = data; 36762306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 36862306a36Sopenharmony_ci int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci uniphier_spi_irq_disable(priv, SSI_IE_RXRE); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (!(state & SSI_DMA_TX_BUSY)) 37362306a36Sopenharmony_ci spi_finalize_current_transfer(master); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void uniphier_spi_dma_txcb(void *data) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct spi_master *master = data; 37962306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 38062306a36Sopenharmony_ci int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci uniphier_spi_irq_disable(priv, SSI_IE_TXRE); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (!(state & SSI_DMA_RX_BUSY)) 38562306a36Sopenharmony_ci spi_finalize_current_transfer(master); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int uniphier_spi_transfer_one_dma(struct spi_master *master, 38962306a36Sopenharmony_ci struct spi_device *spi, 39062306a36Sopenharmony_ci struct spi_transfer *t) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 39362306a36Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; 39462306a36Sopenharmony_ci int buswidth; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci atomic_set(&priv->dma_busy, 0); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci uniphier_spi_set_fifo_threshold(priv, SSI_FIFO_BURST_NUM); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (priv->bits_per_word <= 8) 40162306a36Sopenharmony_ci buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; 40262306a36Sopenharmony_ci else if (priv->bits_per_word <= 16) 40362306a36Sopenharmony_ci buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; 40462306a36Sopenharmony_ci else 40562306a36Sopenharmony_ci buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (priv->rx_buf) { 40862306a36Sopenharmony_ci struct dma_slave_config rxconf = { 40962306a36Sopenharmony_ci .direction = DMA_DEV_TO_MEM, 41062306a36Sopenharmony_ci .src_addr = priv->base_dma_addr + SSI_RXDR, 41162306a36Sopenharmony_ci .src_addr_width = buswidth, 41262306a36Sopenharmony_ci .src_maxburst = SSI_FIFO_BURST_NUM, 41362306a36Sopenharmony_ci }; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci dmaengine_slave_config(master->dma_rx, &rxconf); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg( 41862306a36Sopenharmony_ci master->dma_rx, 41962306a36Sopenharmony_ci t->rx_sg.sgl, t->rx_sg.nents, 42062306a36Sopenharmony_ci DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 42162306a36Sopenharmony_ci if (!rxdesc) 42262306a36Sopenharmony_ci goto out_err_prep; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci rxdesc->callback = uniphier_spi_dma_rxcb; 42562306a36Sopenharmony_ci rxdesc->callback_param = master; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci uniphier_spi_irq_enable(priv, SSI_IE_RXRE); 42862306a36Sopenharmony_ci atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci dmaengine_submit(rxdesc); 43162306a36Sopenharmony_ci dma_async_issue_pending(master->dma_rx); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (priv->tx_buf) { 43562306a36Sopenharmony_ci struct dma_slave_config txconf = { 43662306a36Sopenharmony_ci .direction = DMA_MEM_TO_DEV, 43762306a36Sopenharmony_ci .dst_addr = priv->base_dma_addr + SSI_TXDR, 43862306a36Sopenharmony_ci .dst_addr_width = buswidth, 43962306a36Sopenharmony_ci .dst_maxburst = SSI_FIFO_BURST_NUM, 44062306a36Sopenharmony_ci }; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci dmaengine_slave_config(master->dma_tx, &txconf); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci txdesc = dmaengine_prep_slave_sg( 44562306a36Sopenharmony_ci master->dma_tx, 44662306a36Sopenharmony_ci t->tx_sg.sgl, t->tx_sg.nents, 44762306a36Sopenharmony_ci DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 44862306a36Sopenharmony_ci if (!txdesc) 44962306a36Sopenharmony_ci goto out_err_prep; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci txdesc->callback = uniphier_spi_dma_txcb; 45262306a36Sopenharmony_ci txdesc->callback_param = master; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci uniphier_spi_irq_enable(priv, SSI_IE_TXRE); 45562306a36Sopenharmony_ci atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci dmaengine_submit(txdesc); 45862306a36Sopenharmony_ci dma_async_issue_pending(master->dma_tx); 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* signal that we need to wait for completion */ 46262306a36Sopenharmony_ci return (priv->tx_buf || priv->rx_buf); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ciout_err_prep: 46562306a36Sopenharmony_ci if (rxdesc) 46662306a36Sopenharmony_ci dmaengine_terminate_sync(master->dma_rx); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return -EINVAL; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic int uniphier_spi_transfer_one_irq(struct spi_master *master, 47262306a36Sopenharmony_ci struct spi_device *spi, 47362306a36Sopenharmony_ci struct spi_transfer *t) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 47662306a36Sopenharmony_ci struct device *dev = master->dev.parent; 47762306a36Sopenharmony_ci unsigned long time_left; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci reinit_completion(&priv->xfer_done); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci uniphier_spi_fill_tx_fifo(priv); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci uniphier_spi_irq_enable(priv, SSI_IE_RCIE | SSI_IE_RORIE); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&priv->xfer_done, 48662306a36Sopenharmony_ci msecs_to_jiffies(SSI_TIMEOUT_MS)); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci uniphier_spi_irq_disable(priv, SSI_IE_RCIE | SSI_IE_RORIE); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (!time_left) { 49162306a36Sopenharmony_ci dev_err(dev, "transfer timeout.\n"); 49262306a36Sopenharmony_ci return -ETIMEDOUT; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return priv->error; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int uniphier_spi_transfer_one_poll(struct spi_master *master, 49962306a36Sopenharmony_ci struct spi_device *spi, 50062306a36Sopenharmony_ci struct spi_transfer *t) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 50362306a36Sopenharmony_ci int loop = SSI_POLL_TIMEOUT_US * 10; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci while (priv->tx_bytes) { 50662306a36Sopenharmony_ci uniphier_spi_fill_tx_fifo(priv); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci while ((priv->rx_bytes - priv->tx_bytes) > 0) { 50962306a36Sopenharmony_ci while (!(readl(priv->base + SSI_SR) & SSI_SR_RNE) 51062306a36Sopenharmony_ci && loop--) 51162306a36Sopenharmony_ci ndelay(100); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (loop == -1) 51462306a36Sopenharmony_ci goto irq_transfer; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci uniphier_spi_recv(priv); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ciirq_transfer: 52362306a36Sopenharmony_ci return uniphier_spi_transfer_one_irq(master, spi, t); 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int uniphier_spi_transfer_one(struct spi_master *master, 52762306a36Sopenharmony_ci struct spi_device *spi, 52862306a36Sopenharmony_ci struct spi_transfer *t) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 53162306a36Sopenharmony_ci unsigned long threshold; 53262306a36Sopenharmony_ci bool use_dma; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Terminate and return success for 0 byte length transfer */ 53562306a36Sopenharmony_ci if (!t->len) 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci uniphier_spi_setup_transfer(spi, t); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci use_dma = master->can_dma ? master->can_dma(master, spi, t) : false; 54162306a36Sopenharmony_ci if (use_dma) 54262306a36Sopenharmony_ci return uniphier_spi_transfer_one_dma(master, spi, t); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* 54562306a36Sopenharmony_ci * If the transfer operation will take longer than 54662306a36Sopenharmony_ci * SSI_POLL_TIMEOUT_US, it should use irq. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz, 54962306a36Sopenharmony_ci USEC_PER_SEC * BITS_PER_BYTE); 55062306a36Sopenharmony_ci if (t->len > threshold) 55162306a36Sopenharmony_ci return uniphier_spi_transfer_one_irq(master, spi, t); 55262306a36Sopenharmony_ci else 55362306a36Sopenharmony_ci return uniphier_spi_transfer_one_poll(master, spi, t); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int uniphier_spi_prepare_transfer_hardware(struct spi_master *master) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci writel(SSI_CTL_EN, priv->base + SSI_CTL); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci writel(0, priv->base + SSI_CTL); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void uniphier_spi_handle_err(struct spi_master *master, 57562306a36Sopenharmony_ci struct spi_message *msg) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 57862306a36Sopenharmony_ci u32 val; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* stop running spi transfer */ 58162306a36Sopenharmony_ci writel(0, priv->base + SSI_CTL); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* reset FIFOs */ 58462306a36Sopenharmony_ci val = SSI_FC_TXFFL | SSI_FC_RXFFL; 58562306a36Sopenharmony_ci writel(val, priv->base + SSI_FC); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) { 59062306a36Sopenharmony_ci dmaengine_terminate_async(master->dma_tx); 59162306a36Sopenharmony_ci atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) { 59562306a36Sopenharmony_ci dmaengine_terminate_async(master->dma_rx); 59662306a36Sopenharmony_ci atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic irqreturn_t uniphier_spi_handler(int irq, void *dev_id) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct uniphier_spi_priv *priv = dev_id; 60362306a36Sopenharmony_ci u32 val, stat; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci stat = readl(priv->base + SSI_IS); 60662306a36Sopenharmony_ci val = SSI_IC_TCIC | SSI_IC_RCIC | SSI_IC_RORIC; 60762306a36Sopenharmony_ci writel(val, priv->base + SSI_IC); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* rx fifo overrun */ 61062306a36Sopenharmony_ci if (stat & SSI_IS_RORID) { 61162306a36Sopenharmony_ci priv->error = -EIO; 61262306a36Sopenharmony_ci goto done; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* rx complete */ 61662306a36Sopenharmony_ci if ((stat & SSI_IS_RCID) && (stat & SSI_IS_RXRS)) { 61762306a36Sopenharmony_ci while ((readl(priv->base + SSI_SR) & SSI_SR_RNE) && 61862306a36Sopenharmony_ci (priv->rx_bytes - priv->tx_bytes) > 0) 61962306a36Sopenharmony_ci uniphier_spi_recv(priv); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if ((readl(priv->base + SSI_SR) & SSI_SR_RNE) || 62262306a36Sopenharmony_ci (priv->rx_bytes != priv->tx_bytes)) { 62362306a36Sopenharmony_ci priv->error = -EIO; 62462306a36Sopenharmony_ci goto done; 62562306a36Sopenharmony_ci } else if (priv->rx_bytes == 0) 62662306a36Sopenharmony_ci goto done; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* next tx transfer */ 62962306a36Sopenharmony_ci uniphier_spi_fill_tx_fifo(priv); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return IRQ_HANDLED; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return IRQ_NONE; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cidone: 63762306a36Sopenharmony_ci complete(&priv->xfer_done); 63862306a36Sopenharmony_ci return IRQ_HANDLED; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int uniphier_spi_probe(struct platform_device *pdev) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct uniphier_spi_priv *priv; 64462306a36Sopenharmony_ci struct spi_master *master; 64562306a36Sopenharmony_ci struct resource *res; 64662306a36Sopenharmony_ci struct dma_slave_caps caps; 64762306a36Sopenharmony_ci u32 dma_tx_burst = 0, dma_rx_burst = 0; 64862306a36Sopenharmony_ci unsigned long clk_rate; 64962306a36Sopenharmony_ci int irq; 65062306a36Sopenharmony_ci int ret; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(*priv)); 65362306a36Sopenharmony_ci if (!master) 65462306a36Sopenharmony_ci return -ENOMEM; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci platform_set_drvdata(pdev, master); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci priv = spi_master_get_devdata(master); 65962306a36Sopenharmony_ci priv->master = master; 66062306a36Sopenharmony_ci priv->is_save_param = false; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 66362306a36Sopenharmony_ci if (IS_ERR(priv->base)) { 66462306a36Sopenharmony_ci ret = PTR_ERR(priv->base); 66562306a36Sopenharmony_ci goto out_master_put; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci priv->base_dma_addr = res->start; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci priv->clk = devm_clk_get(&pdev->dev, NULL); 67062306a36Sopenharmony_ci if (IS_ERR(priv->clk)) { 67162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get clock\n"); 67262306a36Sopenharmony_ci ret = PTR_ERR(priv->clk); 67362306a36Sopenharmony_ci goto out_master_put; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 67762306a36Sopenharmony_ci if (ret) 67862306a36Sopenharmony_ci goto out_master_put; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 68162306a36Sopenharmony_ci if (irq < 0) { 68262306a36Sopenharmony_ci ret = irq; 68362306a36Sopenharmony_ci goto out_disable_clk; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler, 68762306a36Sopenharmony_ci 0, "uniphier-spi", priv); 68862306a36Sopenharmony_ci if (ret) { 68962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to request IRQ\n"); 69062306a36Sopenharmony_ci goto out_disable_clk; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci init_completion(&priv->xfer_done); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci clk_rate = clk_get_rate(priv->clk); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); 69862306a36Sopenharmony_ci master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER); 69962306a36Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; 70062306a36Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 70162306a36Sopenharmony_ci master->bus_num = pdev->id; 70262306a36Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci master->set_cs = uniphier_spi_set_cs; 70562306a36Sopenharmony_ci master->transfer_one = uniphier_spi_transfer_one; 70662306a36Sopenharmony_ci master->prepare_transfer_hardware 70762306a36Sopenharmony_ci = uniphier_spi_prepare_transfer_hardware; 70862306a36Sopenharmony_ci master->unprepare_transfer_hardware 70962306a36Sopenharmony_ci = uniphier_spi_unprepare_transfer_hardware; 71062306a36Sopenharmony_ci master->handle_err = uniphier_spi_handle_err; 71162306a36Sopenharmony_ci master->can_dma = uniphier_spi_can_dma; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci master->num_chipselect = 1; 71462306a36Sopenharmony_ci master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci master->dma_tx = dma_request_chan(&pdev->dev, "tx"); 71762306a36Sopenharmony_ci if (IS_ERR_OR_NULL(master->dma_tx)) { 71862306a36Sopenharmony_ci if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) { 71962306a36Sopenharmony_ci ret = -EPROBE_DEFER; 72062306a36Sopenharmony_ci goto out_disable_clk; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci master->dma_tx = NULL; 72362306a36Sopenharmony_ci dma_tx_burst = INT_MAX; 72462306a36Sopenharmony_ci } else { 72562306a36Sopenharmony_ci ret = dma_get_slave_caps(master->dma_tx, &caps); 72662306a36Sopenharmony_ci if (ret) { 72762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", 72862306a36Sopenharmony_ci ret); 72962306a36Sopenharmony_ci goto out_release_dma; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci dma_tx_burst = caps.max_burst; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci master->dma_rx = dma_request_chan(&pdev->dev, "rx"); 73562306a36Sopenharmony_ci if (IS_ERR_OR_NULL(master->dma_rx)) { 73662306a36Sopenharmony_ci if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { 73762306a36Sopenharmony_ci ret = -EPROBE_DEFER; 73862306a36Sopenharmony_ci goto out_release_dma; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci master->dma_rx = NULL; 74162306a36Sopenharmony_ci dma_rx_burst = INT_MAX; 74262306a36Sopenharmony_ci } else { 74362306a36Sopenharmony_ci ret = dma_get_slave_caps(master->dma_rx, &caps); 74462306a36Sopenharmony_ci if (ret) { 74562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", 74662306a36Sopenharmony_ci ret); 74762306a36Sopenharmony_ci goto out_release_dma; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci dma_rx_burst = caps.max_burst; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci master->max_dma_len = min(dma_tx_burst, dma_rx_burst); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = devm_spi_register_master(&pdev->dev, master); 75562306a36Sopenharmony_ci if (ret) 75662306a36Sopenharmony_ci goto out_release_dma; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci return 0; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ciout_release_dma: 76162306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(master->dma_rx)) { 76262306a36Sopenharmony_ci dma_release_channel(master->dma_rx); 76362306a36Sopenharmony_ci master->dma_rx = NULL; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(master->dma_tx)) { 76662306a36Sopenharmony_ci dma_release_channel(master->dma_tx); 76762306a36Sopenharmony_ci master->dma_tx = NULL; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ciout_disable_clk: 77162306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ciout_master_put: 77462306a36Sopenharmony_ci spi_master_put(master); 77562306a36Sopenharmony_ci return ret; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void uniphier_spi_remove(struct platform_device *pdev) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct spi_master *master = platform_get_drvdata(pdev); 78162306a36Sopenharmony_ci struct uniphier_spi_priv *priv = spi_master_get_devdata(master); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (master->dma_tx) 78462306a36Sopenharmony_ci dma_release_channel(master->dma_tx); 78562306a36Sopenharmony_ci if (master->dma_rx) 78662306a36Sopenharmony_ci dma_release_channel(master->dma_rx); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic const struct of_device_id uniphier_spi_match[] = { 79262306a36Sopenharmony_ci { .compatible = "socionext,uniphier-scssi" }, 79362306a36Sopenharmony_ci { /* sentinel */ } 79462306a36Sopenharmony_ci}; 79562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, uniphier_spi_match); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic struct platform_driver uniphier_spi_driver = { 79862306a36Sopenharmony_ci .probe = uniphier_spi_probe, 79962306a36Sopenharmony_ci .remove_new = uniphier_spi_remove, 80062306a36Sopenharmony_ci .driver = { 80162306a36Sopenharmony_ci .name = "uniphier-spi", 80262306a36Sopenharmony_ci .of_match_table = uniphier_spi_match, 80362306a36Sopenharmony_ci }, 80462306a36Sopenharmony_ci}; 80562306a36Sopenharmony_cimodule_platform_driver(uniphier_spi_driver); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ciMODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 80862306a36Sopenharmony_ciMODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>"); 80962306a36Sopenharmony_ciMODULE_DESCRIPTION("Socionext UniPhier SPI controller driver"); 81062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 811