162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Rockchip Serial Flash Controller Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2017-2021, Rockchip Inc. 662306a36Sopenharmony_ci * Author: Shawn Lin <shawn.lin@rock-chips.com> 762306a36Sopenharmony_ci * Chris Morgan <macroalpha82@gmail.com> 862306a36Sopenharmony_ci * Jon Lin <Jon.lin@rock-chips.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/completion.h> 1462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1562306a36Sopenharmony_ci#include <linux/iopoll.h> 1662306a36Sopenharmony_ci#include <linux/mm.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/spi/spi-mem.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* System control */ 2562306a36Sopenharmony_ci#define SFC_CTRL 0x0 2662306a36Sopenharmony_ci#define SFC_CTRL_PHASE_SEL_NEGETIVE BIT(1) 2762306a36Sopenharmony_ci#define SFC_CTRL_CMD_BITS_SHIFT 8 2862306a36Sopenharmony_ci#define SFC_CTRL_ADDR_BITS_SHIFT 10 2962306a36Sopenharmony_ci#define SFC_CTRL_DATA_BITS_SHIFT 12 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Interrupt mask */ 3262306a36Sopenharmony_ci#define SFC_IMR 0x4 3362306a36Sopenharmony_ci#define SFC_IMR_RX_FULL BIT(0) 3462306a36Sopenharmony_ci#define SFC_IMR_RX_UFLOW BIT(1) 3562306a36Sopenharmony_ci#define SFC_IMR_TX_OFLOW BIT(2) 3662306a36Sopenharmony_ci#define SFC_IMR_TX_EMPTY BIT(3) 3762306a36Sopenharmony_ci#define SFC_IMR_TRAN_FINISH BIT(4) 3862306a36Sopenharmony_ci#define SFC_IMR_BUS_ERR BIT(5) 3962306a36Sopenharmony_ci#define SFC_IMR_NSPI_ERR BIT(6) 4062306a36Sopenharmony_ci#define SFC_IMR_DMA BIT(7) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Interrupt clear */ 4362306a36Sopenharmony_ci#define SFC_ICLR 0x8 4462306a36Sopenharmony_ci#define SFC_ICLR_RX_FULL BIT(0) 4562306a36Sopenharmony_ci#define SFC_ICLR_RX_UFLOW BIT(1) 4662306a36Sopenharmony_ci#define SFC_ICLR_TX_OFLOW BIT(2) 4762306a36Sopenharmony_ci#define SFC_ICLR_TX_EMPTY BIT(3) 4862306a36Sopenharmony_ci#define SFC_ICLR_TRAN_FINISH BIT(4) 4962306a36Sopenharmony_ci#define SFC_ICLR_BUS_ERR BIT(5) 5062306a36Sopenharmony_ci#define SFC_ICLR_NSPI_ERR BIT(6) 5162306a36Sopenharmony_ci#define SFC_ICLR_DMA BIT(7) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* FIFO threshold level */ 5462306a36Sopenharmony_ci#define SFC_FTLR 0xc 5562306a36Sopenharmony_ci#define SFC_FTLR_TX_SHIFT 0 5662306a36Sopenharmony_ci#define SFC_FTLR_TX_MASK 0x1f 5762306a36Sopenharmony_ci#define SFC_FTLR_RX_SHIFT 8 5862306a36Sopenharmony_ci#define SFC_FTLR_RX_MASK 0x1f 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Reset FSM and FIFO */ 6162306a36Sopenharmony_ci#define SFC_RCVR 0x10 6262306a36Sopenharmony_ci#define SFC_RCVR_RESET BIT(0) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Enhanced mode */ 6562306a36Sopenharmony_ci#define SFC_AX 0x14 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* Address Bit number */ 6862306a36Sopenharmony_ci#define SFC_ABIT 0x18 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Interrupt status */ 7162306a36Sopenharmony_ci#define SFC_ISR 0x1c 7262306a36Sopenharmony_ci#define SFC_ISR_RX_FULL_SHIFT BIT(0) 7362306a36Sopenharmony_ci#define SFC_ISR_RX_UFLOW_SHIFT BIT(1) 7462306a36Sopenharmony_ci#define SFC_ISR_TX_OFLOW_SHIFT BIT(2) 7562306a36Sopenharmony_ci#define SFC_ISR_TX_EMPTY_SHIFT BIT(3) 7662306a36Sopenharmony_ci#define SFC_ISR_TX_FINISH_SHIFT BIT(4) 7762306a36Sopenharmony_ci#define SFC_ISR_BUS_ERR_SHIFT BIT(5) 7862306a36Sopenharmony_ci#define SFC_ISR_NSPI_ERR_SHIFT BIT(6) 7962306a36Sopenharmony_ci#define SFC_ISR_DMA_SHIFT BIT(7) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* FIFO status */ 8262306a36Sopenharmony_ci#define SFC_FSR 0x20 8362306a36Sopenharmony_ci#define SFC_FSR_TX_IS_FULL BIT(0) 8462306a36Sopenharmony_ci#define SFC_FSR_TX_IS_EMPTY BIT(1) 8562306a36Sopenharmony_ci#define SFC_FSR_RX_IS_EMPTY BIT(2) 8662306a36Sopenharmony_ci#define SFC_FSR_RX_IS_FULL BIT(3) 8762306a36Sopenharmony_ci#define SFC_FSR_TXLV_MASK GENMASK(12, 8) 8862306a36Sopenharmony_ci#define SFC_FSR_TXLV_SHIFT 8 8962306a36Sopenharmony_ci#define SFC_FSR_RXLV_MASK GENMASK(20, 16) 9062306a36Sopenharmony_ci#define SFC_FSR_RXLV_SHIFT 16 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* FSM status */ 9362306a36Sopenharmony_ci#define SFC_SR 0x24 9462306a36Sopenharmony_ci#define SFC_SR_IS_IDLE 0x0 9562306a36Sopenharmony_ci#define SFC_SR_IS_BUSY 0x1 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Raw interrupt status */ 9862306a36Sopenharmony_ci#define SFC_RISR 0x28 9962306a36Sopenharmony_ci#define SFC_RISR_RX_FULL BIT(0) 10062306a36Sopenharmony_ci#define SFC_RISR_RX_UNDERFLOW BIT(1) 10162306a36Sopenharmony_ci#define SFC_RISR_TX_OVERFLOW BIT(2) 10262306a36Sopenharmony_ci#define SFC_RISR_TX_EMPTY BIT(3) 10362306a36Sopenharmony_ci#define SFC_RISR_TRAN_FINISH BIT(4) 10462306a36Sopenharmony_ci#define SFC_RISR_BUS_ERR BIT(5) 10562306a36Sopenharmony_ci#define SFC_RISR_NSPI_ERR BIT(6) 10662306a36Sopenharmony_ci#define SFC_RISR_DMA BIT(7) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Version */ 10962306a36Sopenharmony_ci#define SFC_VER 0x2C 11062306a36Sopenharmony_ci#define SFC_VER_3 0x3 11162306a36Sopenharmony_ci#define SFC_VER_4 0x4 11262306a36Sopenharmony_ci#define SFC_VER_5 0x5 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* Delay line controller resiter */ 11562306a36Sopenharmony_ci#define SFC_DLL_CTRL0 0x3C 11662306a36Sopenharmony_ci#define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15) 11762306a36Sopenharmony_ci#define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU 11862306a36Sopenharmony_ci#define SFC_DLL_CTRL0_DLL_MAX_VER5 0x1FFU 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* Master trigger */ 12162306a36Sopenharmony_ci#define SFC_DMA_TRIGGER 0x80 12262306a36Sopenharmony_ci#define SFC_DMA_TRIGGER_START 1 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Src or Dst addr for master */ 12562306a36Sopenharmony_ci#define SFC_DMA_ADDR 0x84 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Length control register extension 32GB */ 12862306a36Sopenharmony_ci#define SFC_LEN_CTRL 0x88 12962306a36Sopenharmony_ci#define SFC_LEN_CTRL_TRB_SEL 1 13062306a36Sopenharmony_ci#define SFC_LEN_EXT 0x8C 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* Command */ 13362306a36Sopenharmony_ci#define SFC_CMD 0x100 13462306a36Sopenharmony_ci#define SFC_CMD_IDX_SHIFT 0 13562306a36Sopenharmony_ci#define SFC_CMD_DUMMY_SHIFT 8 13662306a36Sopenharmony_ci#define SFC_CMD_DIR_SHIFT 12 13762306a36Sopenharmony_ci#define SFC_CMD_DIR_RD 0 13862306a36Sopenharmony_ci#define SFC_CMD_DIR_WR 1 13962306a36Sopenharmony_ci#define SFC_CMD_ADDR_SHIFT 14 14062306a36Sopenharmony_ci#define SFC_CMD_ADDR_0BITS 0 14162306a36Sopenharmony_ci#define SFC_CMD_ADDR_24BITS 1 14262306a36Sopenharmony_ci#define SFC_CMD_ADDR_32BITS 2 14362306a36Sopenharmony_ci#define SFC_CMD_ADDR_XBITS 3 14462306a36Sopenharmony_ci#define SFC_CMD_TRAN_BYTES_SHIFT 16 14562306a36Sopenharmony_ci#define SFC_CMD_CS_SHIFT 30 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* Address */ 14862306a36Sopenharmony_ci#define SFC_ADDR 0x104 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Data */ 15162306a36Sopenharmony_ci#define SFC_DATA 0x108 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* The controller and documentation reports that it supports up to 4 CS 15462306a36Sopenharmony_ci * devices (0-3), however I have only been able to test a single CS (CS 0) 15562306a36Sopenharmony_ci * due to the configuration of my device. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci#define SFC_MAX_CHIPSELECT_NUM 4 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* The SFC can transfer max 16KB - 1 at one time 16062306a36Sopenharmony_ci * we set it to 15.5KB here for alignment. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci#define SFC_MAX_IOSIZE_VER3 (512 * 31) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* DMA is only enabled for large data transmission */ 16562306a36Sopenharmony_ci#define SFC_DMA_TRANS_THRETHOLD (0x40) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* Maximum clock values from datasheet suggest keeping clock value under 16862306a36Sopenharmony_ci * 150MHz. No minimum or average value is suggested. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci#define SFC_MAX_SPEED (150 * 1000 * 1000) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistruct rockchip_sfc { 17362306a36Sopenharmony_ci struct device *dev; 17462306a36Sopenharmony_ci void __iomem *regbase; 17562306a36Sopenharmony_ci struct clk *hclk; 17662306a36Sopenharmony_ci struct clk *clk; 17762306a36Sopenharmony_ci u32 frequency; 17862306a36Sopenharmony_ci /* virtual mapped addr for dma_buffer */ 17962306a36Sopenharmony_ci void *buffer; 18062306a36Sopenharmony_ci dma_addr_t dma_buffer; 18162306a36Sopenharmony_ci struct completion cp; 18262306a36Sopenharmony_ci bool use_dma; 18362306a36Sopenharmony_ci u32 max_iosize; 18462306a36Sopenharmony_ci u16 version; 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int rockchip_sfc_reset(struct rockchip_sfc *sfc) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci int err; 19062306a36Sopenharmony_ci u32 status; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci writel_relaxed(SFC_RCVR_RESET, sfc->regbase + SFC_RCVR); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci err = readl_poll_timeout(sfc->regbase + SFC_RCVR, status, 19562306a36Sopenharmony_ci !(status & SFC_RCVR_RESET), 20, 19662306a36Sopenharmony_ci jiffies_to_usecs(HZ)); 19762306a36Sopenharmony_ci if (err) 19862306a36Sopenharmony_ci dev_err(sfc->dev, "SFC reset never finished\n"); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Still need to clear the masked interrupt from RISR */ 20162306a36Sopenharmony_ci writel_relaxed(0xFFFFFFFF, sfc->regbase + SFC_ICLR); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci dev_dbg(sfc->dev, "reset\n"); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return err; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic u16 rockchip_sfc_get_version(struct rockchip_sfc *sfc) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return (u16)(readl(sfc->regbase + SFC_VER) & 0xffff); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return SFC_MAX_IOSIZE_VER3; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void rockchip_sfc_irq_unmask(struct rockchip_sfc *sfc, u32 mask) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci u32 reg; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Enable transfer complete interrupt */ 22362306a36Sopenharmony_ci reg = readl(sfc->regbase + SFC_IMR); 22462306a36Sopenharmony_ci reg &= ~mask; 22562306a36Sopenharmony_ci writel(reg, sfc->regbase + SFC_IMR); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void rockchip_sfc_irq_mask(struct rockchip_sfc *sfc, u32 mask) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci u32 reg; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Disable transfer finish interrupt */ 23362306a36Sopenharmony_ci reg = readl(sfc->regbase + SFC_IMR); 23462306a36Sopenharmony_ci reg |= mask; 23562306a36Sopenharmony_ci writel(reg, sfc->regbase + SFC_IMR); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int rockchip_sfc_init(struct rockchip_sfc *sfc) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci writel(0, sfc->regbase + SFC_CTRL); 24162306a36Sopenharmony_ci writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); 24262306a36Sopenharmony_ci rockchip_sfc_irq_mask(sfc, 0xFFFFFFFF); 24362306a36Sopenharmony_ci if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) 24462306a36Sopenharmony_ci writel(SFC_LEN_CTRL_TRB_SEL, sfc->regbase + SFC_LEN_CTRL); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int rockchip_sfc_wait_txfifo_ready(struct rockchip_sfc *sfc, u32 timeout_us) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci int ret = 0; 25262306a36Sopenharmony_ci u32 status; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ret = readl_poll_timeout(sfc->regbase + SFC_FSR, status, 25562306a36Sopenharmony_ci status & SFC_FSR_TXLV_MASK, 0, 25662306a36Sopenharmony_ci timeout_us); 25762306a36Sopenharmony_ci if (ret) { 25862306a36Sopenharmony_ci dev_dbg(sfc->dev, "sfc wait tx fifo timeout\n"); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return -ETIMEDOUT; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return (status & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int rockchip_sfc_wait_rxfifo_ready(struct rockchip_sfc *sfc, u32 timeout_us) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int ret = 0; 26962306a36Sopenharmony_ci u32 status; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ret = readl_poll_timeout(sfc->regbase + SFC_FSR, status, 27262306a36Sopenharmony_ci status & SFC_FSR_RXLV_MASK, 0, 27362306a36Sopenharmony_ci timeout_us); 27462306a36Sopenharmony_ci if (ret) { 27562306a36Sopenharmony_ci dev_dbg(sfc->dev, "sfc wait rx fifo timeout\n"); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return -ETIMEDOUT; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return (status & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void rockchip_sfc_adjust_op_work(struct spi_mem_op *op) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci if (unlikely(op->dummy.nbytes && !op->addr.nbytes)) { 28662306a36Sopenharmony_ci /* 28762306a36Sopenharmony_ci * SFC not support output DUMMY cycles right after CMD cycles, so 28862306a36Sopenharmony_ci * treat it as ADDR cycles. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci op->addr.nbytes = op->dummy.nbytes; 29162306a36Sopenharmony_ci op->addr.buswidth = op->dummy.buswidth; 29262306a36Sopenharmony_ci op->addr.val = 0xFFFFFFFFF; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci op->dummy.nbytes = 0; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, 29962306a36Sopenharmony_ci struct spi_mem *mem, 30062306a36Sopenharmony_ci const struct spi_mem_op *op, 30162306a36Sopenharmony_ci u32 len) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci u32 ctrl = 0, cmd = 0; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* set CMD */ 30662306a36Sopenharmony_ci cmd = op->cmd.opcode; 30762306a36Sopenharmony_ci ctrl |= ((op->cmd.buswidth >> 1) << SFC_CTRL_CMD_BITS_SHIFT); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* set ADDR */ 31062306a36Sopenharmony_ci if (op->addr.nbytes) { 31162306a36Sopenharmony_ci if (op->addr.nbytes == 4) { 31262306a36Sopenharmony_ci cmd |= SFC_CMD_ADDR_32BITS << SFC_CMD_ADDR_SHIFT; 31362306a36Sopenharmony_ci } else if (op->addr.nbytes == 3) { 31462306a36Sopenharmony_ci cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT; 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT; 31762306a36Sopenharmony_ci writel(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* set DUMMY */ 32462306a36Sopenharmony_ci if (op->dummy.nbytes) { 32562306a36Sopenharmony_ci if (op->dummy.buswidth == 4) 32662306a36Sopenharmony_ci cmd |= op->dummy.nbytes * 2 << SFC_CMD_DUMMY_SHIFT; 32762306a36Sopenharmony_ci else if (op->dummy.buswidth == 2) 32862306a36Sopenharmony_ci cmd |= op->dummy.nbytes * 4 << SFC_CMD_DUMMY_SHIFT; 32962306a36Sopenharmony_ci else 33062306a36Sopenharmony_ci cmd |= op->dummy.nbytes * 8 << SFC_CMD_DUMMY_SHIFT; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* set DATA */ 33462306a36Sopenharmony_ci if (sfc->version >= SFC_VER_4) /* Clear it if no data to transfer */ 33562306a36Sopenharmony_ci writel(len, sfc->regbase + SFC_LEN_EXT); 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci cmd |= len << SFC_CMD_TRAN_BYTES_SHIFT; 33862306a36Sopenharmony_ci if (len) { 33962306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT) 34062306a36Sopenharmony_ci cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ctrl |= ((op->data.buswidth >> 1) << SFC_CTRL_DATA_BITS_SHIFT); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci if (!len && op->addr.nbytes) 34562306a36Sopenharmony_ci cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* set the Controller */ 34862306a36Sopenharmony_ci ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE; 34962306a36Sopenharmony_ci cmd |= spi_get_chipselect(mem->spi, 0) << SFC_CMD_CS_SHIFT; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", 35262306a36Sopenharmony_ci op->addr.nbytes, op->addr.buswidth, 35362306a36Sopenharmony_ci op->dummy.nbytes, op->dummy.buswidth); 35462306a36Sopenharmony_ci dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n", 35562306a36Sopenharmony_ci ctrl, cmd, op->addr.val, len); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci writel(ctrl, sfc->regbase + SFC_CTRL); 35862306a36Sopenharmony_ci writel(cmd, sfc->regbase + SFC_CMD); 35962306a36Sopenharmony_ci if (op->addr.nbytes) 36062306a36Sopenharmony_ci writel(op->addr.val, sfc->regbase + SFC_ADDR); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int len) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci u8 bytes = len & 0x3; 36862306a36Sopenharmony_ci u32 dwords; 36962306a36Sopenharmony_ci int tx_level; 37062306a36Sopenharmony_ci u32 write_words; 37162306a36Sopenharmony_ci u32 tmp = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci dwords = len >> 2; 37462306a36Sopenharmony_ci while (dwords) { 37562306a36Sopenharmony_ci tx_level = rockchip_sfc_wait_txfifo_ready(sfc, 1000); 37662306a36Sopenharmony_ci if (tx_level < 0) 37762306a36Sopenharmony_ci return tx_level; 37862306a36Sopenharmony_ci write_words = min_t(u32, tx_level, dwords); 37962306a36Sopenharmony_ci iowrite32_rep(sfc->regbase + SFC_DATA, buf, write_words); 38062306a36Sopenharmony_ci buf += write_words << 2; 38162306a36Sopenharmony_ci dwords -= write_words; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* write the rest non word aligned bytes */ 38562306a36Sopenharmony_ci if (bytes) { 38662306a36Sopenharmony_ci tx_level = rockchip_sfc_wait_txfifo_ready(sfc, 1000); 38762306a36Sopenharmony_ci if (tx_level < 0) 38862306a36Sopenharmony_ci return tx_level; 38962306a36Sopenharmony_ci memcpy(&tmp, buf, bytes); 39062306a36Sopenharmony_ci writel(tmp, sfc->regbase + SFC_DATA); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return len; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci u8 bytes = len & 0x3; 39962306a36Sopenharmony_ci u32 dwords; 40062306a36Sopenharmony_ci u8 read_words; 40162306a36Sopenharmony_ci int rx_level; 40262306a36Sopenharmony_ci int tmp; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* word aligned access only */ 40562306a36Sopenharmony_ci dwords = len >> 2; 40662306a36Sopenharmony_ci while (dwords) { 40762306a36Sopenharmony_ci rx_level = rockchip_sfc_wait_rxfifo_ready(sfc, 1000); 40862306a36Sopenharmony_ci if (rx_level < 0) 40962306a36Sopenharmony_ci return rx_level; 41062306a36Sopenharmony_ci read_words = min_t(u32, rx_level, dwords); 41162306a36Sopenharmony_ci ioread32_rep(sfc->regbase + SFC_DATA, buf, read_words); 41262306a36Sopenharmony_ci buf += read_words << 2; 41362306a36Sopenharmony_ci dwords -= read_words; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* read the rest non word aligned bytes */ 41762306a36Sopenharmony_ci if (bytes) { 41862306a36Sopenharmony_ci rx_level = rockchip_sfc_wait_rxfifo_ready(sfc, 1000); 41962306a36Sopenharmony_ci if (rx_level < 0) 42062306a36Sopenharmony_ci return rx_level; 42162306a36Sopenharmony_ci tmp = readl(sfc->regbase + SFC_DATA); 42262306a36Sopenharmony_ci memcpy(buf, &tmp, bytes); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return len; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int rockchip_sfc_fifo_transfer_dma(struct rockchip_sfc *sfc, dma_addr_t dma_buf, size_t len) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); 43162306a36Sopenharmony_ci writel((u32)dma_buf, sfc->regbase + SFC_DMA_ADDR); 43262306a36Sopenharmony_ci writel(SFC_DMA_TRIGGER_START, sfc->regbase + SFC_DMA_TRIGGER); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return len; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int rockchip_sfc_xfer_data_poll(struct rockchip_sfc *sfc, 43862306a36Sopenharmony_ci const struct spi_mem_op *op, u32 len) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci dev_dbg(sfc->dev, "sfc xfer_poll len=%x\n", len); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT) 44362306a36Sopenharmony_ci return rockchip_sfc_write_fifo(sfc, op->data.buf.out, len); 44462306a36Sopenharmony_ci else 44562306a36Sopenharmony_ci return rockchip_sfc_read_fifo(sfc, op->data.buf.in, len); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc, 44962306a36Sopenharmony_ci const struct spi_mem_op *op, u32 len) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci int ret; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci dev_dbg(sfc->dev, "sfc xfer_dma len=%x\n", len); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT) 45662306a36Sopenharmony_ci memcpy(sfc->buffer, op->data.buf.out, len); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ret = rockchip_sfc_fifo_transfer_dma(sfc, sfc->dma_buffer, len); 45962306a36Sopenharmony_ci if (!wait_for_completion_timeout(&sfc->cp, msecs_to_jiffies(2000))) { 46062306a36Sopenharmony_ci dev_err(sfc->dev, "DMA wait for transfer finish timeout\n"); 46162306a36Sopenharmony_ci ret = -ETIMEDOUT; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci rockchip_sfc_irq_mask(sfc, SFC_IMR_DMA); 46462306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN) 46562306a36Sopenharmony_ci memcpy(op->data.buf.in, sfc->buffer, len); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return ret; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci int ret = 0; 47362306a36Sopenharmony_ci u32 status; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = readl_poll_timeout(sfc->regbase + SFC_SR, status, 47662306a36Sopenharmony_ci !(status & SFC_SR_IS_BUSY), 47762306a36Sopenharmony_ci 20, timeout_us); 47862306a36Sopenharmony_ci if (ret) { 47962306a36Sopenharmony_ci dev_err(sfc->dev, "wait sfc idle timeout\n"); 48062306a36Sopenharmony_ci rockchip_sfc_reset(sfc); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci ret = -EIO; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return ret; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller); 49162306a36Sopenharmony_ci u32 len = op->data.nbytes; 49262306a36Sopenharmony_ci int ret; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (unlikely(mem->spi->max_speed_hz != sfc->frequency)) { 49562306a36Sopenharmony_ci ret = clk_set_rate(sfc->clk, mem->spi->max_speed_hz); 49662306a36Sopenharmony_ci if (ret) 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci sfc->frequency = mem->spi->max_speed_hz; 49962306a36Sopenharmony_ci dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%ldHz\n", 50062306a36Sopenharmony_ci sfc->frequency, clk_get_rate(sfc->clk)); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci rockchip_sfc_adjust_op_work((struct spi_mem_op *)op); 50462306a36Sopenharmony_ci rockchip_sfc_xfer_setup(sfc, mem, op, len); 50562306a36Sopenharmony_ci if (len) { 50662306a36Sopenharmony_ci if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD) { 50762306a36Sopenharmony_ci init_completion(&sfc->cp); 50862306a36Sopenharmony_ci rockchip_sfc_irq_unmask(sfc, SFC_IMR_DMA); 50962306a36Sopenharmony_ci ret = rockchip_sfc_xfer_data_dma(sfc, op, len); 51062306a36Sopenharmony_ci } else { 51162306a36Sopenharmony_ci ret = rockchip_sfc_xfer_data_poll(sfc, op, len); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (ret != len) { 51562306a36Sopenharmony_ci dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return -EIO; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return rockchip_sfc_xfer_done(sfc, 100000); 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci op->data.nbytes = min(op->data.nbytes, sfc->max_iosize); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic const struct spi_controller_mem_ops rockchip_sfc_mem_ops = { 53462306a36Sopenharmony_ci .exec_op = rockchip_sfc_exec_mem_op, 53562306a36Sopenharmony_ci .adjust_op_size = rockchip_sfc_adjust_op_size, 53662306a36Sopenharmony_ci}; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct rockchip_sfc *sfc = dev_id; 54162306a36Sopenharmony_ci u32 reg; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci reg = readl(sfc->regbase + SFC_RISR); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* Clear interrupt */ 54662306a36Sopenharmony_ci writel_relaxed(reg, sfc->regbase + SFC_ICLR); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (reg & SFC_RISR_DMA) { 54962306a36Sopenharmony_ci complete(&sfc->cp); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return IRQ_HANDLED; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return IRQ_NONE; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic int rockchip_sfc_probe(struct platform_device *pdev) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 56062306a36Sopenharmony_ci struct spi_controller *host; 56162306a36Sopenharmony_ci struct rockchip_sfc *sfc; 56262306a36Sopenharmony_ci int ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci host = devm_spi_alloc_host(&pdev->dev, sizeof(*sfc)); 56562306a36Sopenharmony_ci if (!host) 56662306a36Sopenharmony_ci return -ENOMEM; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci host->flags = SPI_CONTROLLER_HALF_DUPLEX; 56962306a36Sopenharmony_ci host->mem_ops = &rockchip_sfc_mem_ops; 57062306a36Sopenharmony_ci host->dev.of_node = pdev->dev.of_node; 57162306a36Sopenharmony_ci host->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL; 57262306a36Sopenharmony_ci host->max_speed_hz = SFC_MAX_SPEED; 57362306a36Sopenharmony_ci host->num_chipselect = SFC_MAX_CHIPSELECT_NUM; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci sfc = spi_controller_get_devdata(host); 57662306a36Sopenharmony_ci sfc->dev = dev; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci sfc->regbase = devm_platform_ioremap_resource(pdev, 0); 57962306a36Sopenharmony_ci if (IS_ERR(sfc->regbase)) 58062306a36Sopenharmony_ci return PTR_ERR(sfc->regbase); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc"); 58362306a36Sopenharmony_ci if (IS_ERR(sfc->clk)) { 58462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get sfc interface clk\n"); 58562306a36Sopenharmony_ci return PTR_ERR(sfc->clk); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc"); 58962306a36Sopenharmony_ci if (IS_ERR(sfc->hclk)) { 59062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get sfc ahb clk\n"); 59162306a36Sopenharmony_ci return PTR_ERR(sfc->hclk); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, 59562306a36Sopenharmony_ci "rockchip,sfc-no-dma"); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (sfc->use_dma) { 59862306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 59962306a36Sopenharmony_ci if (ret) { 60062306a36Sopenharmony_ci dev_warn(dev, "Unable to set dma mask\n"); 60162306a36Sopenharmony_ci return ret; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3, 60562306a36Sopenharmony_ci &sfc->dma_buffer, 60662306a36Sopenharmony_ci GFP_KERNEL); 60762306a36Sopenharmony_ci if (!sfc->buffer) 60862306a36Sopenharmony_ci return -ENOMEM; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = clk_prepare_enable(sfc->hclk); 61262306a36Sopenharmony_ci if (ret) { 61362306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable ahb clk\n"); 61462306a36Sopenharmony_ci goto err_hclk; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = clk_prepare_enable(sfc->clk); 61862306a36Sopenharmony_ci if (ret) { 61962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to enable interface clk\n"); 62062306a36Sopenharmony_ci goto err_clk; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* Find the irq */ 62462306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 62562306a36Sopenharmony_ci if (ret < 0) 62662306a36Sopenharmony_ci goto err_irq; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci ret = devm_request_irq(dev, ret, rockchip_sfc_irq_handler, 62962306a36Sopenharmony_ci 0, pdev->name, sfc); 63062306a36Sopenharmony_ci if (ret) { 63162306a36Sopenharmony_ci dev_err(dev, "Failed to request irq\n"); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci goto err_irq; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = rockchip_sfc_init(sfc); 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci goto err_irq; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc); 64162306a36Sopenharmony_ci sfc->version = rockchip_sfc_get_version(sfc); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ret = spi_register_controller(host); 64462306a36Sopenharmony_ci if (ret) 64562306a36Sopenharmony_ci goto err_irq; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cierr_irq: 65062306a36Sopenharmony_ci clk_disable_unprepare(sfc->clk); 65162306a36Sopenharmony_cierr_clk: 65262306a36Sopenharmony_ci clk_disable_unprepare(sfc->hclk); 65362306a36Sopenharmony_cierr_hclk: 65462306a36Sopenharmony_ci return ret; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void rockchip_sfc_remove(struct platform_device *pdev) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct spi_controller *host = platform_get_drvdata(pdev); 66062306a36Sopenharmony_ci struct rockchip_sfc *sfc = platform_get_drvdata(pdev); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci spi_unregister_controller(host); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci clk_disable_unprepare(sfc->clk); 66562306a36Sopenharmony_ci clk_disable_unprepare(sfc->hclk); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic const struct of_device_id rockchip_sfc_dt_ids[] = { 66962306a36Sopenharmony_ci { .compatible = "rockchip,sfc"}, 67062306a36Sopenharmony_ci { /* sentinel */ } 67162306a36Sopenharmony_ci}; 67262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_sfc_dt_ids); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic struct platform_driver rockchip_sfc_driver = { 67562306a36Sopenharmony_ci .driver = { 67662306a36Sopenharmony_ci .name = "rockchip-sfc", 67762306a36Sopenharmony_ci .of_match_table = rockchip_sfc_dt_ids, 67862306a36Sopenharmony_ci }, 67962306a36Sopenharmony_ci .probe = rockchip_sfc_probe, 68062306a36Sopenharmony_ci .remove_new = rockchip_sfc_remove, 68162306a36Sopenharmony_ci}; 68262306a36Sopenharmony_cimodule_platform_driver(rockchip_sfc_driver); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 68562306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip Serial Flash Controller Driver"); 68662306a36Sopenharmony_ciMODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>"); 68762306a36Sopenharmony_ciMODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); 68862306a36Sopenharmony_ciMODULE_AUTHOR("Jon Lin <Jon.lin@rock-chips.com>"); 689