162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 462306a36Sopenharmony_ci * Author: Addy Ke <addy.ke@rock-chips.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/dmaengine.h> 962306a36Sopenharmony_ci#include <linux/interrupt.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/spi/spi.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <linux/scatterlist.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define DRIVER_NAME "rockchip-spi" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define ROCKCHIP_SPI_CLR_BITS(reg, bits) \ 2162306a36Sopenharmony_ci writel_relaxed(readl_relaxed(reg) & ~(bits), reg) 2262306a36Sopenharmony_ci#define ROCKCHIP_SPI_SET_BITS(reg, bits) \ 2362306a36Sopenharmony_ci writel_relaxed(readl_relaxed(reg) | (bits), reg) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* SPI register offsets */ 2662306a36Sopenharmony_ci#define ROCKCHIP_SPI_CTRLR0 0x0000 2762306a36Sopenharmony_ci#define ROCKCHIP_SPI_CTRLR1 0x0004 2862306a36Sopenharmony_ci#define ROCKCHIP_SPI_SSIENR 0x0008 2962306a36Sopenharmony_ci#define ROCKCHIP_SPI_SER 0x000c 3062306a36Sopenharmony_ci#define ROCKCHIP_SPI_BAUDR 0x0010 3162306a36Sopenharmony_ci#define ROCKCHIP_SPI_TXFTLR 0x0014 3262306a36Sopenharmony_ci#define ROCKCHIP_SPI_RXFTLR 0x0018 3362306a36Sopenharmony_ci#define ROCKCHIP_SPI_TXFLR 0x001c 3462306a36Sopenharmony_ci#define ROCKCHIP_SPI_RXFLR 0x0020 3562306a36Sopenharmony_ci#define ROCKCHIP_SPI_SR 0x0024 3662306a36Sopenharmony_ci#define ROCKCHIP_SPI_IPR 0x0028 3762306a36Sopenharmony_ci#define ROCKCHIP_SPI_IMR 0x002c 3862306a36Sopenharmony_ci#define ROCKCHIP_SPI_ISR 0x0030 3962306a36Sopenharmony_ci#define ROCKCHIP_SPI_RISR 0x0034 4062306a36Sopenharmony_ci#define ROCKCHIP_SPI_ICR 0x0038 4162306a36Sopenharmony_ci#define ROCKCHIP_SPI_DMACR 0x003c 4262306a36Sopenharmony_ci#define ROCKCHIP_SPI_DMATDLR 0x0040 4362306a36Sopenharmony_ci#define ROCKCHIP_SPI_DMARDLR 0x0044 4462306a36Sopenharmony_ci#define ROCKCHIP_SPI_VERSION 0x0048 4562306a36Sopenharmony_ci#define ROCKCHIP_SPI_TXDR 0x0400 4662306a36Sopenharmony_ci#define ROCKCHIP_SPI_RXDR 0x0800 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Bit fields in CTRLR0 */ 4962306a36Sopenharmony_ci#define CR0_DFS_OFFSET 0 5062306a36Sopenharmony_ci#define CR0_DFS_4BIT 0x0 5162306a36Sopenharmony_ci#define CR0_DFS_8BIT 0x1 5262306a36Sopenharmony_ci#define CR0_DFS_16BIT 0x2 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define CR0_CFS_OFFSET 2 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define CR0_SCPH_OFFSET 6 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define CR0_SCPOL_OFFSET 7 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define CR0_CSM_OFFSET 8 6162306a36Sopenharmony_ci#define CR0_CSM_KEEP 0x0 6262306a36Sopenharmony_ci/* ss_n be high for half sclk_out cycles */ 6362306a36Sopenharmony_ci#define CR0_CSM_HALF 0X1 6462306a36Sopenharmony_ci/* ss_n be high for one sclk_out cycle */ 6562306a36Sopenharmony_ci#define CR0_CSM_ONE 0x2 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* ss_n to sclk_out delay */ 6862306a36Sopenharmony_ci#define CR0_SSD_OFFSET 10 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * The period between ss_n active and 7162306a36Sopenharmony_ci * sclk_out active is half sclk_out cycles 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci#define CR0_SSD_HALF 0x0 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * The period between ss_n active and 7662306a36Sopenharmony_ci * sclk_out active is one sclk_out cycle 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci#define CR0_SSD_ONE 0x1 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define CR0_EM_OFFSET 11 8162306a36Sopenharmony_ci#define CR0_EM_LITTLE 0x0 8262306a36Sopenharmony_ci#define CR0_EM_BIG 0x1 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define CR0_FBM_OFFSET 12 8562306a36Sopenharmony_ci#define CR0_FBM_MSB 0x0 8662306a36Sopenharmony_ci#define CR0_FBM_LSB 0x1 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define CR0_BHT_OFFSET 13 8962306a36Sopenharmony_ci#define CR0_BHT_16BIT 0x0 9062306a36Sopenharmony_ci#define CR0_BHT_8BIT 0x1 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define CR0_RSD_OFFSET 14 9362306a36Sopenharmony_ci#define CR0_RSD_MAX 0x3 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define CR0_FRF_OFFSET 16 9662306a36Sopenharmony_ci#define CR0_FRF_SPI 0x0 9762306a36Sopenharmony_ci#define CR0_FRF_SSP 0x1 9862306a36Sopenharmony_ci#define CR0_FRF_MICROWIRE 0x2 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define CR0_XFM_OFFSET 18 10162306a36Sopenharmony_ci#define CR0_XFM_MASK (0x03 << SPI_XFM_OFFSET) 10262306a36Sopenharmony_ci#define CR0_XFM_TR 0x0 10362306a36Sopenharmony_ci#define CR0_XFM_TO 0x1 10462306a36Sopenharmony_ci#define CR0_XFM_RO 0x2 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define CR0_OPM_OFFSET 20 10762306a36Sopenharmony_ci#define CR0_OPM_HOST 0x0 10862306a36Sopenharmony_ci#define CR0_OPM_TARGET 0x1 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define CR0_SOI_OFFSET 23 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define CR0_MTM_OFFSET 0x21 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* Bit fields in SER, 2bit */ 11562306a36Sopenharmony_ci#define SER_MASK 0x3 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* Bit fields in BAUDR */ 11862306a36Sopenharmony_ci#define BAUDR_SCKDV_MIN 2 11962306a36Sopenharmony_ci#define BAUDR_SCKDV_MAX 65534 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* Bit fields in SR, 6bit */ 12262306a36Sopenharmony_ci#define SR_MASK 0x3f 12362306a36Sopenharmony_ci#define SR_BUSY (1 << 0) 12462306a36Sopenharmony_ci#define SR_TF_FULL (1 << 1) 12562306a36Sopenharmony_ci#define SR_TF_EMPTY (1 << 2) 12662306a36Sopenharmony_ci#define SR_RF_EMPTY (1 << 3) 12762306a36Sopenharmony_ci#define SR_RF_FULL (1 << 4) 12862306a36Sopenharmony_ci#define SR_TARGET_TX_BUSY (1 << 5) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* Bit fields in ISR, IMR, ISR, RISR, 5bit */ 13162306a36Sopenharmony_ci#define INT_MASK 0x1f 13262306a36Sopenharmony_ci#define INT_TF_EMPTY (1 << 0) 13362306a36Sopenharmony_ci#define INT_TF_OVERFLOW (1 << 1) 13462306a36Sopenharmony_ci#define INT_RF_UNDERFLOW (1 << 2) 13562306a36Sopenharmony_ci#define INT_RF_OVERFLOW (1 << 3) 13662306a36Sopenharmony_ci#define INT_RF_FULL (1 << 4) 13762306a36Sopenharmony_ci#define INT_CS_INACTIVE (1 << 6) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* Bit fields in ICR, 4bit */ 14062306a36Sopenharmony_ci#define ICR_MASK 0x0f 14162306a36Sopenharmony_ci#define ICR_ALL (1 << 0) 14262306a36Sopenharmony_ci#define ICR_RF_UNDERFLOW (1 << 1) 14362306a36Sopenharmony_ci#define ICR_RF_OVERFLOW (1 << 2) 14462306a36Sopenharmony_ci#define ICR_TF_OVERFLOW (1 << 3) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* Bit fields in DMACR */ 14762306a36Sopenharmony_ci#define RF_DMA_EN (1 << 0) 14862306a36Sopenharmony_ci#define TF_DMA_EN (1 << 1) 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Driver state flags */ 15162306a36Sopenharmony_ci#define RXDMA (1 << 0) 15262306a36Sopenharmony_ci#define TXDMA (1 << 1) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* sclk_out: spi host internal logic in rk3x can support 50Mhz */ 15562306a36Sopenharmony_ci#define MAX_SCLK_OUT 50000000U 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However, 15962306a36Sopenharmony_ci * the controller seems to hang when given 0x10000, so stick with this for now. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* 2 for native cs, 2 for cs-gpio */ 16462306a36Sopenharmony_ci#define ROCKCHIP_SPI_MAX_CS_NUM 4 16562306a36Sopenharmony_ci#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002 16662306a36Sopenharmony_ci#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#define ROCKCHIP_AUTOSUSPEND_TIMEOUT 2000 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistruct rockchip_spi { 17162306a36Sopenharmony_ci struct device *dev; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci struct clk *spiclk; 17462306a36Sopenharmony_ci struct clk *apb_pclk; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci void __iomem *regs; 17762306a36Sopenharmony_ci dma_addr_t dma_addr_rx; 17862306a36Sopenharmony_ci dma_addr_t dma_addr_tx; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci const void *tx; 18162306a36Sopenharmony_ci void *rx; 18262306a36Sopenharmony_ci unsigned int tx_left; 18362306a36Sopenharmony_ci unsigned int rx_left; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci atomic_t state; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /*depth of the FIFO buffer */ 18862306a36Sopenharmony_ci u32 fifo_len; 18962306a36Sopenharmony_ci /* frequency of spiclk */ 19062306a36Sopenharmony_ci u32 freq; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci u8 n_bytes; 19362306a36Sopenharmony_ci u8 rsd; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci bool target_abort; 19862306a36Sopenharmony_ci bool cs_inactive; /* spi target tansmition stop when cs inactive */ 19962306a36Sopenharmony_ci bool cs_high_supported; /* native CS supports active-high polarity */ 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci struct spi_transfer *xfer; /* Store xfer temporarily */ 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic inline void spi_enable_chip(struct rockchip_spi *rs, bool enable) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline void wait_for_tx_idle(struct rockchip_spi *rs, bool target_mode) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(5); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci do { 21462306a36Sopenharmony_ci if (target_mode) { 21562306a36Sopenharmony_ci if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_TARGET_TX_BUSY) && 21662306a36Sopenharmony_ci !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))) 21762306a36Sopenharmony_ci return; 21862306a36Sopenharmony_ci } else { 21962306a36Sopenharmony_ci if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)) 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci } while (!time_after(jiffies, timeout)); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci dev_warn(rs->dev, "spi controller is in busy state!\n"); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic u32 get_fifo_len(struct rockchip_spi *rs) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u32 ver; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ver = readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci switch (ver) { 23462306a36Sopenharmony_ci case ROCKCHIP_SPI_VER2_TYPE1: 23562306a36Sopenharmony_ci case ROCKCHIP_SPI_VER2_TYPE2: 23662306a36Sopenharmony_ci return 64; 23762306a36Sopenharmony_ci default: 23862306a36Sopenharmony_ci return 32; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void rockchip_spi_set_cs(struct spi_device *spi, bool enable) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct spi_controller *ctlr = spi->controller; 24562306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 24662306a36Sopenharmony_ci bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Return immediately for no-op */ 24962306a36Sopenharmony_ci if (cs_asserted == rs->cs_asserted[spi_get_chipselect(spi, 0)]) 25062306a36Sopenharmony_ci return; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (cs_asserted) { 25362306a36Sopenharmony_ci /* Keep things powered as long as CS is asserted */ 25462306a36Sopenharmony_ci pm_runtime_get_sync(rs->dev); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (spi_get_csgpiod(spi, 0)) 25762306a36Sopenharmony_ci ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 26062306a36Sopenharmony_ci BIT(spi_get_chipselect(spi, 0))); 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci if (spi_get_csgpiod(spi, 0)) 26362306a36Sopenharmony_ci ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); 26462306a36Sopenharmony_ci else 26562306a36Sopenharmony_ci ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 26662306a36Sopenharmony_ci BIT(spi_get_chipselect(spi, 0))); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Drop reference from when we first asserted CS */ 26962306a36Sopenharmony_ci pm_runtime_put(rs->dev); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci rs->cs_asserted[spi_get_chipselect(spi, 0)] = cs_asserted; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void rockchip_spi_handle_err(struct spi_controller *ctlr, 27662306a36Sopenharmony_ci struct spi_message *msg) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* stop running spi transfer 28162306a36Sopenharmony_ci * this also flushes both rx and tx fifos 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci spi_enable_chip(rs, false); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* make sure all interrupts are masked and status cleared */ 28662306a36Sopenharmony_ci writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); 28762306a36Sopenharmony_ci writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (atomic_read(&rs->state) & TXDMA) 29062306a36Sopenharmony_ci dmaengine_terminate_async(ctlr->dma_tx); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (atomic_read(&rs->state) & RXDMA) 29362306a36Sopenharmony_ci dmaengine_terminate_async(ctlr->dma_rx); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void rockchip_spi_pio_writer(struct rockchip_spi *rs) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci u32 tx_free = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR); 29962306a36Sopenharmony_ci u32 words = min(rs->tx_left, tx_free); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci rs->tx_left -= words; 30262306a36Sopenharmony_ci for (; words; words--) { 30362306a36Sopenharmony_ci u32 txw; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (rs->n_bytes == 1) 30662306a36Sopenharmony_ci txw = *(u8 *)rs->tx; 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci txw = *(u16 *)rs->tx; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci writel_relaxed(txw, rs->regs + ROCKCHIP_SPI_TXDR); 31162306a36Sopenharmony_ci rs->tx += rs->n_bytes; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void rockchip_spi_pio_reader(struct rockchip_spi *rs) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); 31862306a36Sopenharmony_ci u32 rx_left = (rs->rx_left > words) ? rs->rx_left - words : 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* the hardware doesn't allow us to change fifo threshold 32162306a36Sopenharmony_ci * level while spi is enabled, so instead make sure to leave 32262306a36Sopenharmony_ci * enough words in the rx fifo to get the last interrupt 32362306a36Sopenharmony_ci * exactly when all words have been received 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci if (rx_left) { 32662306a36Sopenharmony_ci u32 ftl = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFTLR) + 1; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (rx_left < ftl) { 32962306a36Sopenharmony_ci rx_left = ftl; 33062306a36Sopenharmony_ci words = rs->rx_left - rx_left; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci rs->rx_left = rx_left; 33562306a36Sopenharmony_ci for (; words; words--) { 33662306a36Sopenharmony_ci u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!rs->rx) 33962306a36Sopenharmony_ci continue; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (rs->n_bytes == 1) 34262306a36Sopenharmony_ci *(u8 *)rs->rx = (u8)rxw; 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci *(u16 *)rs->rx = (u16)rxw; 34562306a36Sopenharmony_ci rs->rx += rs->n_bytes; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic irqreturn_t rockchip_spi_isr(int irq, void *dev_id) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct spi_controller *ctlr = dev_id; 35262306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* When int_cs_inactive comes, spi target abort */ 35562306a36Sopenharmony_ci if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { 35662306a36Sopenharmony_ci ctlr->target_abort(ctlr); 35762306a36Sopenharmony_ci writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); 35862306a36Sopenharmony_ci writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return IRQ_HANDLED; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (rs->tx_left) 36462306a36Sopenharmony_ci rockchip_spi_pio_writer(rs); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci rockchip_spi_pio_reader(rs); 36762306a36Sopenharmony_ci if (!rs->rx_left) { 36862306a36Sopenharmony_ci spi_enable_chip(rs, false); 36962306a36Sopenharmony_ci writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); 37062306a36Sopenharmony_ci writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); 37162306a36Sopenharmony_ci spi_finalize_current_transfer(ctlr); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return IRQ_HANDLED; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int rockchip_spi_prepare_irq(struct rockchip_spi *rs, 37862306a36Sopenharmony_ci struct spi_controller *ctlr, 37962306a36Sopenharmony_ci struct spi_transfer *xfer) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci rs->tx = xfer->tx_buf; 38262306a36Sopenharmony_ci rs->rx = xfer->rx_buf; 38362306a36Sopenharmony_ci rs->tx_left = rs->tx ? xfer->len / rs->n_bytes : 0; 38462306a36Sopenharmony_ci rs->rx_left = xfer->len / rs->n_bytes; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci spi_enable_chip(rs, true); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (rs->tx_left) 39162306a36Sopenharmony_ci rockchip_spi_pio_writer(rs); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (rs->cs_inactive) 39462306a36Sopenharmony_ci writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR); 39562306a36Sopenharmony_ci else 39662306a36Sopenharmony_ci writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* 1 means the transfer is in progress */ 39962306a36Sopenharmony_ci return 1; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void rockchip_spi_dma_rxcb(void *data) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct spi_controller *ctlr = data; 40562306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 40662306a36Sopenharmony_ci int state = atomic_fetch_andnot(RXDMA, &rs->state); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (state & TXDMA && !rs->target_abort) 40962306a36Sopenharmony_ci return; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (rs->cs_inactive) 41262306a36Sopenharmony_ci writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci spi_enable_chip(rs, false); 41562306a36Sopenharmony_ci spi_finalize_current_transfer(ctlr); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic void rockchip_spi_dma_txcb(void *data) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct spi_controller *ctlr = data; 42162306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 42262306a36Sopenharmony_ci int state = atomic_fetch_andnot(TXDMA, &rs->state); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (state & RXDMA && !rs->target_abort) 42562306a36Sopenharmony_ci return; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Wait until the FIFO data completely. */ 42862306a36Sopenharmony_ci wait_for_tx_idle(rs, ctlr->target); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci spi_enable_chip(rs, false); 43162306a36Sopenharmony_ci spi_finalize_current_transfer(ctlr); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic u32 rockchip_spi_calc_burst_size(u32 data_len) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci u32 i; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* burst size: 1, 2, 4, 8 */ 43962306a36Sopenharmony_ci for (i = 1; i < 8; i <<= 1) { 44062306a36Sopenharmony_ci if (data_len & i) 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return i; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int rockchip_spi_prepare_dma(struct rockchip_spi *rs, 44862306a36Sopenharmony_ci struct spi_controller *ctlr, struct spi_transfer *xfer) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc, *txdesc; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci atomic_set(&rs->state, 0); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci rs->tx = xfer->tx_buf; 45562306a36Sopenharmony_ci rs->rx = xfer->rx_buf; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci rxdesc = NULL; 45862306a36Sopenharmony_ci if (xfer->rx_buf) { 45962306a36Sopenharmony_ci struct dma_slave_config rxconf = { 46062306a36Sopenharmony_ci .direction = DMA_DEV_TO_MEM, 46162306a36Sopenharmony_ci .src_addr = rs->dma_addr_rx, 46262306a36Sopenharmony_ci .src_addr_width = rs->n_bytes, 46362306a36Sopenharmony_ci .src_maxburst = rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes), 46462306a36Sopenharmony_ci }; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci dmaengine_slave_config(ctlr->dma_rx, &rxconf); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg( 46962306a36Sopenharmony_ci ctlr->dma_rx, 47062306a36Sopenharmony_ci xfer->rx_sg.sgl, xfer->rx_sg.nents, 47162306a36Sopenharmony_ci DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); 47262306a36Sopenharmony_ci if (!rxdesc) 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci rxdesc->callback = rockchip_spi_dma_rxcb; 47662306a36Sopenharmony_ci rxdesc->callback_param = ctlr; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci txdesc = NULL; 48062306a36Sopenharmony_ci if (xfer->tx_buf) { 48162306a36Sopenharmony_ci struct dma_slave_config txconf = { 48262306a36Sopenharmony_ci .direction = DMA_MEM_TO_DEV, 48362306a36Sopenharmony_ci .dst_addr = rs->dma_addr_tx, 48462306a36Sopenharmony_ci .dst_addr_width = rs->n_bytes, 48562306a36Sopenharmony_ci .dst_maxburst = rs->fifo_len / 4, 48662306a36Sopenharmony_ci }; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci dmaengine_slave_config(ctlr->dma_tx, &txconf); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci txdesc = dmaengine_prep_slave_sg( 49162306a36Sopenharmony_ci ctlr->dma_tx, 49262306a36Sopenharmony_ci xfer->tx_sg.sgl, xfer->tx_sg.nents, 49362306a36Sopenharmony_ci DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); 49462306a36Sopenharmony_ci if (!txdesc) { 49562306a36Sopenharmony_ci if (rxdesc) 49662306a36Sopenharmony_ci dmaengine_terminate_sync(ctlr->dma_rx); 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci txdesc->callback = rockchip_spi_dma_txcb; 50162306a36Sopenharmony_ci txdesc->callback_param = ctlr; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* rx must be started before tx due to spi instinct */ 50562306a36Sopenharmony_ci if (rxdesc) { 50662306a36Sopenharmony_ci atomic_or(RXDMA, &rs->state); 50762306a36Sopenharmony_ci ctlr->dma_rx->cookie = dmaengine_submit(rxdesc); 50862306a36Sopenharmony_ci dma_async_issue_pending(ctlr->dma_rx); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (rs->cs_inactive) 51262306a36Sopenharmony_ci writel_relaxed(INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci spi_enable_chip(rs, true); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (txdesc) { 51762306a36Sopenharmony_ci atomic_or(TXDMA, &rs->state); 51862306a36Sopenharmony_ci dmaengine_submit(txdesc); 51962306a36Sopenharmony_ci dma_async_issue_pending(ctlr->dma_tx); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* 1 means the transfer is in progress */ 52362306a36Sopenharmony_ci return 1; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int rockchip_spi_config(struct rockchip_spi *rs, 52762306a36Sopenharmony_ci struct spi_device *spi, struct spi_transfer *xfer, 52862306a36Sopenharmony_ci bool use_dma, bool target_mode) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET 53162306a36Sopenharmony_ci | CR0_BHT_8BIT << CR0_BHT_OFFSET 53262306a36Sopenharmony_ci | CR0_SSD_ONE << CR0_SSD_OFFSET 53362306a36Sopenharmony_ci | CR0_EM_BIG << CR0_EM_OFFSET; 53462306a36Sopenharmony_ci u32 cr1; 53562306a36Sopenharmony_ci u32 dmacr = 0; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (target_mode) 53862306a36Sopenharmony_ci cr0 |= CR0_OPM_TARGET << CR0_OPM_OFFSET; 53962306a36Sopenharmony_ci rs->target_abort = false; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci cr0 |= rs->rsd << CR0_RSD_OFFSET; 54262306a36Sopenharmony_ci cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; 54362306a36Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) 54462306a36Sopenharmony_ci cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; 54562306a36Sopenharmony_ci if (spi->mode & SPI_CS_HIGH) 54662306a36Sopenharmony_ci cr0 |= BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (xfer->rx_buf && xfer->tx_buf) 54962306a36Sopenharmony_ci cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET; 55062306a36Sopenharmony_ci else if (xfer->rx_buf) 55162306a36Sopenharmony_ci cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET; 55262306a36Sopenharmony_ci else if (use_dma) 55362306a36Sopenharmony_ci cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci switch (xfer->bits_per_word) { 55662306a36Sopenharmony_ci case 4: 55762306a36Sopenharmony_ci cr0 |= CR0_DFS_4BIT << CR0_DFS_OFFSET; 55862306a36Sopenharmony_ci cr1 = xfer->len - 1; 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci case 8: 56162306a36Sopenharmony_ci cr0 |= CR0_DFS_8BIT << CR0_DFS_OFFSET; 56262306a36Sopenharmony_ci cr1 = xfer->len - 1; 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci case 16: 56562306a36Sopenharmony_ci cr0 |= CR0_DFS_16BIT << CR0_DFS_OFFSET; 56662306a36Sopenharmony_ci cr1 = xfer->len / 2 - 1; 56762306a36Sopenharmony_ci break; 56862306a36Sopenharmony_ci default: 56962306a36Sopenharmony_ci /* we only whitelist 4, 8 and 16 bit words in 57062306a36Sopenharmony_ci * ctlr->bits_per_word_mask, so this shouldn't 57162306a36Sopenharmony_ci * happen 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci dev_err(rs->dev, "unknown bits per word: %d\n", 57462306a36Sopenharmony_ci xfer->bits_per_word); 57562306a36Sopenharmony_ci return -EINVAL; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (use_dma) { 57962306a36Sopenharmony_ci if (xfer->tx_buf) 58062306a36Sopenharmony_ci dmacr |= TF_DMA_EN; 58162306a36Sopenharmony_ci if (xfer->rx_buf) 58262306a36Sopenharmony_ci dmacr |= RF_DMA_EN; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); 58662306a36Sopenharmony_ci writel_relaxed(cr1, rs->regs + ROCKCHIP_SPI_CTRLR1); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* unfortunately setting the fifo threshold level to generate an 58962306a36Sopenharmony_ci * interrupt exactly when the fifo is full doesn't seem to work, 59062306a36Sopenharmony_ci * so we need the strict inequality here 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci if ((xfer->len / rs->n_bytes) < rs->fifo_len) 59362306a36Sopenharmony_ci writel_relaxed(xfer->len / rs->n_bytes - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); 59462306a36Sopenharmony_ci else 59562306a36Sopenharmony_ci writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR); 59862306a36Sopenharmony_ci writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1, 59962306a36Sopenharmony_ci rs->regs + ROCKCHIP_SPI_DMARDLR); 60062306a36Sopenharmony_ci writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* the hardware only supports an even clock divisor, so 60362306a36Sopenharmony_ci * round divisor = spiclk / speed up to nearest even number 60462306a36Sopenharmony_ci * so that the resulting speed is <= the requested speed 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ci writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz), 60762306a36Sopenharmony_ci rs->regs + ROCKCHIP_SPI_BAUDR); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic size_t rockchip_spi_max_transfer_size(struct spi_device *spi) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci return ROCKCHIP_SPI_MAX_TRANLEN; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int rockchip_spi_target_abort(struct spi_controller *ctlr) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 62062306a36Sopenharmony_ci u32 rx_fifo_left; 62162306a36Sopenharmony_ci struct dma_tx_state state; 62262306a36Sopenharmony_ci enum dma_status status; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Get current dma rx point */ 62562306a36Sopenharmony_ci if (atomic_read(&rs->state) & RXDMA) { 62662306a36Sopenharmony_ci dmaengine_pause(ctlr->dma_rx); 62762306a36Sopenharmony_ci status = dmaengine_tx_status(ctlr->dma_rx, ctlr->dma_rx->cookie, &state); 62862306a36Sopenharmony_ci if (status == DMA_ERROR) { 62962306a36Sopenharmony_ci rs->rx = rs->xfer->rx_buf; 63062306a36Sopenharmony_ci rs->xfer->len = 0; 63162306a36Sopenharmony_ci rx_fifo_left = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); 63262306a36Sopenharmony_ci for (; rx_fifo_left; rx_fifo_left--) 63362306a36Sopenharmony_ci readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR); 63462306a36Sopenharmony_ci goto out; 63562306a36Sopenharmony_ci } else { 63662306a36Sopenharmony_ci rs->rx += rs->xfer->len - rs->n_bytes * state.residue; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Get the valid data left in rx fifo and set rs->xfer->len real rx size */ 64162306a36Sopenharmony_ci if (rs->rx) { 64262306a36Sopenharmony_ci rx_fifo_left = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); 64362306a36Sopenharmony_ci for (; rx_fifo_left; rx_fifo_left--) { 64462306a36Sopenharmony_ci u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (rs->n_bytes == 1) 64762306a36Sopenharmony_ci *(u8 *)rs->rx = (u8)rxw; 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci *(u16 *)rs->rx = (u16)rxw; 65062306a36Sopenharmony_ci rs->rx += rs->n_bytes; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci rs->xfer->len = (unsigned int)(rs->rx - rs->xfer->rx_buf); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ciout: 65662306a36Sopenharmony_ci if (atomic_read(&rs->state) & RXDMA) 65762306a36Sopenharmony_ci dmaengine_terminate_sync(ctlr->dma_rx); 65862306a36Sopenharmony_ci if (atomic_read(&rs->state) & TXDMA) 65962306a36Sopenharmony_ci dmaengine_terminate_sync(ctlr->dma_tx); 66062306a36Sopenharmony_ci atomic_set(&rs->state, 0); 66162306a36Sopenharmony_ci spi_enable_chip(rs, false); 66262306a36Sopenharmony_ci rs->target_abort = true; 66362306a36Sopenharmony_ci spi_finalize_current_transfer(ctlr); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int rockchip_spi_transfer_one( 66962306a36Sopenharmony_ci struct spi_controller *ctlr, 67062306a36Sopenharmony_ci struct spi_device *spi, 67162306a36Sopenharmony_ci struct spi_transfer *xfer) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 67462306a36Sopenharmony_ci int ret; 67562306a36Sopenharmony_ci bool use_dma; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Zero length transfers won't trigger an interrupt on completion */ 67862306a36Sopenharmony_ci if (!xfer->len) { 67962306a36Sopenharmony_ci spi_finalize_current_transfer(ctlr); 68062306a36Sopenharmony_ci return 1; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && 68462306a36Sopenharmony_ci (readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (!xfer->tx_buf && !xfer->rx_buf) { 68762306a36Sopenharmony_ci dev_err(rs->dev, "No buffer for transfer\n"); 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (xfer->len > ROCKCHIP_SPI_MAX_TRANLEN) { 69262306a36Sopenharmony_ci dev_err(rs->dev, "Transfer is too long (%d)\n", xfer->len); 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2; 69762306a36Sopenharmony_ci rs->xfer = xfer; 69862306a36Sopenharmony_ci use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->target); 70162306a36Sopenharmony_ci if (ret) 70262306a36Sopenharmony_ci return ret; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (use_dma) 70562306a36Sopenharmony_ci return rockchip_spi_prepare_dma(rs, ctlr, xfer); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return rockchip_spi_prepare_irq(rs, ctlr, xfer); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic bool rockchip_spi_can_dma(struct spi_controller *ctlr, 71162306a36Sopenharmony_ci struct spi_device *spi, 71262306a36Sopenharmony_ci struct spi_transfer *xfer) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 71562306a36Sopenharmony_ci unsigned int bytes_per_word = xfer->bits_per_word <= 8 ? 1 : 2; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* if the numbor of spi words to transfer is less than the fifo 71862306a36Sopenharmony_ci * length we can just fill the fifo and wait for a single irq, 71962306a36Sopenharmony_ci * so don't bother setting up dma 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci return xfer->len / bytes_per_word >= rs->fifo_len; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int rockchip_spi_setup(struct spi_device *spi) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(spi->controller); 72762306a36Sopenharmony_ci u32 cr0; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (!spi_get_csgpiod(spi, 0) && (spi->mode & SPI_CS_HIGH) && !rs->cs_high_supported) { 73062306a36Sopenharmony_ci dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n"); 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci pm_runtime_get_sync(rs->dev); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci cr0 = readl_relaxed(rs->regs + ROCKCHIP_SPI_CTRLR0); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci cr0 &= ~(0x3 << CR0_SCPH_OFFSET); 73962306a36Sopenharmony_ci cr0 |= ((spi->mode & 0x3) << CR0_SCPH_OFFSET); 74062306a36Sopenharmony_ci if (spi->mode & SPI_CS_HIGH && spi_get_chipselect(spi, 0) <= 1) 74162306a36Sopenharmony_ci cr0 |= BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET; 74262306a36Sopenharmony_ci else if (spi_get_chipselect(spi, 0) <= 1) 74362306a36Sopenharmony_ci cr0 &= ~(BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci pm_runtime_put(rs->dev); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return 0; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic int rockchip_spi_probe(struct platform_device *pdev) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci int ret; 75562306a36Sopenharmony_ci struct rockchip_spi *rs; 75662306a36Sopenharmony_ci struct spi_controller *ctlr; 75762306a36Sopenharmony_ci struct resource *mem; 75862306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 75962306a36Sopenharmony_ci u32 rsd_nsecs, num_cs; 76062306a36Sopenharmony_ci bool target_mode; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci target_mode = of_property_read_bool(np, "spi-slave"); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (target_mode) 76562306a36Sopenharmony_ci ctlr = spi_alloc_target(&pdev->dev, 76662306a36Sopenharmony_ci sizeof(struct rockchip_spi)); 76762306a36Sopenharmony_ci else 76862306a36Sopenharmony_ci ctlr = spi_alloc_host(&pdev->dev, 76962306a36Sopenharmony_ci sizeof(struct rockchip_spi)); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!ctlr) 77262306a36Sopenharmony_ci return -ENOMEM; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci platform_set_drvdata(pdev, ctlr); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci rs = spi_controller_get_devdata(ctlr); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Get basic io resource and map it */ 77962306a36Sopenharmony_ci rs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); 78062306a36Sopenharmony_ci if (IS_ERR(rs->regs)) { 78162306a36Sopenharmony_ci ret = PTR_ERR(rs->regs); 78262306a36Sopenharmony_ci goto err_put_ctlr; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); 78662306a36Sopenharmony_ci if (IS_ERR(rs->apb_pclk)) { 78762306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get apb_pclk\n"); 78862306a36Sopenharmony_ci ret = PTR_ERR(rs->apb_pclk); 78962306a36Sopenharmony_ci goto err_put_ctlr; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci rs->spiclk = devm_clk_get(&pdev->dev, "spiclk"); 79362306a36Sopenharmony_ci if (IS_ERR(rs->spiclk)) { 79462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get spi_pclk\n"); 79562306a36Sopenharmony_ci ret = PTR_ERR(rs->spiclk); 79662306a36Sopenharmony_ci goto err_put_ctlr; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci ret = clk_prepare_enable(rs->apb_pclk); 80062306a36Sopenharmony_ci if (ret < 0) { 80162306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable apb_pclk\n"); 80262306a36Sopenharmony_ci goto err_put_ctlr; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci ret = clk_prepare_enable(rs->spiclk); 80662306a36Sopenharmony_ci if (ret < 0) { 80762306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable spi_clk\n"); 80862306a36Sopenharmony_ci goto err_disable_apbclk; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci spi_enable_chip(rs, false); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 81462306a36Sopenharmony_ci if (ret < 0) 81562306a36Sopenharmony_ci goto err_disable_spiclk; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL, 81862306a36Sopenharmony_ci IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); 81962306a36Sopenharmony_ci if (ret) 82062306a36Sopenharmony_ci goto err_disable_spiclk; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci rs->dev = &pdev->dev; 82362306a36Sopenharmony_ci rs->freq = clk_get_rate(rs->spiclk); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns", 82662306a36Sopenharmony_ci &rsd_nsecs)) { 82762306a36Sopenharmony_ci /* rx sample delay is expressed in parent clock cycles (max 3) */ 82862306a36Sopenharmony_ci u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 82962306a36Sopenharmony_ci 1000000000 >> 8); 83062306a36Sopenharmony_ci if (!rsd) { 83162306a36Sopenharmony_ci dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n", 83262306a36Sopenharmony_ci rs->freq, rsd_nsecs); 83362306a36Sopenharmony_ci } else if (rsd > CR0_RSD_MAX) { 83462306a36Sopenharmony_ci rsd = CR0_RSD_MAX; 83562306a36Sopenharmony_ci dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", 83662306a36Sopenharmony_ci rs->freq, rsd_nsecs, 83762306a36Sopenharmony_ci CR0_RSD_MAX * 1000000000U / rs->freq); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci rs->rsd = rsd; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci rs->fifo_len = get_fifo_len(rs); 84362306a36Sopenharmony_ci if (!rs->fifo_len) { 84462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get fifo length\n"); 84562306a36Sopenharmony_ci ret = -EINVAL; 84662306a36Sopenharmony_ci goto err_disable_spiclk; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, ROCKCHIP_AUTOSUSPEND_TIMEOUT); 85062306a36Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 85162306a36Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 85262306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci ctlr->auto_runtime_pm = true; 85562306a36Sopenharmony_ci ctlr->bus_num = pdev->id; 85662306a36Sopenharmony_ci ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST; 85762306a36Sopenharmony_ci if (target_mode) { 85862306a36Sopenharmony_ci ctlr->mode_bits |= SPI_NO_CS; 85962306a36Sopenharmony_ci ctlr->target_abort = rockchip_spi_target_abort; 86062306a36Sopenharmony_ci } else { 86162306a36Sopenharmony_ci ctlr->flags = SPI_CONTROLLER_GPIO_SS; 86262306a36Sopenharmony_ci ctlr->max_native_cs = ROCKCHIP_SPI_MAX_CS_NUM; 86362306a36Sopenharmony_ci /* 86462306a36Sopenharmony_ci * rk spi0 has two native cs, spi1..5 one cs only 86562306a36Sopenharmony_ci * if num-cs is missing in the dts, default to 1 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_ci if (of_property_read_u32(np, "num-cs", &num_cs)) 86862306a36Sopenharmony_ci num_cs = 1; 86962306a36Sopenharmony_ci ctlr->num_chipselect = num_cs; 87062306a36Sopenharmony_ci ctlr->use_gpio_descriptors = true; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci ctlr->dev.of_node = pdev->dev.of_node; 87362306a36Sopenharmony_ci ctlr->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4); 87462306a36Sopenharmony_ci ctlr->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX; 87562306a36Sopenharmony_ci ctlr->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci ctlr->setup = rockchip_spi_setup; 87862306a36Sopenharmony_ci ctlr->set_cs = rockchip_spi_set_cs; 87962306a36Sopenharmony_ci ctlr->transfer_one = rockchip_spi_transfer_one; 88062306a36Sopenharmony_ci ctlr->max_transfer_size = rockchip_spi_max_transfer_size; 88162306a36Sopenharmony_ci ctlr->handle_err = rockchip_spi_handle_err; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci ctlr->dma_tx = dma_request_chan(rs->dev, "tx"); 88462306a36Sopenharmony_ci if (IS_ERR(ctlr->dma_tx)) { 88562306a36Sopenharmony_ci /* Check tx to see if we need defer probing driver */ 88662306a36Sopenharmony_ci if (PTR_ERR(ctlr->dma_tx) == -EPROBE_DEFER) { 88762306a36Sopenharmony_ci ret = -EPROBE_DEFER; 88862306a36Sopenharmony_ci goto err_disable_pm_runtime; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci dev_warn(rs->dev, "Failed to request TX DMA channel\n"); 89162306a36Sopenharmony_ci ctlr->dma_tx = NULL; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci ctlr->dma_rx = dma_request_chan(rs->dev, "rx"); 89562306a36Sopenharmony_ci if (IS_ERR(ctlr->dma_rx)) { 89662306a36Sopenharmony_ci if (PTR_ERR(ctlr->dma_rx) == -EPROBE_DEFER) { 89762306a36Sopenharmony_ci ret = -EPROBE_DEFER; 89862306a36Sopenharmony_ci goto err_free_dma_tx; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci dev_warn(rs->dev, "Failed to request RX DMA channel\n"); 90162306a36Sopenharmony_ci ctlr->dma_rx = NULL; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (ctlr->dma_tx && ctlr->dma_rx) { 90562306a36Sopenharmony_ci rs->dma_addr_tx = mem->start + ROCKCHIP_SPI_TXDR; 90662306a36Sopenharmony_ci rs->dma_addr_rx = mem->start + ROCKCHIP_SPI_RXDR; 90762306a36Sopenharmony_ci ctlr->can_dma = rockchip_spi_can_dma; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci switch (readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION)) { 91162306a36Sopenharmony_ci case ROCKCHIP_SPI_VER2_TYPE2: 91262306a36Sopenharmony_ci rs->cs_high_supported = true; 91362306a36Sopenharmony_ci ctlr->mode_bits |= SPI_CS_HIGH; 91462306a36Sopenharmony_ci if (ctlr->can_dma && target_mode) 91562306a36Sopenharmony_ci rs->cs_inactive = true; 91662306a36Sopenharmony_ci else 91762306a36Sopenharmony_ci rs->cs_inactive = false; 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci default: 92062306a36Sopenharmony_ci rs->cs_inactive = false; 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = devm_spi_register_controller(&pdev->dev, ctlr); 92562306a36Sopenharmony_ci if (ret < 0) { 92662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register controller\n"); 92762306a36Sopenharmony_ci goto err_free_dma_rx; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cierr_free_dma_rx: 93362306a36Sopenharmony_ci if (ctlr->dma_rx) 93462306a36Sopenharmony_ci dma_release_channel(ctlr->dma_rx); 93562306a36Sopenharmony_cierr_free_dma_tx: 93662306a36Sopenharmony_ci if (ctlr->dma_tx) 93762306a36Sopenharmony_ci dma_release_channel(ctlr->dma_tx); 93862306a36Sopenharmony_cierr_disable_pm_runtime: 93962306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 94062306a36Sopenharmony_cierr_disable_spiclk: 94162306a36Sopenharmony_ci clk_disable_unprepare(rs->spiclk); 94262306a36Sopenharmony_cierr_disable_apbclk: 94362306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 94462306a36Sopenharmony_cierr_put_ctlr: 94562306a36Sopenharmony_ci spi_controller_put(ctlr); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci return ret; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic void rockchip_spi_remove(struct platform_device *pdev) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct spi_controller *ctlr = spi_controller_get(platform_get_drvdata(pdev)); 95362306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci clk_disable_unprepare(rs->spiclk); 95862306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 96162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 96262306a36Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (ctlr->dma_tx) 96562306a36Sopenharmony_ci dma_release_channel(ctlr->dma_tx); 96662306a36Sopenharmony_ci if (ctlr->dma_rx) 96762306a36Sopenharmony_ci dma_release_channel(ctlr->dma_rx); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci spi_controller_put(ctlr); 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 97362306a36Sopenharmony_cistatic int rockchip_spi_suspend(struct device *dev) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci int ret; 97662306a36Sopenharmony_ci struct spi_controller *ctlr = dev_get_drvdata(dev); 97762306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci ret = spi_controller_suspend(ctlr); 98062306a36Sopenharmony_ci if (ret < 0) 98162306a36Sopenharmony_ci return ret; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci clk_disable_unprepare(rs->spiclk); 98462306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return 0; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic int rockchip_spi_resume(struct device *dev) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci int ret; 99462306a36Sopenharmony_ci struct spi_controller *ctlr = dev_get_drvdata(dev); 99562306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci ret = clk_prepare_enable(rs->apb_pclk); 100062306a36Sopenharmony_ci if (ret < 0) 100162306a36Sopenharmony_ci return ret; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci ret = clk_prepare_enable(rs->spiclk); 100462306a36Sopenharmony_ci if (ret < 0) 100562306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci ret = spi_controller_resume(ctlr); 100862306a36Sopenharmony_ci if (ret < 0) { 100962306a36Sopenharmony_ci clk_disable_unprepare(rs->spiclk); 101062306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci#ifdef CONFIG_PM 101862306a36Sopenharmony_cistatic int rockchip_spi_runtime_suspend(struct device *dev) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct spi_controller *ctlr = dev_get_drvdata(dev); 102162306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci clk_disable_unprepare(rs->spiclk); 102462306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci return 0; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic int rockchip_spi_runtime_resume(struct device *dev) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci int ret; 103262306a36Sopenharmony_ci struct spi_controller *ctlr = dev_get_drvdata(dev); 103362306a36Sopenharmony_ci struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci ret = clk_prepare_enable(rs->apb_pclk); 103662306a36Sopenharmony_ci if (ret < 0) 103762306a36Sopenharmony_ci return ret; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci ret = clk_prepare_enable(rs->spiclk); 104062306a36Sopenharmony_ci if (ret < 0) 104162306a36Sopenharmony_ci clk_disable_unprepare(rs->apb_pclk); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci#endif /* CONFIG_PM */ 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic const struct dev_pm_ops rockchip_spi_pm = { 104862306a36Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume) 104962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(rockchip_spi_runtime_suspend, 105062306a36Sopenharmony_ci rockchip_spi_runtime_resume, NULL) 105162306a36Sopenharmony_ci}; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic const struct of_device_id rockchip_spi_dt_match[] = { 105462306a36Sopenharmony_ci { .compatible = "rockchip,px30-spi", }, 105562306a36Sopenharmony_ci { .compatible = "rockchip,rk3036-spi", }, 105662306a36Sopenharmony_ci { .compatible = "rockchip,rk3066-spi", }, 105762306a36Sopenharmony_ci { .compatible = "rockchip,rk3188-spi", }, 105862306a36Sopenharmony_ci { .compatible = "rockchip,rk3228-spi", }, 105962306a36Sopenharmony_ci { .compatible = "rockchip,rk3288-spi", }, 106062306a36Sopenharmony_ci { .compatible = "rockchip,rk3308-spi", }, 106162306a36Sopenharmony_ci { .compatible = "rockchip,rk3328-spi", }, 106262306a36Sopenharmony_ci { .compatible = "rockchip,rk3368-spi", }, 106362306a36Sopenharmony_ci { .compatible = "rockchip,rk3399-spi", }, 106462306a36Sopenharmony_ci { .compatible = "rockchip,rv1108-spi", }, 106562306a36Sopenharmony_ci { .compatible = "rockchip,rv1126-spi", }, 106662306a36Sopenharmony_ci { }, 106762306a36Sopenharmony_ci}; 106862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_spi_dt_match); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic struct platform_driver rockchip_spi_driver = { 107162306a36Sopenharmony_ci .driver = { 107262306a36Sopenharmony_ci .name = DRIVER_NAME, 107362306a36Sopenharmony_ci .pm = &rockchip_spi_pm, 107462306a36Sopenharmony_ci .of_match_table = of_match_ptr(rockchip_spi_dt_match), 107562306a36Sopenharmony_ci }, 107662306a36Sopenharmony_ci .probe = rockchip_spi_probe, 107762306a36Sopenharmony_ci .remove_new = rockchip_spi_remove, 107862306a36Sopenharmony_ci}; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cimodule_platform_driver(rockchip_spi_driver); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ciMODULE_AUTHOR("Addy Ke <addy.ke@rock-chips.com>"); 108362306a36Sopenharmony_ciMODULE_DESCRIPTION("ROCKCHIP SPI Controller Driver"); 108462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1085