18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Xilinx SPI controller driver (master mode only) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: MontaVista Software, Inc. 68c2ecf20Sopenharmony_ci * source@mvista.com 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2010 Secret Lab Technologies, Ltd. 98c2ecf20Sopenharmony_ci * Copyright (c) 2009 Intel Corporation 108c2ecf20Sopenharmony_ci * 2002-2007 (c) MontaVista Software, Inc. 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 198c2ecf20Sopenharmony_ci#include <linux/spi/spi_bitbang.h> 208c2ecf20Sopenharmony_ci#include <linux/spi/xilinx_spi.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define XILINX_SPI_MAX_CS 32 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define XILINX_SPI_NAME "xilinx_spi" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) 288c2ecf20Sopenharmony_ci * Product Specification", DS464 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci#define XSPI_CR_OFFSET 0x60 /* Control Register */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define XSPI_CR_LOOP 0x01 338c2ecf20Sopenharmony_ci#define XSPI_CR_ENABLE 0x02 348c2ecf20Sopenharmony_ci#define XSPI_CR_MASTER_MODE 0x04 358c2ecf20Sopenharmony_ci#define XSPI_CR_CPOL 0x08 368c2ecf20Sopenharmony_ci#define XSPI_CR_CPHA 0x10 378c2ecf20Sopenharmony_ci#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \ 388c2ecf20Sopenharmony_ci XSPI_CR_LSB_FIRST | XSPI_CR_LOOP) 398c2ecf20Sopenharmony_ci#define XSPI_CR_TXFIFO_RESET 0x20 408c2ecf20Sopenharmony_ci#define XSPI_CR_RXFIFO_RESET 0x40 418c2ecf20Sopenharmony_ci#define XSPI_CR_MANUAL_SSELECT 0x80 428c2ecf20Sopenharmony_ci#define XSPI_CR_TRANS_INHIBIT 0x100 438c2ecf20Sopenharmony_ci#define XSPI_CR_LSB_FIRST 0x200 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define XSPI_SR_OFFSET 0x64 /* Status Register */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */ 488c2ecf20Sopenharmony_ci#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */ 498c2ecf20Sopenharmony_ci#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */ 508c2ecf20Sopenharmony_ci#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */ 518c2ecf20Sopenharmony_ci#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define XSPI_TXD_OFFSET 0x68 /* Data Transmit Register */ 548c2ecf20Sopenharmony_ci#define XSPI_RXD_OFFSET 0x6c /* Data Receive Register */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414 598c2ecf20Sopenharmony_ci * IPIF registers are 32 bit 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */ 628c2ecf20Sopenharmony_ci#define XIPIF_V123B_GINTR_ENABLE 0x80000000 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */ 658c2ecf20Sopenharmony_ci#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */ 688c2ecf20Sopenharmony_ci#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while 698c2ecf20Sopenharmony_ci * disabled */ 708c2ecf20Sopenharmony_ci#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */ 718c2ecf20Sopenharmony_ci#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */ 728c2ecf20Sopenharmony_ci#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */ 738c2ecf20Sopenharmony_ci#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */ 748c2ecf20Sopenharmony_ci#define XSPI_INTR_TX_HALF_EMPTY 0x40 /* TxFIFO is half empty */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */ 778c2ecf20Sopenharmony_ci#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct xilinx_spi { 808c2ecf20Sopenharmony_ci /* bitbang has to be first */ 818c2ecf20Sopenharmony_ci struct spi_bitbang bitbang; 828c2ecf20Sopenharmony_ci struct completion done; 838c2ecf20Sopenharmony_ci void __iomem *regs; /* virt. address of the control registers */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci int irq; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci u8 *rx_ptr; /* pointer in the Tx buffer */ 888c2ecf20Sopenharmony_ci const u8 *tx_ptr; /* pointer in the Rx buffer */ 898c2ecf20Sopenharmony_ci u8 bytes_per_word; 908c2ecf20Sopenharmony_ci int buffer_size; /* buffer size in words */ 918c2ecf20Sopenharmony_ci u32 cs_inactive; /* Level of the CS pins when inactive*/ 928c2ecf20Sopenharmony_ci unsigned int (*read_fn)(void __iomem *); 938c2ecf20Sopenharmony_ci void (*write_fn)(u32, void __iomem *); 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void xspi_write32(u32 val, void __iomem *addr) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci iowrite32(val, addr); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic unsigned int xspi_read32(void __iomem *addr) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci return ioread32(addr); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void xspi_write32_be(u32 val, void __iomem *addr) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci iowrite32be(val, addr); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic unsigned int xspi_read32_be(void __iomem *addr) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return ioread32be(addr); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void xilinx_spi_tx(struct xilinx_spi *xspi) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci u32 data = 0; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (!xspi->tx_ptr) { 1218c2ecf20Sopenharmony_ci xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci switch (xspi->bytes_per_word) { 1268c2ecf20Sopenharmony_ci case 1: 1278c2ecf20Sopenharmony_ci data = *(u8 *)(xspi->tx_ptr); 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci case 2: 1308c2ecf20Sopenharmony_ci data = *(u16 *)(xspi->tx_ptr); 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci case 4: 1338c2ecf20Sopenharmony_ci data = *(u32 *)(xspi->tx_ptr); 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET); 1388c2ecf20Sopenharmony_ci xspi->tx_ptr += xspi->bytes_per_word; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void xilinx_spi_rx(struct xilinx_spi *xspi) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!xspi->rx_ptr) 1468c2ecf20Sopenharmony_ci return; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci switch (xspi->bytes_per_word) { 1498c2ecf20Sopenharmony_ci case 1: 1508c2ecf20Sopenharmony_ci *(u8 *)(xspi->rx_ptr) = data; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case 2: 1538c2ecf20Sopenharmony_ci *(u16 *)(xspi->rx_ptr) = data; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case 4: 1568c2ecf20Sopenharmony_ci *(u32 *)(xspi->rx_ptr) = data; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci xspi->rx_ptr += xspi->bytes_per_word; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void xspi_init_hw(struct xilinx_spi *xspi) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci void __iomem *regs_base = xspi->regs; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Reset the SPI device */ 1688c2ecf20Sopenharmony_ci xspi->write_fn(XIPIF_V123B_RESET_MASK, 1698c2ecf20Sopenharmony_ci regs_base + XIPIF_V123B_RESETR_OFFSET); 1708c2ecf20Sopenharmony_ci /* Enable the transmit empty interrupt, which we use to determine 1718c2ecf20Sopenharmony_ci * progress on the transmission. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci xspi->write_fn(XSPI_INTR_TX_EMPTY, 1748c2ecf20Sopenharmony_ci regs_base + XIPIF_V123B_IIER_OFFSET); 1758c2ecf20Sopenharmony_ci /* Disable the global IPIF interrupt */ 1768c2ecf20Sopenharmony_ci xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); 1778c2ecf20Sopenharmony_ci /* Deselect the slave on the SPI bus */ 1788c2ecf20Sopenharmony_ci xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); 1798c2ecf20Sopenharmony_ci /* Disable the transmitter, enable Manual Slave Select Assertion, 1808c2ecf20Sopenharmony_ci * put SPI controller into master mode, and enable it */ 1818c2ecf20Sopenharmony_ci xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE | 1828c2ecf20Sopenharmony_ci XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET, 1838c2ecf20Sopenharmony_ci regs_base + XSPI_CR_OFFSET); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void xilinx_spi_chipselect(struct spi_device *spi, int is_on) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); 1898c2ecf20Sopenharmony_ci u16 cr; 1908c2ecf20Sopenharmony_ci u32 cs; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (is_on == BITBANG_CS_INACTIVE) { 1938c2ecf20Sopenharmony_ci /* Deselect the slave on the SPI bus */ 1948c2ecf20Sopenharmony_ci xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET); 1958c2ecf20Sopenharmony_ci return; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Set the SPI clock phase and polarity */ 1998c2ecf20Sopenharmony_ci cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_MODE_MASK; 2008c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPHA) 2018c2ecf20Sopenharmony_ci cr |= XSPI_CR_CPHA; 2028c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 2038c2ecf20Sopenharmony_ci cr |= XSPI_CR_CPOL; 2048c2ecf20Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) 2058c2ecf20Sopenharmony_ci cr |= XSPI_CR_LSB_FIRST; 2068c2ecf20Sopenharmony_ci if (spi->mode & SPI_LOOP) 2078c2ecf20Sopenharmony_ci cr |= XSPI_CR_LOOP; 2088c2ecf20Sopenharmony_ci xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* We do not check spi->max_speed_hz here as the SPI clock 2118c2ecf20Sopenharmony_ci * frequency is not software programmable (the IP block design 2128c2ecf20Sopenharmony_ci * parameter) 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci cs = xspi->cs_inactive; 2168c2ecf20Sopenharmony_ci cs ^= BIT(spi->chip_select); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Activate the chip select */ 2198c2ecf20Sopenharmony_ci xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* spi_bitbang requires custom setup_transfer() to be defined if there is a 2238c2ecf20Sopenharmony_ci * custom txrx_bufs(). 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistatic int xilinx_spi_setup_transfer(struct spi_device *spi, 2268c2ecf20Sopenharmony_ci struct spi_transfer *t) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (spi->mode & SPI_CS_HIGH) 2318c2ecf20Sopenharmony_ci xspi->cs_inactive &= ~BIT(spi->chip_select); 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci xspi->cs_inactive |= BIT(spi->chip_select); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); 2418c2ecf20Sopenharmony_ci int remaining_words; /* the number of words left to transfer */ 2428c2ecf20Sopenharmony_ci bool use_irq = false; 2438c2ecf20Sopenharmony_ci u16 cr = 0; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* We get here with transmitter inhibited */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci xspi->tx_ptr = t->tx_buf; 2488c2ecf20Sopenharmony_ci xspi->rx_ptr = t->rx_buf; 2498c2ecf20Sopenharmony_ci remaining_words = t->len / xspi->bytes_per_word; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) { 2528c2ecf20Sopenharmony_ci u32 isr; 2538c2ecf20Sopenharmony_ci use_irq = true; 2548c2ecf20Sopenharmony_ci /* Inhibit irq to avoid spurious irqs on tx_empty*/ 2558c2ecf20Sopenharmony_ci cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); 2568c2ecf20Sopenharmony_ci xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, 2578c2ecf20Sopenharmony_ci xspi->regs + XSPI_CR_OFFSET); 2588c2ecf20Sopenharmony_ci /* ACK old irqs (if any) */ 2598c2ecf20Sopenharmony_ci isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET); 2608c2ecf20Sopenharmony_ci if (isr) 2618c2ecf20Sopenharmony_ci xspi->write_fn(isr, 2628c2ecf20Sopenharmony_ci xspi->regs + XIPIF_V123B_IISR_OFFSET); 2638c2ecf20Sopenharmony_ci /* Enable the global IPIF interrupt */ 2648c2ecf20Sopenharmony_ci xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, 2658c2ecf20Sopenharmony_ci xspi->regs + XIPIF_V123B_DGIER_OFFSET); 2668c2ecf20Sopenharmony_ci reinit_completion(&xspi->done); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci while (remaining_words) { 2708c2ecf20Sopenharmony_ci int n_words, tx_words, rx_words; 2718c2ecf20Sopenharmony_ci u32 sr; 2728c2ecf20Sopenharmony_ci int stalled; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci n_words = min(remaining_words, xspi->buffer_size); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci tx_words = n_words; 2778c2ecf20Sopenharmony_ci while (tx_words--) 2788c2ecf20Sopenharmony_ci xilinx_spi_tx(xspi); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Start the transfer by not inhibiting the transmitter any 2818c2ecf20Sopenharmony_ci * longer 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (use_irq) { 2858c2ecf20Sopenharmony_ci xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); 2868c2ecf20Sopenharmony_ci wait_for_completion(&xspi->done); 2878c2ecf20Sopenharmony_ci /* A transmit has just completed. Process received data 2888c2ecf20Sopenharmony_ci * and check for more data to transmit. Always inhibit 2898c2ecf20Sopenharmony_ci * the transmitter while the Isr refills the transmit 2908c2ecf20Sopenharmony_ci * register/FIFO, or make sure it is stopped if we're 2918c2ecf20Sopenharmony_ci * done. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, 2948c2ecf20Sopenharmony_ci xspi->regs + XSPI_CR_OFFSET); 2958c2ecf20Sopenharmony_ci sr = XSPI_SR_TX_EMPTY_MASK; 2968c2ecf20Sopenharmony_ci } else 2978c2ecf20Sopenharmony_ci sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Read out all the data from the Rx FIFO */ 3008c2ecf20Sopenharmony_ci rx_words = n_words; 3018c2ecf20Sopenharmony_ci stalled = 10; 3028c2ecf20Sopenharmony_ci while (rx_words) { 3038c2ecf20Sopenharmony_ci if (rx_words == n_words && !(stalled--) && 3048c2ecf20Sopenharmony_ci !(sr & XSPI_SR_TX_EMPTY_MASK) && 3058c2ecf20Sopenharmony_ci (sr & XSPI_SR_RX_EMPTY_MASK)) { 3068c2ecf20Sopenharmony_ci dev_err(&spi->dev, 3078c2ecf20Sopenharmony_ci "Detected stall. Check C_SPI_MODE and C_SPI_MEMORY\n"); 3088c2ecf20Sopenharmony_ci xspi_init_hw(xspi); 3098c2ecf20Sopenharmony_ci return -EIO; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) { 3138c2ecf20Sopenharmony_ci xilinx_spi_rx(xspi); 3148c2ecf20Sopenharmony_ci rx_words--; 3158c2ecf20Sopenharmony_ci continue; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); 3198c2ecf20Sopenharmony_ci if (!(sr & XSPI_SR_RX_EMPTY_MASK)) { 3208c2ecf20Sopenharmony_ci xilinx_spi_rx(xspi); 3218c2ecf20Sopenharmony_ci rx_words--; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci remaining_words -= n_words; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (use_irq) { 3298c2ecf20Sopenharmony_ci xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET); 3308c2ecf20Sopenharmony_ci xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return t->len; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* This driver supports single master mode only. Hence Tx FIFO Empty 3388c2ecf20Sopenharmony_ci * is the only interrupt we care about. 3398c2ecf20Sopenharmony_ci * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode 3408c2ecf20Sopenharmony_ci * Fault are not to happen. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_cistatic irqreturn_t xilinx_spi_irq(int irq, void *dev_id) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct xilinx_spi *xspi = dev_id; 3458c2ecf20Sopenharmony_ci u32 ipif_isr; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Get the IPIF interrupts, and clear them immediately */ 3488c2ecf20Sopenharmony_ci ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET); 3498c2ecf20Sopenharmony_ci xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ 3528c2ecf20Sopenharmony_ci complete(&xspi->done); 3538c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return IRQ_NONE; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci u8 sr; 3628c2ecf20Sopenharmony_ci int n_words = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Before the buffer_size detection we reset the core 3668c2ecf20Sopenharmony_ci * to make sure we start with a clean state. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci xspi->write_fn(XIPIF_V123B_RESET_MASK, 3698c2ecf20Sopenharmony_ci xspi->regs + XIPIF_V123B_RESETR_OFFSET); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Fill the Tx FIFO with as many words as possible */ 3728c2ecf20Sopenharmony_ci do { 3738c2ecf20Sopenharmony_ci xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); 3748c2ecf20Sopenharmony_ci sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); 3758c2ecf20Sopenharmony_ci n_words++; 3768c2ecf20Sopenharmony_ci } while (!(sr & XSPI_SR_TX_FULL_MASK)); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return n_words; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic const struct of_device_id xilinx_spi_of_match[] = { 3828c2ecf20Sopenharmony_ci { .compatible = "xlnx,axi-quad-spi-1.00.a", }, 3838c2ecf20Sopenharmony_ci { .compatible = "xlnx,xps-spi-2.00.a", }, 3848c2ecf20Sopenharmony_ci { .compatible = "xlnx,xps-spi-2.00.b", }, 3858c2ecf20Sopenharmony_ci {} 3868c2ecf20Sopenharmony_ci}; 3878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xilinx_spi_of_match); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int xilinx_spi_probe(struct platform_device *pdev) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct xilinx_spi *xspi; 3928c2ecf20Sopenharmony_ci struct xspi_platform_data *pdata; 3938c2ecf20Sopenharmony_ci struct resource *res; 3948c2ecf20Sopenharmony_ci int ret, num_cs = 0, bits_per_word; 3958c2ecf20Sopenharmony_ci struct spi_master *master; 3968c2ecf20Sopenharmony_ci u32 tmp; 3978c2ecf20Sopenharmony_ci u8 i; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&pdev->dev); 4008c2ecf20Sopenharmony_ci if (pdata) { 4018c2ecf20Sopenharmony_ci num_cs = pdata->num_chipselect; 4028c2ecf20Sopenharmony_ci bits_per_word = pdata->bits_per_word; 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits", 4058c2ecf20Sopenharmony_ci &num_cs); 4068c2ecf20Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, 4078c2ecf20Sopenharmony_ci "xlnx,num-transfer-bits", 4088c2ecf20Sopenharmony_ci &bits_per_word); 4098c2ecf20Sopenharmony_ci if (ret) 4108c2ecf20Sopenharmony_ci bits_per_word = 8; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!num_cs) { 4148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4158c2ecf20Sopenharmony_ci "Missing slave select configuration data\n"); 4168c2ecf20Sopenharmony_ci return -EINVAL; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (num_cs > XILINX_SPI_MAX_CS) { 4208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Invalid number of spi slaves\n"); 4218c2ecf20Sopenharmony_ci return -EINVAL; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); 4258c2ecf20Sopenharmony_ci if (!master) 4268c2ecf20Sopenharmony_ci return -ENODEV; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* the spi->mode bits understood by this driver: */ 4298c2ecf20Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | 4308c2ecf20Sopenharmony_ci SPI_CS_HIGH; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci xspi = spi_master_get_devdata(master); 4338c2ecf20Sopenharmony_ci xspi->cs_inactive = 0xffffffff; 4348c2ecf20Sopenharmony_ci xspi->bitbang.master = master; 4358c2ecf20Sopenharmony_ci xspi->bitbang.chipselect = xilinx_spi_chipselect; 4368c2ecf20Sopenharmony_ci xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; 4378c2ecf20Sopenharmony_ci xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; 4388c2ecf20Sopenharmony_ci init_completion(&xspi->done); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4418c2ecf20Sopenharmony_ci xspi->regs = devm_ioremap_resource(&pdev->dev, res); 4428c2ecf20Sopenharmony_ci if (IS_ERR(xspi->regs)) { 4438c2ecf20Sopenharmony_ci ret = PTR_ERR(xspi->regs); 4448c2ecf20Sopenharmony_ci goto put_master; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci master->bus_num = pdev->id; 4488c2ecf20Sopenharmony_ci master->num_chipselect = num_cs; 4498c2ecf20Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* 4528c2ecf20Sopenharmony_ci * Detect endianess on the IP via loop bit in CR. Detection 4538c2ecf20Sopenharmony_ci * must be done before reset is sent because incorrect reset 4548c2ecf20Sopenharmony_ci * value generates error interrupt. 4558c2ecf20Sopenharmony_ci * Setup little endian helper functions first and try to use them 4568c2ecf20Sopenharmony_ci * and check if bit was correctly setup or not. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci xspi->read_fn = xspi_read32; 4598c2ecf20Sopenharmony_ci xspi->write_fn = xspi_write32; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET); 4628c2ecf20Sopenharmony_ci tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); 4638c2ecf20Sopenharmony_ci tmp &= XSPI_CR_LOOP; 4648c2ecf20Sopenharmony_ci if (tmp != XSPI_CR_LOOP) { 4658c2ecf20Sopenharmony_ci xspi->read_fn = xspi_read32_be; 4668c2ecf20Sopenharmony_ci xspi->write_fn = xspi_write32_be; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); 4708c2ecf20Sopenharmony_ci xspi->bytes_per_word = bits_per_word / 8; 4718c2ecf20Sopenharmony_ci xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci xspi->irq = platform_get_irq(pdev, 0); 4748c2ecf20Sopenharmony_ci if (xspi->irq < 0 && xspi->irq != -ENXIO) { 4758c2ecf20Sopenharmony_ci ret = xspi->irq; 4768c2ecf20Sopenharmony_ci goto put_master; 4778c2ecf20Sopenharmony_ci } else if (xspi->irq >= 0) { 4788c2ecf20Sopenharmony_ci /* Register for SPI Interrupt */ 4798c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, 4808c2ecf20Sopenharmony_ci dev_name(&pdev->dev), xspi); 4818c2ecf20Sopenharmony_ci if (ret) 4828c2ecf20Sopenharmony_ci goto put_master; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* SPI controller initializations */ 4868c2ecf20Sopenharmony_ci xspi_init_hw(xspi); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = spi_bitbang_start(&xspi->bitbang); 4898c2ecf20Sopenharmony_ci if (ret) { 4908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); 4918c2ecf20Sopenharmony_ci goto put_master; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "at %pR, irq=%d\n", res, xspi->irq); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (pdata) { 4978c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_devices; i++) 4988c2ecf20Sopenharmony_ci spi_new_device(master, pdata->devices + i); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, master); 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ciput_master: 5058c2ecf20Sopenharmony_ci spi_master_put(master); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return ret; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int xilinx_spi_remove(struct platform_device *pdev) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct spi_master *master = platform_get_drvdata(pdev); 5138c2ecf20Sopenharmony_ci struct xilinx_spi *xspi = spi_master_get_devdata(master); 5148c2ecf20Sopenharmony_ci void __iomem *regs_base = xspi->regs; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci spi_bitbang_stop(&xspi->bitbang); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Disable all the interrupts just in case */ 5198c2ecf20Sopenharmony_ci xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); 5208c2ecf20Sopenharmony_ci /* Disable the global IPIF interrupt */ 5218c2ecf20Sopenharmony_ci xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci spi_master_put(xspi->bitbang.master); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/* work with hotplug and coldplug */ 5298c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" XILINX_SPI_NAME); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic struct platform_driver xilinx_spi_driver = { 5328c2ecf20Sopenharmony_ci .probe = xilinx_spi_probe, 5338c2ecf20Sopenharmony_ci .remove = xilinx_spi_remove, 5348c2ecf20Sopenharmony_ci .driver = { 5358c2ecf20Sopenharmony_ci .name = XILINX_SPI_NAME, 5368c2ecf20Sopenharmony_ci .of_match_table = xilinx_spi_of_match, 5378c2ecf20Sopenharmony_ci }, 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_cimodule_platform_driver(xilinx_spi_driver); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ciMODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); 5428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xilinx SPI driver"); 5438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 544