162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Microchip coreQSPI QSPI controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018-2022 Microchip Technology Inc. and its subsidiaries 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Naga Sureshkumar Relli <nagasuresh.relli@microchip.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/iopoll.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/of_irq.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/spi/spi.h> 2262306a36Sopenharmony_ci#include <linux/spi/spi-mem.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * QSPI Control register mask defines 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci#define CONTROL_ENABLE BIT(0) 2862306a36Sopenharmony_ci#define CONTROL_MASTER BIT(1) 2962306a36Sopenharmony_ci#define CONTROL_XIP BIT(2) 3062306a36Sopenharmony_ci#define CONTROL_XIPADDR BIT(3) 3162306a36Sopenharmony_ci#define CONTROL_CLKIDLE BIT(10) 3262306a36Sopenharmony_ci#define CONTROL_SAMPLE_MASK GENMASK(12, 11) 3362306a36Sopenharmony_ci#define CONTROL_MODE0 BIT(13) 3462306a36Sopenharmony_ci#define CONTROL_MODE12_MASK GENMASK(15, 14) 3562306a36Sopenharmony_ci#define CONTROL_MODE12_EX_RO BIT(14) 3662306a36Sopenharmony_ci#define CONTROL_MODE12_EX_RW BIT(15) 3762306a36Sopenharmony_ci#define CONTROL_MODE12_FULL GENMASK(15, 14) 3862306a36Sopenharmony_ci#define CONTROL_FLAGSX4 BIT(16) 3962306a36Sopenharmony_ci#define CONTROL_CLKRATE_MASK GENMASK(27, 24) 4062306a36Sopenharmony_ci#define CONTROL_CLKRATE_SHIFT 24 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * QSPI Frames register mask defines 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci#define FRAMES_TOTALBYTES_MASK GENMASK(15, 0) 4662306a36Sopenharmony_ci#define FRAMES_CMDBYTES_MASK GENMASK(24, 16) 4762306a36Sopenharmony_ci#define FRAMES_CMDBYTES_SHIFT 16 4862306a36Sopenharmony_ci#define FRAMES_SHIFT 25 4962306a36Sopenharmony_ci#define FRAMES_IDLE_MASK GENMASK(29, 26) 5062306a36Sopenharmony_ci#define FRAMES_IDLE_SHIFT 26 5162306a36Sopenharmony_ci#define FRAMES_FLAGBYTE BIT(30) 5262306a36Sopenharmony_ci#define FRAMES_FLAGWORD BIT(31) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * QSPI Interrupt Enable register mask defines 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define IEN_TXDONE BIT(0) 5862306a36Sopenharmony_ci#define IEN_RXDONE BIT(1) 5962306a36Sopenharmony_ci#define IEN_RXAVAILABLE BIT(2) 6062306a36Sopenharmony_ci#define IEN_TXAVAILABLE BIT(3) 6162306a36Sopenharmony_ci#define IEN_RXFIFOEMPTY BIT(4) 6262306a36Sopenharmony_ci#define IEN_TXFIFOFULL BIT(5) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * QSPI Status register mask defines 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci#define STATUS_TXDONE BIT(0) 6862306a36Sopenharmony_ci#define STATUS_RXDONE BIT(1) 6962306a36Sopenharmony_ci#define STATUS_RXAVAILABLE BIT(2) 7062306a36Sopenharmony_ci#define STATUS_TXAVAILABLE BIT(3) 7162306a36Sopenharmony_ci#define STATUS_RXFIFOEMPTY BIT(4) 7262306a36Sopenharmony_ci#define STATUS_TXFIFOFULL BIT(5) 7362306a36Sopenharmony_ci#define STATUS_READY BIT(7) 7462306a36Sopenharmony_ci#define STATUS_FLAGSX4 BIT(8) 7562306a36Sopenharmony_ci#define STATUS_MASK GENMASK(8, 0) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define BYTESUPPER_MASK GENMASK(31, 16) 7862306a36Sopenharmony_ci#define BYTESLOWER_MASK GENMASK(15, 0) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define MAX_DIVIDER 16 8162306a36Sopenharmony_ci#define MIN_DIVIDER 0 8262306a36Sopenharmony_ci#define MAX_DATA_CMD_LEN 256 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* QSPI ready time out value */ 8562306a36Sopenharmony_ci#define TIMEOUT_MS 500 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* 8862306a36Sopenharmony_ci * QSPI Register offsets. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci#define REG_CONTROL (0x00) 9162306a36Sopenharmony_ci#define REG_FRAMES (0x04) 9262306a36Sopenharmony_ci#define REG_IEN (0x0c) 9362306a36Sopenharmony_ci#define REG_STATUS (0x10) 9462306a36Sopenharmony_ci#define REG_DIRECT_ACCESS (0x14) 9562306a36Sopenharmony_ci#define REG_UPPER_ACCESS (0x18) 9662306a36Sopenharmony_ci#define REG_RX_DATA (0x40) 9762306a36Sopenharmony_ci#define REG_TX_DATA (0x44) 9862306a36Sopenharmony_ci#define REG_X4_RX_DATA (0x48) 9962306a36Sopenharmony_ci#define REG_X4_TX_DATA (0x4c) 10062306a36Sopenharmony_ci#define REG_FRAMESUP (0x50) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/** 10362306a36Sopenharmony_ci * struct mchp_coreqspi - Defines qspi driver instance 10462306a36Sopenharmony_ci * @regs: Virtual address of the QSPI controller registers 10562306a36Sopenharmony_ci * @clk: QSPI Operating clock 10662306a36Sopenharmony_ci * @data_completion: completion structure 10762306a36Sopenharmony_ci * @op_lock: lock access to the device 10862306a36Sopenharmony_ci * @txbuf: TX buffer 10962306a36Sopenharmony_ci * @rxbuf: RX buffer 11062306a36Sopenharmony_ci * @irq: IRQ number 11162306a36Sopenharmony_ci * @tx_len: Number of bytes left to transfer 11262306a36Sopenharmony_ci * @rx_len: Number of bytes left to receive 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistruct mchp_coreqspi { 11562306a36Sopenharmony_ci void __iomem *regs; 11662306a36Sopenharmony_ci struct clk *clk; 11762306a36Sopenharmony_ci struct completion data_completion; 11862306a36Sopenharmony_ci struct mutex op_lock; /* lock access to the device */ 11962306a36Sopenharmony_ci u8 *txbuf; 12062306a36Sopenharmony_ci u8 *rxbuf; 12162306a36Sopenharmony_ci int irq; 12262306a36Sopenharmony_ci int tx_len; 12362306a36Sopenharmony_ci int rx_len; 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci u32 control = readl_relaxed(qspi->regs + REG_CONTROL); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * The operating mode can be configured based on the command that needs to be send. 13262306a36Sopenharmony_ci * bits[15:14]: Sets whether multiple bit SPI operates in normal, extended or full modes. 13362306a36Sopenharmony_ci * 00: Normal (single DQ0 TX and single DQ1 RX lines) 13462306a36Sopenharmony_ci * 01: Extended RO (command and address bytes on DQ0 only) 13562306a36Sopenharmony_ci * 10: Extended RW (command byte on DQ0 only) 13662306a36Sopenharmony_ci * 11: Full. (command and address are on all DQ lines) 13762306a36Sopenharmony_ci * bit[13]: Sets whether multiple bit SPI uses 2 or 4 bits of data 13862306a36Sopenharmony_ci * 0: 2-bits (BSPI) 13962306a36Sopenharmony_ci * 1: 4-bits (QSPI) 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci if (op->data.buswidth == 4 || op->data.buswidth == 2) { 14262306a36Sopenharmony_ci control &= ~CONTROL_MODE12_MASK; 14362306a36Sopenharmony_ci if (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0)) 14462306a36Sopenharmony_ci control |= CONTROL_MODE12_EX_RO; 14562306a36Sopenharmony_ci else if (op->cmd.buswidth == 1) 14662306a36Sopenharmony_ci control |= CONTROL_MODE12_EX_RW; 14762306a36Sopenharmony_ci else 14862306a36Sopenharmony_ci control |= CONTROL_MODE12_FULL; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci control |= CONTROL_MODE0; 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci control &= ~(CONTROL_MODE12_MASK | 15362306a36Sopenharmony_ci CONTROL_MODE0); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci u32 control, data; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!qspi->rx_len) 16662306a36Sopenharmony_ci return; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci control = readl_relaxed(qspi->regs + REG_CONTROL); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* 17162306a36Sopenharmony_ci * Read 4-bytes from the SPI FIFO in single transaction and then read 17262306a36Sopenharmony_ci * the reamaining data byte wise. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci control |= CONTROL_FLAGSX4; 17562306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci while (qspi->rx_len >= 4) { 17862306a36Sopenharmony_ci while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) 17962306a36Sopenharmony_ci ; 18062306a36Sopenharmony_ci data = readl_relaxed(qspi->regs + REG_X4_RX_DATA); 18162306a36Sopenharmony_ci *(u32 *)qspi->rxbuf = data; 18262306a36Sopenharmony_ci qspi->rxbuf += 4; 18362306a36Sopenharmony_ci qspi->rx_len -= 4; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci control &= ~CONTROL_FLAGSX4; 18762306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci while (qspi->rx_len--) { 19062306a36Sopenharmony_ci while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) 19162306a36Sopenharmony_ci ; 19262306a36Sopenharmony_ci data = readl_relaxed(qspi->regs + REG_RX_DATA); 19362306a36Sopenharmony_ci *qspi->rxbuf++ = (data & 0xFF); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci u32 control, data; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci control = readl_relaxed(qspi->regs + REG_CONTROL); 20262306a36Sopenharmony_ci control |= CONTROL_FLAGSX4; 20362306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci while (qspi->tx_len >= 4) { 20662306a36Sopenharmony_ci while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) 20762306a36Sopenharmony_ci ; 20862306a36Sopenharmony_ci data = *(u32 *)qspi->txbuf; 20962306a36Sopenharmony_ci qspi->txbuf += 4; 21062306a36Sopenharmony_ci qspi->tx_len -= 4; 21162306a36Sopenharmony_ci writel_relaxed(data, qspi->regs + REG_X4_TX_DATA); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci control &= ~CONTROL_FLAGSX4; 21562306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci while (qspi->tx_len--) { 21862306a36Sopenharmony_ci while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) 21962306a36Sopenharmony_ci ; 22062306a36Sopenharmony_ci data = *qspi->txbuf++; 22162306a36Sopenharmony_ci writel_relaxed(data, qspi->regs + REG_TX_DATA); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void mchp_coreqspi_enable_ints(struct mchp_coreqspi *qspi) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci u32 mask = IEN_TXDONE | 22862306a36Sopenharmony_ci IEN_RXDONE | 22962306a36Sopenharmony_ci IEN_RXAVAILABLE; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci writel_relaxed(mask, qspi->regs + REG_IEN); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void mchp_coreqspi_disable_ints(struct mchp_coreqspi *qspi) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci writel_relaxed(0, qspi->regs + REG_IEN); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct mchp_coreqspi *qspi = (struct mchp_coreqspi *)dev_id; 24262306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 24362306a36Sopenharmony_ci int intfield = readl_relaxed(qspi->regs + REG_STATUS) & STATUS_MASK; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (intfield == 0) 24662306a36Sopenharmony_ci return ret; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (intfield & IEN_TXDONE) { 24962306a36Sopenharmony_ci writel_relaxed(IEN_TXDONE, qspi->regs + REG_STATUS); 25062306a36Sopenharmony_ci ret = IRQ_HANDLED; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (intfield & IEN_RXAVAILABLE) { 25462306a36Sopenharmony_ci writel_relaxed(IEN_RXAVAILABLE, qspi->regs + REG_STATUS); 25562306a36Sopenharmony_ci mchp_coreqspi_read_op(qspi); 25662306a36Sopenharmony_ci ret = IRQ_HANDLED; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (intfield & IEN_RXDONE) { 26062306a36Sopenharmony_ci writel_relaxed(IEN_RXDONE, qspi->regs + REG_STATUS); 26162306a36Sopenharmony_ci complete(&qspi->data_completion); 26262306a36Sopenharmony_ci ret = IRQ_HANDLED; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci unsigned long clk_hz; 27162306a36Sopenharmony_ci u32 control, baud_rate_val = 0; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci clk_hz = clk_get_rate(qspi->clk); 27462306a36Sopenharmony_ci if (!clk_hz) 27562306a36Sopenharmony_ci return -EINVAL; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * spi->max_speed_hz); 27862306a36Sopenharmony_ci if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) { 27962306a36Sopenharmony_ci dev_err(&spi->dev, 28062306a36Sopenharmony_ci "could not configure the clock for spi clock %d Hz & system clock %ld Hz\n", 28162306a36Sopenharmony_ci spi->max_speed_hz, clk_hz); 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci control = readl_relaxed(qspi->regs + REG_CONTROL); 28662306a36Sopenharmony_ci control |= baud_rate_val << CONTROL_CLKRATE_SHIFT; 28762306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 28862306a36Sopenharmony_ci control = readl_relaxed(qspi->regs + REG_CONTROL); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if ((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA)) 29162306a36Sopenharmony_ci control |= CONTROL_CLKIDLE; 29262306a36Sopenharmony_ci else 29362306a36Sopenharmony_ci control &= ~CONTROL_CLKIDLE; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int mchp_coreqspi_setup_op(struct spi_device *spi_dev) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct spi_controller *ctlr = spi_dev->master; 30362306a36Sopenharmony_ci struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr); 30462306a36Sopenharmony_ci u32 control = readl_relaxed(qspi->regs + REG_CONTROL); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci control |= (CONTROL_MASTER | CONTROL_ENABLE); 30762306a36Sopenharmony_ci control &= ~CONTROL_CLKIDLE; 30862306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci u32 idle_cycles = 0; 31662306a36Sopenharmony_ci int total_bytes, cmd_bytes, frames, ctrl; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci cmd_bytes = op->cmd.nbytes + op->addr.nbytes; 31962306a36Sopenharmony_ci total_bytes = cmd_bytes + op->data.nbytes; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * As per the coreQSPI IP spec,the number of command and data bytes are 32362306a36Sopenharmony_ci * controlled by the frames register for each SPI sequence. This supports 32462306a36Sopenharmony_ci * the SPI flash memory read and writes sequences as below. so configure 32562306a36Sopenharmony_ci * the cmd and total bytes accordingly. 32662306a36Sopenharmony_ci * --------------------------------------------------------------------- 32762306a36Sopenharmony_ci * TOTAL BYTES | CMD BYTES | What happens | 32862306a36Sopenharmony_ci * ______________________________________________________________________ 32962306a36Sopenharmony_ci * | | | 33062306a36Sopenharmony_ci * 1 | 1 | The SPI core will transmit a single byte | 33162306a36Sopenharmony_ci * | | and receive data is discarded | 33262306a36Sopenharmony_ci * | | | 33362306a36Sopenharmony_ci * 1 | 0 | The SPI core will transmit a single byte | 33462306a36Sopenharmony_ci * | | and return a single byte | 33562306a36Sopenharmony_ci * | | | 33662306a36Sopenharmony_ci * 10 | 4 | The SPI core will transmit 4 command | 33762306a36Sopenharmony_ci * | | bytes discarding the receive data and | 33862306a36Sopenharmony_ci * | | transmits 6 dummy bytes returning the 6 | 33962306a36Sopenharmony_ci * | | received bytes and return a single byte | 34062306a36Sopenharmony_ci * | | | 34162306a36Sopenharmony_ci * 10 | 10 | The SPI core will transmit 10 command | 34262306a36Sopenharmony_ci * | | | 34362306a36Sopenharmony_ci * 10 | 0 | The SPI core will transmit 10 command | 34462306a36Sopenharmony_ci * | | bytes and returning 10 received bytes | 34562306a36Sopenharmony_ci * ______________________________________________________________________ 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci if (!(op->data.dir == SPI_MEM_DATA_IN)) 34862306a36Sopenharmony_ci cmd_bytes = total_bytes; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci frames = total_bytes & BYTESUPPER_MASK; 35162306a36Sopenharmony_ci writel_relaxed(frames, qspi->regs + REG_FRAMESUP); 35262306a36Sopenharmony_ci frames = total_bytes & BYTESLOWER_MASK; 35362306a36Sopenharmony_ci frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (op->dummy.buswidth) 35662306a36Sopenharmony_ci idle_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci frames |= idle_cycles << FRAMES_IDLE_SHIFT; 35962306a36Sopenharmony_ci ctrl = readl_relaxed(qspi->regs + REG_CONTROL); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (ctrl & CONTROL_MODE12_MASK) 36262306a36Sopenharmony_ci frames |= (1 << FRAMES_SHIFT); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci frames |= FRAMES_FLAGWORD; 36562306a36Sopenharmony_ci writel_relaxed(frames, qspi->regs + REG_FRAMES); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int mchp_qspi_wait_for_ready(struct spi_mem *mem) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct mchp_coreqspi *qspi = spi_controller_get_devdata 37162306a36Sopenharmony_ci (mem->spi->master); 37262306a36Sopenharmony_ci u32 status; 37362306a36Sopenharmony_ci int ret; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ret = readl_poll_timeout(qspi->regs + REG_STATUS, status, 37662306a36Sopenharmony_ci (status & STATUS_READY), 0, 37762306a36Sopenharmony_ci TIMEOUT_MS); 37862306a36Sopenharmony_ci if (ret) { 37962306a36Sopenharmony_ci dev_err(&mem->spi->dev, 38062306a36Sopenharmony_ci "Timeout waiting on QSPI ready.\n"); 38162306a36Sopenharmony_ci return -ETIMEDOUT; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return ret; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct mchp_coreqspi *qspi = spi_controller_get_devdata 39062306a36Sopenharmony_ci (mem->spi->master); 39162306a36Sopenharmony_ci u32 address = op->addr.val; 39262306a36Sopenharmony_ci u8 opcode = op->cmd.opcode; 39362306a36Sopenharmony_ci u8 opaddr[5]; 39462306a36Sopenharmony_ci int err, i; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci mutex_lock(&qspi->op_lock); 39762306a36Sopenharmony_ci err = mchp_qspi_wait_for_ready(mem); 39862306a36Sopenharmony_ci if (err) 39962306a36Sopenharmony_ci goto error; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci err = mchp_coreqspi_setup_clock(qspi, mem->spi); 40262306a36Sopenharmony_ci if (err) 40362306a36Sopenharmony_ci goto error; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci err = mchp_coreqspi_set_mode(qspi, op); 40662306a36Sopenharmony_ci if (err) 40762306a36Sopenharmony_ci goto error; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci reinit_completion(&qspi->data_completion); 41062306a36Sopenharmony_ci mchp_coreqspi_config_op(qspi, op); 41162306a36Sopenharmony_ci if (op->cmd.opcode) { 41262306a36Sopenharmony_ci qspi->txbuf = &opcode; 41362306a36Sopenharmony_ci qspi->rxbuf = NULL; 41462306a36Sopenharmony_ci qspi->tx_len = op->cmd.nbytes; 41562306a36Sopenharmony_ci qspi->rx_len = 0; 41662306a36Sopenharmony_ci mchp_coreqspi_write_op(qspi, false); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci qspi->txbuf = &opaddr[0]; 42062306a36Sopenharmony_ci if (op->addr.nbytes) { 42162306a36Sopenharmony_ci for (i = 0; i < op->addr.nbytes; i++) 42262306a36Sopenharmony_ci qspi->txbuf[i] = address >> (8 * (op->addr.nbytes - i - 1)); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci qspi->rxbuf = NULL; 42562306a36Sopenharmony_ci qspi->tx_len = op->addr.nbytes; 42662306a36Sopenharmony_ci qspi->rx_len = 0; 42762306a36Sopenharmony_ci mchp_coreqspi_write_op(qspi, false); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (op->data.nbytes) { 43162306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT) { 43262306a36Sopenharmony_ci qspi->txbuf = (u8 *)op->data.buf.out; 43362306a36Sopenharmony_ci qspi->rxbuf = NULL; 43462306a36Sopenharmony_ci qspi->rx_len = 0; 43562306a36Sopenharmony_ci qspi->tx_len = op->data.nbytes; 43662306a36Sopenharmony_ci mchp_coreqspi_write_op(qspi, true); 43762306a36Sopenharmony_ci } else { 43862306a36Sopenharmony_ci qspi->txbuf = NULL; 43962306a36Sopenharmony_ci qspi->rxbuf = (u8 *)op->data.buf.in; 44062306a36Sopenharmony_ci qspi->rx_len = op->data.nbytes; 44162306a36Sopenharmony_ci qspi->tx_len = 0; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci mchp_coreqspi_enable_ints(qspi); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&qspi->data_completion, msecs_to_jiffies(1000))) 44862306a36Sopenharmony_ci err = -ETIMEDOUT; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cierror: 45162306a36Sopenharmony_ci mutex_unlock(&qspi->op_lock); 45262306a36Sopenharmony_ci mchp_coreqspi_disable_ints(qspi); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return err; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci if (!spi_mem_default_supports_op(mem, op)) 46062306a36Sopenharmony_ci return false; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if ((op->data.buswidth == 4 || op->data.buswidth == 2) && 46362306a36Sopenharmony_ci (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0))) { 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * If the command and address are on DQ0 only, then this 46662306a36Sopenharmony_ci * controller doesn't support sending data on dual and 46762306a36Sopenharmony_ci * quad lines. but it supports reading data on dual and 46862306a36Sopenharmony_ci * quad lines with same configuration as command and 46962306a36Sopenharmony_ci * address on DQ0. 47062306a36Sopenharmony_ci * i.e. The control register[15:13] :EX_RO(read only) is 47162306a36Sopenharmony_ci * meant only for the command and address are on DQ0 but 47262306a36Sopenharmony_ci * not to write data, it is just to read. 47362306a36Sopenharmony_ci * Ex: 0x34h is Quad Load Program Data which is not 47462306a36Sopenharmony_ci * supported. Then the spi-mem layer will iterate over 47562306a36Sopenharmony_ci * each command and it will chose the supported one. 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT) 47862306a36Sopenharmony_ci return false; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return true; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int mchp_coreqspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT || op->data.dir == SPI_MEM_DATA_IN) { 48762306a36Sopenharmony_ci if (op->data.nbytes > MAX_DATA_CMD_LEN) 48862306a36Sopenharmony_ci op->data.nbytes = MAX_DATA_CMD_LEN; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = { 49562306a36Sopenharmony_ci .adjust_op_size = mchp_coreqspi_adjust_op_size, 49662306a36Sopenharmony_ci .supports_op = mchp_coreqspi_supports_op, 49762306a36Sopenharmony_ci .exec_op = mchp_coreqspi_exec_op, 49862306a36Sopenharmony_ci}; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int mchp_coreqspi_probe(struct platform_device *pdev) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct spi_controller *ctlr; 50362306a36Sopenharmony_ci struct mchp_coreqspi *qspi; 50462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 50562306a36Sopenharmony_ci struct device_node *np = dev->of_node; 50662306a36Sopenharmony_ci int ret; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*qspi)); 50962306a36Sopenharmony_ci if (!ctlr) 51062306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, -ENOMEM, 51162306a36Sopenharmony_ci "unable to allocate master for QSPI controller\n"); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci qspi = spi_controller_get_devdata(ctlr); 51462306a36Sopenharmony_ci platform_set_drvdata(pdev, qspi); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci qspi->regs = devm_platform_ioremap_resource(pdev, 0); 51762306a36Sopenharmony_ci if (IS_ERR(qspi->regs)) 51862306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs), 51962306a36Sopenharmony_ci "failed to map registers\n"); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci qspi->clk = devm_clk_get(&pdev->dev, NULL); 52262306a36Sopenharmony_ci if (IS_ERR(qspi->clk)) 52362306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk), 52462306a36Sopenharmony_ci "could not get clock\n"); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci ret = clk_prepare_enable(qspi->clk); 52762306a36Sopenharmony_ci if (ret) 52862306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, 52962306a36Sopenharmony_ci "failed to enable clock\n"); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci init_completion(&qspi->data_completion); 53262306a36Sopenharmony_ci mutex_init(&qspi->op_lock); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci qspi->irq = platform_get_irq(pdev, 0); 53562306a36Sopenharmony_ci if (qspi->irq < 0) { 53662306a36Sopenharmony_ci ret = qspi->irq; 53762306a36Sopenharmony_ci goto out; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr, 54162306a36Sopenharmony_ci IRQF_SHARED, pdev->name, qspi); 54262306a36Sopenharmony_ci if (ret) { 54362306a36Sopenharmony_ci dev_err(&pdev->dev, "request_irq failed %d\n", ret); 54462306a36Sopenharmony_ci goto out; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ctlr->bits_per_word_mask = SPI_BPW_MASK(8); 54862306a36Sopenharmony_ci ctlr->mem_ops = &mchp_coreqspi_mem_ops; 54962306a36Sopenharmony_ci ctlr->setup = mchp_coreqspi_setup_op; 55062306a36Sopenharmony_ci ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD | 55162306a36Sopenharmony_ci SPI_TX_DUAL | SPI_TX_QUAD; 55262306a36Sopenharmony_ci ctlr->dev.of_node = np; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ret = devm_spi_register_controller(&pdev->dev, ctlr); 55562306a36Sopenharmony_ci if (ret) { 55662306a36Sopenharmony_ci dev_err_probe(&pdev->dev, ret, 55762306a36Sopenharmony_ci "spi_register_controller failed\n"); 55862306a36Sopenharmony_ci goto out; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ciout: 56462306a36Sopenharmony_ci clk_disable_unprepare(qspi->clk); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return ret; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic void mchp_coreqspi_remove(struct platform_device *pdev) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct mchp_coreqspi *qspi = platform_get_drvdata(pdev); 57262306a36Sopenharmony_ci u32 control = readl_relaxed(qspi->regs + REG_CONTROL); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci mchp_coreqspi_disable_ints(qspi); 57562306a36Sopenharmony_ci control &= ~CONTROL_ENABLE; 57662306a36Sopenharmony_ci writel_relaxed(control, qspi->regs + REG_CONTROL); 57762306a36Sopenharmony_ci clk_disable_unprepare(qspi->clk); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic const struct of_device_id mchp_coreqspi_of_match[] = { 58162306a36Sopenharmony_ci { .compatible = "microchip,coreqspi-rtl-v2" }, 58262306a36Sopenharmony_ci { /* sentinel */ } 58362306a36Sopenharmony_ci}; 58462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mchp_coreqspi_of_match); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic struct platform_driver mchp_coreqspi_driver = { 58762306a36Sopenharmony_ci .probe = mchp_coreqspi_probe, 58862306a36Sopenharmony_ci .driver = { 58962306a36Sopenharmony_ci .name = "microchip,coreqspi", 59062306a36Sopenharmony_ci .of_match_table = mchp_coreqspi_of_match, 59162306a36Sopenharmony_ci }, 59262306a36Sopenharmony_ci .remove_new = mchp_coreqspi_remove, 59362306a36Sopenharmony_ci}; 59462306a36Sopenharmony_cimodule_platform_driver(mchp_coreqspi_driver); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ciMODULE_AUTHOR("Naga Sureshkumar Relli <nagasuresh.relli@microchip.com"); 59762306a36Sopenharmony_ciMODULE_DESCRIPTION("Microchip coreQSPI QSPI controller driver"); 59862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 599