18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell Armada-3700 SPI controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Marvell Ltd. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Wilson Ding <dingwei@marvell.com> 88c2ecf20Sopenharmony_ci * Author: Romain Perier <romain.perier@free-electrons.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/completion.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/of.h> 208c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 218c2ecf20Sopenharmony_ci#include <linux/of_device.h> 228c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 238c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DRIVER_NAME "armada_3700_spi" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define A3700_SPI_MAX_SPEED_HZ 100000000 288c2ecf20Sopenharmony_ci#define A3700_SPI_MAX_PRESCALE 30 298c2ecf20Sopenharmony_ci#define A3700_SPI_TIMEOUT 10 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* SPI Register Offest */ 328c2ecf20Sopenharmony_ci#define A3700_SPI_IF_CTRL_REG 0x00 338c2ecf20Sopenharmony_ci#define A3700_SPI_IF_CFG_REG 0x04 348c2ecf20Sopenharmony_ci#define A3700_SPI_DATA_OUT_REG 0x08 358c2ecf20Sopenharmony_ci#define A3700_SPI_DATA_IN_REG 0x0C 368c2ecf20Sopenharmony_ci#define A3700_SPI_IF_INST_REG 0x10 378c2ecf20Sopenharmony_ci#define A3700_SPI_IF_ADDR_REG 0x14 388c2ecf20Sopenharmony_ci#define A3700_SPI_IF_RMODE_REG 0x18 398c2ecf20Sopenharmony_ci#define A3700_SPI_IF_HDR_CNT_REG 0x1C 408c2ecf20Sopenharmony_ci#define A3700_SPI_IF_DIN_CNT_REG 0x20 418c2ecf20Sopenharmony_ci#define A3700_SPI_IF_TIME_REG 0x24 428c2ecf20Sopenharmony_ci#define A3700_SPI_INT_STAT_REG 0x28 438c2ecf20Sopenharmony_ci#define A3700_SPI_INT_MASK_REG 0x2C 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* A3700_SPI_IF_CTRL_REG */ 468c2ecf20Sopenharmony_ci#define A3700_SPI_EN BIT(16) 478c2ecf20Sopenharmony_ci#define A3700_SPI_ADDR_NOT_CONFIG BIT(12) 488c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_OVERFLOW BIT(11) 498c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_UNDERFLOW BIT(10) 508c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_OVERFLOW BIT(9) 518c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_UNDERFLOW BIT(8) 528c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_FULL BIT(7) 538c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_EMPTY BIT(6) 548c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_FULL BIT(5) 558c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_EMPTY BIT(4) 568c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_RDY BIT(3) 578c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_RDY BIT(2) 588c2ecf20Sopenharmony_ci#define A3700_SPI_XFER_RDY BIT(1) 598c2ecf20Sopenharmony_ci#define A3700_SPI_XFER_DONE BIT(0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* A3700_SPI_IF_CFG_REG */ 628c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_THRS BIT(28) 638c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_THRS BIT(24) 648c2ecf20Sopenharmony_ci#define A3700_SPI_AUTO_CS BIT(20) 658c2ecf20Sopenharmony_ci#define A3700_SPI_DMA_RD_EN BIT(18) 668c2ecf20Sopenharmony_ci#define A3700_SPI_FIFO_MODE BIT(17) 678c2ecf20Sopenharmony_ci#define A3700_SPI_SRST BIT(16) 688c2ecf20Sopenharmony_ci#define A3700_SPI_XFER_START BIT(15) 698c2ecf20Sopenharmony_ci#define A3700_SPI_XFER_STOP BIT(14) 708c2ecf20Sopenharmony_ci#define A3700_SPI_INST_PIN BIT(13) 718c2ecf20Sopenharmony_ci#define A3700_SPI_ADDR_PIN BIT(12) 728c2ecf20Sopenharmony_ci#define A3700_SPI_DATA_PIN1 BIT(11) 738c2ecf20Sopenharmony_ci#define A3700_SPI_DATA_PIN0 BIT(10) 748c2ecf20Sopenharmony_ci#define A3700_SPI_FIFO_FLUSH BIT(9) 758c2ecf20Sopenharmony_ci#define A3700_SPI_RW_EN BIT(8) 768c2ecf20Sopenharmony_ci#define A3700_SPI_CLK_POL BIT(7) 778c2ecf20Sopenharmony_ci#define A3700_SPI_CLK_PHA BIT(6) 788c2ecf20Sopenharmony_ci#define A3700_SPI_BYTE_LEN BIT(5) 798c2ecf20Sopenharmony_ci#define A3700_SPI_CLK_PRESCALE BIT(0) 808c2ecf20Sopenharmony_ci#define A3700_SPI_CLK_PRESCALE_MASK (0x1f) 818c2ecf20Sopenharmony_ci#define A3700_SPI_CLK_EVEN_OFFS (0x10) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define A3700_SPI_WFIFO_THRS_BIT 28 848c2ecf20Sopenharmony_ci#define A3700_SPI_RFIFO_THRS_BIT 24 858c2ecf20Sopenharmony_ci#define A3700_SPI_FIFO_THRS_MASK 0x7 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define A3700_SPI_DATA_PIN_MASK 0x3 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* A3700_SPI_IF_HDR_CNT_REG */ 908c2ecf20Sopenharmony_ci#define A3700_SPI_DUMMY_CNT_BIT 12 918c2ecf20Sopenharmony_ci#define A3700_SPI_DUMMY_CNT_MASK 0x7 928c2ecf20Sopenharmony_ci#define A3700_SPI_RMODE_CNT_BIT 8 938c2ecf20Sopenharmony_ci#define A3700_SPI_RMODE_CNT_MASK 0x3 948c2ecf20Sopenharmony_ci#define A3700_SPI_ADDR_CNT_BIT 4 958c2ecf20Sopenharmony_ci#define A3700_SPI_ADDR_CNT_MASK 0x7 968c2ecf20Sopenharmony_ci#define A3700_SPI_INSTR_CNT_BIT 0 978c2ecf20Sopenharmony_ci#define A3700_SPI_INSTR_CNT_MASK 0x3 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* A3700_SPI_IF_TIME_REG */ 1008c2ecf20Sopenharmony_ci#define A3700_SPI_CLK_CAPT_EDGE BIT(7) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct a3700_spi { 1038c2ecf20Sopenharmony_ci struct spi_master *master; 1048c2ecf20Sopenharmony_ci void __iomem *base; 1058c2ecf20Sopenharmony_ci struct clk *clk; 1068c2ecf20Sopenharmony_ci unsigned int irq; 1078c2ecf20Sopenharmony_ci unsigned int flags; 1088c2ecf20Sopenharmony_ci bool xmit_data; 1098c2ecf20Sopenharmony_ci const u8 *tx_buf; 1108c2ecf20Sopenharmony_ci u8 *rx_buf; 1118c2ecf20Sopenharmony_ci size_t buf_len; 1128c2ecf20Sopenharmony_ci u8 byte_len; 1138c2ecf20Sopenharmony_ci u32 wait_mask; 1148c2ecf20Sopenharmony_ci struct completion done; 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return readl(a3700_spi->base + offset); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void spireg_write(struct a3700_spi *a3700_spi, u32 offset, u32 data) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci writel(data, a3700_spi->base + offset); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void a3700_spi_auto_cs_unset(struct a3700_spi *a3700_spi) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci u32 val; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 1328c2ecf20Sopenharmony_ci val &= ~A3700_SPI_AUTO_CS; 1338c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void a3700_spi_activate_cs(struct a3700_spi *a3700_spi, unsigned int cs) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci u32 val; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); 1418c2ecf20Sopenharmony_ci val |= (A3700_SPI_EN << cs); 1428c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CTRL_REG, val); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi, 1468c2ecf20Sopenharmony_ci unsigned int cs) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci u32 val; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); 1518c2ecf20Sopenharmony_ci val &= ~(A3700_SPI_EN << cs); 1528c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CTRL_REG, val); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, 1568c2ecf20Sopenharmony_ci unsigned int pin_mode, bool receiving) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci u32 val; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 1618c2ecf20Sopenharmony_ci val &= ~(A3700_SPI_INST_PIN | A3700_SPI_ADDR_PIN); 1628c2ecf20Sopenharmony_ci val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci switch (pin_mode) { 1658c2ecf20Sopenharmony_ci case SPI_NBITS_SINGLE: 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case SPI_NBITS_DUAL: 1688c2ecf20Sopenharmony_ci val |= A3700_SPI_DATA_PIN0; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case SPI_NBITS_QUAD: 1718c2ecf20Sopenharmony_ci val |= A3700_SPI_DATA_PIN1; 1728c2ecf20Sopenharmony_ci /* RX during address reception uses 4-pin */ 1738c2ecf20Sopenharmony_ci if (receiving) 1748c2ecf20Sopenharmony_ci val |= A3700_SPI_ADDR_PIN; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci default: 1778c2ecf20Sopenharmony_ci dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode); 1788c2ecf20Sopenharmony_ci return -EINVAL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi, bool enable) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u32 val; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 1918c2ecf20Sopenharmony_ci if (enable) 1928c2ecf20Sopenharmony_ci val |= A3700_SPI_FIFO_MODE; 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci val &= ~A3700_SPI_FIFO_MODE; 1958c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void a3700_spi_mode_set(struct a3700_spi *a3700_spi, 1998c2ecf20Sopenharmony_ci unsigned int mode_bits) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci u32 val; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (mode_bits & SPI_CPOL) 2068c2ecf20Sopenharmony_ci val |= A3700_SPI_CLK_POL; 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci val &= ~A3700_SPI_CLK_POL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (mode_bits & SPI_CPHA) 2118c2ecf20Sopenharmony_ci val |= A3700_SPI_CLK_PHA; 2128c2ecf20Sopenharmony_ci else 2138c2ecf20Sopenharmony_ci val &= ~A3700_SPI_CLK_PHA; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void a3700_spi_clock_set(struct a3700_spi *a3700_spi, 2198c2ecf20Sopenharmony_ci unsigned int speed_hz) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci u32 val; 2228c2ecf20Sopenharmony_ci u32 prescale; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci prescale = DIV_ROUND_UP(clk_get_rate(a3700_spi->clk), speed_hz); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* For prescaler values over 15, we can only set it by steps of 2. 2278c2ecf20Sopenharmony_ci * Starting from A3700_SPI_CLK_EVEN_OFFS, we set values from 0 up to 2288c2ecf20Sopenharmony_ci * 30. We only use this range from 16 to 30. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci if (prescale > 15) 2318c2ecf20Sopenharmony_ci prescale = A3700_SPI_CLK_EVEN_OFFS + DIV_ROUND_UP(prescale, 2); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2348c2ecf20Sopenharmony_ci val = val & ~A3700_SPI_CLK_PRESCALE_MASK; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci val = val | (prescale & A3700_SPI_CLK_PRESCALE_MASK); 2378c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (prescale <= 2) { 2408c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_TIME_REG); 2418c2ecf20Sopenharmony_ci val |= A3700_SPI_CLK_CAPT_EDGE; 2428c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci u32 val; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2518c2ecf20Sopenharmony_ci if (len == 4) 2528c2ecf20Sopenharmony_ci val |= A3700_SPI_BYTE_LEN; 2538c2ecf20Sopenharmony_ci else 2548c2ecf20Sopenharmony_ci val &= ~A3700_SPI_BYTE_LEN; 2558c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci a3700_spi->byte_len = len; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int timeout = A3700_SPI_TIMEOUT; 2638c2ecf20Sopenharmony_ci u32 val; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2668c2ecf20Sopenharmony_ci val |= A3700_SPI_FIFO_FLUSH; 2678c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci while (--timeout) { 2708c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2718c2ecf20Sopenharmony_ci if (!(val & A3700_SPI_FIFO_FLUSH)) 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci udelay(1); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void a3700_spi_init(struct a3700_spi *a3700_spi) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct spi_master *master = a3700_spi->master; 2828c2ecf20Sopenharmony_ci u32 val; 2838c2ecf20Sopenharmony_ci int i; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Reset SPI unit */ 2868c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2878c2ecf20Sopenharmony_ci val |= A3700_SPI_SRST; 2888c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci udelay(A3700_SPI_TIMEOUT); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 2938c2ecf20Sopenharmony_ci val &= ~A3700_SPI_SRST; 2948c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Disable AUTO_CS and deactivate all chip-selects */ 2978c2ecf20Sopenharmony_ci a3700_spi_auto_cs_unset(a3700_spi); 2988c2ecf20Sopenharmony_ci for (i = 0; i < master->num_chipselect; i++) 2998c2ecf20Sopenharmony_ci a3700_spi_deactivate_cs(a3700_spi, i); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Enable FIFO mode */ 3028c2ecf20Sopenharmony_ci a3700_spi_fifo_mode_set(a3700_spi, true); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Set SPI mode */ 3058c2ecf20Sopenharmony_ci a3700_spi_mode_set(a3700_spi, master->mode_bits); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* Reset counters */ 3088c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0); 3098c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG, 0); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Mask the interrupts and clear cause bits */ 3128c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0); 3138c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, ~0U); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic irqreturn_t a3700_spi_interrupt(int irq, void *dev_id) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct spi_master *master = dev_id; 3198c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi; 3208c2ecf20Sopenharmony_ci u32 cause; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci a3700_spi = spi_master_get_devdata(master); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Get interrupt causes */ 3258c2ecf20Sopenharmony_ci cause = spireg_read(a3700_spi, A3700_SPI_INT_STAT_REG); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!cause || !(a3700_spi->wait_mask & cause)) 3288c2ecf20Sopenharmony_ci return IRQ_NONE; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* mask and acknowledge the SPI interrupts */ 3318c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0); 3328c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Wake up the transfer */ 3358c2ecf20Sopenharmony_ci complete(&a3700_spi->done); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic bool a3700_spi_wait_completion(struct spi_device *spi) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi; 3438c2ecf20Sopenharmony_ci unsigned int timeout; 3448c2ecf20Sopenharmony_ci unsigned int ctrl_reg; 3458c2ecf20Sopenharmony_ci unsigned long timeout_jiffies; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci a3700_spi = spi_master_get_devdata(spi->master); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* SPI interrupt is edge-triggered, which means an interrupt will 3508c2ecf20Sopenharmony_ci * be generated only when detecting a specific status bit changed 3518c2ecf20Sopenharmony_ci * from '0' to '1'. So when we start waiting for a interrupt, we 3528c2ecf20Sopenharmony_ci * need to check status bit in control reg first, if it is already 1, 3538c2ecf20Sopenharmony_ci * then we do not need to wait for interrupt 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); 3568c2ecf20Sopenharmony_ci if (a3700_spi->wait_mask & ctrl_reg) 3578c2ecf20Sopenharmony_ci return true; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci reinit_completion(&a3700_spi->done); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 3628c2ecf20Sopenharmony_ci a3700_spi->wait_mask); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT); 3658c2ecf20Sopenharmony_ci timeout = wait_for_completion_timeout(&a3700_spi->done, 3668c2ecf20Sopenharmony_ci timeout_jiffies); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci a3700_spi->wait_mask = 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (timeout) 3718c2ecf20Sopenharmony_ci return true; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* there might be the case that right after we checked the 3748c2ecf20Sopenharmony_ci * status bits in this routine and before start to wait for 3758c2ecf20Sopenharmony_ci * interrupt by wait_for_completion_timeout, the interrupt 3768c2ecf20Sopenharmony_ci * happens, to avoid missing it we need to double check 3778c2ecf20Sopenharmony_ci * status bits in control reg, if it is already 1, then 3788c2ecf20Sopenharmony_ci * consider that we have the interrupt successfully and 3798c2ecf20Sopenharmony_ci * return true. 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_ci ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); 3828c2ecf20Sopenharmony_ci if (a3700_spi->wait_mask & ctrl_reg) 3838c2ecf20Sopenharmony_ci return true; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Timeout was reached */ 3888c2ecf20Sopenharmony_ci return false; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic bool a3700_spi_transfer_wait(struct spi_device *spi, 3928c2ecf20Sopenharmony_ci unsigned int bit_mask) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci a3700_spi = spi_master_get_devdata(spi->master); 3978c2ecf20Sopenharmony_ci a3700_spi->wait_mask = bit_mask; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return a3700_spi_wait_completion(spi); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi, 4038c2ecf20Sopenharmony_ci unsigned int bytes) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci u32 val; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 4088c2ecf20Sopenharmony_ci val &= ~(A3700_SPI_FIFO_THRS_MASK << A3700_SPI_RFIFO_THRS_BIT); 4098c2ecf20Sopenharmony_ci val |= (bytes - 1) << A3700_SPI_RFIFO_THRS_BIT; 4108c2ecf20Sopenharmony_ci val &= ~(A3700_SPI_FIFO_THRS_MASK << A3700_SPI_WFIFO_THRS_BIT); 4118c2ecf20Sopenharmony_ci val |= (7 - bytes) << A3700_SPI_WFIFO_THRS_BIT; 4128c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void a3700_spi_transfer_setup(struct spi_device *spi, 4168c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci a3700_spi = spi_master_get_devdata(spi->master); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci a3700_spi_clock_set(a3700_spi, xfer->speed_hz); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Use 4 bytes long transfers. Each transfer method has its way to deal 4258c2ecf20Sopenharmony_ci * with the remaining bytes for non 4-bytes aligned transfers. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci a3700_spi_bytelen_set(a3700_spi, 4); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Initialize the working buffers */ 4308c2ecf20Sopenharmony_ci a3700_spi->tx_buf = xfer->tx_buf; 4318c2ecf20Sopenharmony_ci a3700_spi->rx_buf = xfer->rx_buf; 4328c2ecf20Sopenharmony_ci a3700_spi->buf_len = xfer->len; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void a3700_spi_set_cs(struct spi_device *spi, bool enable) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi = spi_master_get_devdata(spi->master); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (!enable) 4408c2ecf20Sopenharmony_ci a3700_spi_activate_cs(a3700_spi, spi->chip_select); 4418c2ecf20Sopenharmony_ci else 4428c2ecf20Sopenharmony_ci a3700_spi_deactivate_cs(a3700_spi, spi->chip_select); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void a3700_spi_header_set(struct a3700_spi *a3700_spi) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci unsigned int addr_cnt; 4488c2ecf20Sopenharmony_ci u32 val = 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* Clear the header registers */ 4518c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0); 4528c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0); 4538c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0); 4548c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Set header counters */ 4578c2ecf20Sopenharmony_ci if (a3700_spi->tx_buf) { 4588c2ecf20Sopenharmony_ci /* 4598c2ecf20Sopenharmony_ci * when tx data is not 4 bytes aligned, there will be unexpected 4608c2ecf20Sopenharmony_ci * bytes out of SPI output register, since it always shifts out 4618c2ecf20Sopenharmony_ci * as whole 4 bytes. This might cause incorrect transaction with 4628c2ecf20Sopenharmony_ci * some devices. To avoid that, use SPI header count feature to 4638c2ecf20Sopenharmony_ci * transfer up to 3 bytes of data first, and then make the rest 4648c2ecf20Sopenharmony_ci * of data 4-byte aligned. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci addr_cnt = a3700_spi->buf_len % 4; 4678c2ecf20Sopenharmony_ci if (addr_cnt) { 4688c2ecf20Sopenharmony_ci val = (addr_cnt & A3700_SPI_ADDR_CNT_MASK) 4698c2ecf20Sopenharmony_ci << A3700_SPI_ADDR_CNT_BIT; 4708c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Update the buffer length to be transferred */ 4738c2ecf20Sopenharmony_ci a3700_spi->buf_len -= addr_cnt; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* transfer 1~3 bytes through address count */ 4768c2ecf20Sopenharmony_ci val = 0; 4778c2ecf20Sopenharmony_ci while (addr_cnt--) { 4788c2ecf20Sopenharmony_ci val = (val << 8) | a3700_spi->tx_buf[0]; 4798c2ecf20Sopenharmony_ci a3700_spi->tx_buf++; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val); 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int a3700_is_wfifo_full(struct a3700_spi *a3700_spi) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci u32 val; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); 4918c2ecf20Sopenharmony_ci return (val & A3700_SPI_WFIFO_FULL); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int a3700_spi_fifo_write(struct a3700_spi *a3700_spi) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci u32 val; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) { 4998c2ecf20Sopenharmony_ci val = *(u32 *)a3700_spi->tx_buf; 5008c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val); 5018c2ecf20Sopenharmony_ci a3700_spi->buf_len -= 4; 5028c2ecf20Sopenharmony_ci a3700_spi->tx_buf += 4; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic int a3700_is_rfifo_empty(struct a3700_spi *a3700_spi) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci u32 val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return (val & A3700_SPI_RFIFO_EMPTY); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int a3700_spi_fifo_read(struct a3700_spi *a3700_spi) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci u32 val; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) { 5208c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); 5218c2ecf20Sopenharmony_ci if (a3700_spi->buf_len >= 4) { 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci memcpy(a3700_spi->rx_buf, &val, 4); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci a3700_spi->buf_len -= 4; 5268c2ecf20Sopenharmony_ci a3700_spi->rx_buf += 4; 5278c2ecf20Sopenharmony_ci } else { 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * When remain bytes is not larger than 4, we should 5308c2ecf20Sopenharmony_ci * avoid memory overwriting and just write the left rx 5318c2ecf20Sopenharmony_ci * buffer bytes. 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ci while (a3700_spi->buf_len) { 5348c2ecf20Sopenharmony_ci *a3700_spi->rx_buf = val & 0xff; 5358c2ecf20Sopenharmony_ci val >>= 8; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci a3700_spi->buf_len--; 5388c2ecf20Sopenharmony_ci a3700_spi->rx_buf++; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void a3700_spi_transfer_abort_fifo(struct a3700_spi *a3700_spi) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci int timeout = A3700_SPI_TIMEOUT; 5498c2ecf20Sopenharmony_ci u32 val; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 5528c2ecf20Sopenharmony_ci val |= A3700_SPI_XFER_STOP; 5538c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci while (--timeout) { 5568c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 5578c2ecf20Sopenharmony_ci if (!(val & A3700_SPI_XFER_START)) 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci udelay(1); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci a3700_spi_fifo_flush(a3700_spi); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci val &= ~A3700_SPI_XFER_STOP; 5658c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int a3700_spi_prepare_message(struct spi_master *master, 5698c2ecf20Sopenharmony_ci struct spi_message *message) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi = spi_master_get_devdata(master); 5728c2ecf20Sopenharmony_ci struct spi_device *spi = message->spi; 5738c2ecf20Sopenharmony_ci int ret; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci ret = clk_enable(a3700_spi->clk); 5768c2ecf20Sopenharmony_ci if (ret) { 5778c2ecf20Sopenharmony_ci dev_err(&spi->dev, "failed to enable clk with error %d\n", ret); 5788c2ecf20Sopenharmony_ci return ret; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* Flush the FIFOs */ 5828c2ecf20Sopenharmony_ci ret = a3700_spi_fifo_flush(a3700_spi); 5838c2ecf20Sopenharmony_ci if (ret) 5848c2ecf20Sopenharmony_ci return ret; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci a3700_spi_mode_set(a3700_spi, spi->mode); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return 0; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int a3700_spi_transfer_one_fifo(struct spi_master *master, 5928c2ecf20Sopenharmony_ci struct spi_device *spi, 5938c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi = spi_master_get_devdata(master); 5968c2ecf20Sopenharmony_ci int ret = 0, timeout = A3700_SPI_TIMEOUT; 5978c2ecf20Sopenharmony_ci unsigned int nbits = 0, byte_len; 5988c2ecf20Sopenharmony_ci u32 val; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Make sure we use FIFO mode */ 6018c2ecf20Sopenharmony_ci a3700_spi_fifo_mode_set(a3700_spi, true); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Configure FIFO thresholds */ 6048c2ecf20Sopenharmony_ci byte_len = xfer->bits_per_word >> 3; 6058c2ecf20Sopenharmony_ci a3700_spi_fifo_thres_set(a3700_spi, byte_len); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (xfer->tx_buf) 6088c2ecf20Sopenharmony_ci nbits = xfer->tx_nbits; 6098c2ecf20Sopenharmony_ci else if (xfer->rx_buf) 6108c2ecf20Sopenharmony_ci nbits = xfer->rx_nbits; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci a3700_spi_pin_mode_set(a3700_spi, nbits, xfer->rx_buf ? true : false); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* Flush the FIFOs */ 6158c2ecf20Sopenharmony_ci a3700_spi_fifo_flush(a3700_spi); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Transfer first bytes of data when buffer is not 4-byte aligned */ 6188c2ecf20Sopenharmony_ci a3700_spi_header_set(a3700_spi); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (xfer->rx_buf) { 6218c2ecf20Sopenharmony_ci /* Clear WFIFO, since it's last 2 bytes are shifted out during 6228c2ecf20Sopenharmony_ci * a read operation 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, 0); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Set read data length */ 6278c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG, 6288c2ecf20Sopenharmony_ci a3700_spi->buf_len); 6298c2ecf20Sopenharmony_ci /* Start READ transfer */ 6308c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 6318c2ecf20Sopenharmony_ci val &= ~A3700_SPI_RW_EN; 6328c2ecf20Sopenharmony_ci val |= A3700_SPI_XFER_START; 6338c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 6348c2ecf20Sopenharmony_ci } else if (xfer->tx_buf) { 6358c2ecf20Sopenharmony_ci /* Start Write transfer */ 6368c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 6378c2ecf20Sopenharmony_ci val |= (A3700_SPI_XFER_START | A3700_SPI_RW_EN); 6388c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* 6418c2ecf20Sopenharmony_ci * If there are data to be written to the SPI device, xmit_data 6428c2ecf20Sopenharmony_ci * flag is set true; otherwise the instruction in SPI_INSTR does 6438c2ecf20Sopenharmony_ci * not require data to be written to the SPI device, then 6448c2ecf20Sopenharmony_ci * xmit_data flag is set false. 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci a3700_spi->xmit_data = (a3700_spi->buf_len != 0); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci while (a3700_spi->buf_len) { 6508c2ecf20Sopenharmony_ci if (a3700_spi->tx_buf) { 6518c2ecf20Sopenharmony_ci /* Wait wfifo ready */ 6528c2ecf20Sopenharmony_ci if (!a3700_spi_transfer_wait(spi, 6538c2ecf20Sopenharmony_ci A3700_SPI_WFIFO_RDY)) { 6548c2ecf20Sopenharmony_ci dev_err(&spi->dev, 6558c2ecf20Sopenharmony_ci "wait wfifo ready timed out\n"); 6568c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 6578c2ecf20Sopenharmony_ci goto error; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci /* Fill up the wfifo */ 6608c2ecf20Sopenharmony_ci ret = a3700_spi_fifo_write(a3700_spi); 6618c2ecf20Sopenharmony_ci if (ret) 6628c2ecf20Sopenharmony_ci goto error; 6638c2ecf20Sopenharmony_ci } else if (a3700_spi->rx_buf) { 6648c2ecf20Sopenharmony_ci /* Wait rfifo ready */ 6658c2ecf20Sopenharmony_ci if (!a3700_spi_transfer_wait(spi, 6668c2ecf20Sopenharmony_ci A3700_SPI_RFIFO_RDY)) { 6678c2ecf20Sopenharmony_ci dev_err(&spi->dev, 6688c2ecf20Sopenharmony_ci "wait rfifo ready timed out\n"); 6698c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 6708c2ecf20Sopenharmony_ci goto error; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci /* Drain out the rfifo */ 6738c2ecf20Sopenharmony_ci ret = a3700_spi_fifo_read(a3700_spi); 6748c2ecf20Sopenharmony_ci if (ret) 6758c2ecf20Sopenharmony_ci goto error; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* 6808c2ecf20Sopenharmony_ci * Stop a write transfer in fifo mode: 6818c2ecf20Sopenharmony_ci * - wait all the bytes in wfifo to be shifted out 6828c2ecf20Sopenharmony_ci * - set XFER_STOP bit 6838c2ecf20Sopenharmony_ci * - wait XFER_START bit clear 6848c2ecf20Sopenharmony_ci * - clear XFER_STOP bit 6858c2ecf20Sopenharmony_ci * Stop a read transfer in fifo mode: 6868c2ecf20Sopenharmony_ci * - the hardware is to reset the XFER_START bit 6878c2ecf20Sopenharmony_ci * after the number of bytes indicated in DIN_CNT 6888c2ecf20Sopenharmony_ci * register 6898c2ecf20Sopenharmony_ci * - just wait XFER_START bit clear 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci if (a3700_spi->tx_buf) { 6928c2ecf20Sopenharmony_ci if (a3700_spi->xmit_data) { 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * If there are data written to the SPI device, wait 6958c2ecf20Sopenharmony_ci * until SPI_WFIFO_EMPTY is 1 to wait for all data to 6968c2ecf20Sopenharmony_ci * transfer out of write FIFO. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci if (!a3700_spi_transfer_wait(spi, 6998c2ecf20Sopenharmony_ci A3700_SPI_WFIFO_EMPTY)) { 7008c2ecf20Sopenharmony_ci dev_err(&spi->dev, "wait wfifo empty timed out\n"); 7018c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) { 7068c2ecf20Sopenharmony_ci dev_err(&spi->dev, "wait xfer ready timed out\n"); 7078c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 7118c2ecf20Sopenharmony_ci val |= A3700_SPI_XFER_STOP; 7128c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci while (--timeout) { 7168c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); 7178c2ecf20Sopenharmony_ci if (!(val & A3700_SPI_XFER_START)) 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci udelay(1); 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (timeout == 0) { 7238c2ecf20Sopenharmony_ci dev_err(&spi->dev, "wait transfer start clear timed out\n"); 7248c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 7258c2ecf20Sopenharmony_ci goto error; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci val &= ~A3700_SPI_XFER_STOP; 7298c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); 7308c2ecf20Sopenharmony_ci goto out; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cierror: 7338c2ecf20Sopenharmony_ci a3700_spi_transfer_abort_fifo(a3700_spi); 7348c2ecf20Sopenharmony_ciout: 7358c2ecf20Sopenharmony_ci spi_finalize_current_transfer(master); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return ret; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic int a3700_spi_transfer_one_full_duplex(struct spi_master *master, 7418c2ecf20Sopenharmony_ci struct spi_device *spi, 7428c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi = spi_master_get_devdata(master); 7458c2ecf20Sopenharmony_ci u32 val; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* Disable FIFO mode */ 7488c2ecf20Sopenharmony_ci a3700_spi_fifo_mode_set(a3700_spi, false); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci while (a3700_spi->buf_len) { 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* When we have less than 4 bytes to transfer, switch to 1 byte 7538c2ecf20Sopenharmony_ci * mode. This is reset after each transfer 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci if (a3700_spi->buf_len < 4) 7568c2ecf20Sopenharmony_ci a3700_spi_bytelen_set(a3700_spi, 1); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (a3700_spi->byte_len == 1) 7598c2ecf20Sopenharmony_ci val = *a3700_spi->tx_buf; 7608c2ecf20Sopenharmony_ci else 7618c2ecf20Sopenharmony_ci val = *(u32 *)a3700_spi->tx_buf; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Wait for all the data to be shifted in / out */ 7668c2ecf20Sopenharmony_ci while (!(spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG) & 7678c2ecf20Sopenharmony_ci A3700_SPI_XFER_DONE)) 7688c2ecf20Sopenharmony_ci cpu_relax(); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci memcpy(a3700_spi->rx_buf, &val, a3700_spi->byte_len); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci a3700_spi->buf_len -= a3700_spi->byte_len; 7758c2ecf20Sopenharmony_ci a3700_spi->tx_buf += a3700_spi->byte_len; 7768c2ecf20Sopenharmony_ci a3700_spi->rx_buf += a3700_spi->byte_len; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci spi_finalize_current_transfer(master); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int a3700_spi_transfer_one(struct spi_master *master, 7868c2ecf20Sopenharmony_ci struct spi_device *spi, 7878c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci a3700_spi_transfer_setup(spi, xfer); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (xfer->tx_buf && xfer->rx_buf) 7928c2ecf20Sopenharmony_ci return a3700_spi_transfer_one_full_duplex(master, spi, xfer); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return a3700_spi_transfer_one_fifo(master, spi, xfer); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int a3700_spi_unprepare_message(struct spi_master *master, 7988c2ecf20Sopenharmony_ci struct spi_message *message) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct a3700_spi *a3700_spi = spi_master_get_devdata(master); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci clk_disable(a3700_spi->clk); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic const struct of_device_id a3700_spi_dt_ids[] = { 8088c2ecf20Sopenharmony_ci { .compatible = "marvell,armada-3700-spi", .data = NULL }, 8098c2ecf20Sopenharmony_ci {}, 8108c2ecf20Sopenharmony_ci}; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, a3700_spi_dt_ids); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int a3700_spi_probe(struct platform_device *pdev) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 8178c2ecf20Sopenharmony_ci struct device_node *of_node = dev->of_node; 8188c2ecf20Sopenharmony_ci struct spi_master *master; 8198c2ecf20Sopenharmony_ci struct a3700_spi *spi; 8208c2ecf20Sopenharmony_ci u32 num_cs = 0; 8218c2ecf20Sopenharmony_ci int irq, ret = 0; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci master = spi_alloc_master(dev, sizeof(*spi)); 8248c2ecf20Sopenharmony_ci if (!master) { 8258c2ecf20Sopenharmony_ci dev_err(dev, "master allocation failed\n"); 8268c2ecf20Sopenharmony_ci ret = -ENOMEM; 8278c2ecf20Sopenharmony_ci goto out; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (of_property_read_u32(of_node, "num-cs", &num_cs)) { 8318c2ecf20Sopenharmony_ci dev_err(dev, "could not find num-cs\n"); 8328c2ecf20Sopenharmony_ci ret = -ENXIO; 8338c2ecf20Sopenharmony_ci goto error; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci master->bus_num = pdev->id; 8378c2ecf20Sopenharmony_ci master->dev.of_node = of_node; 8388c2ecf20Sopenharmony_ci master->mode_bits = SPI_MODE_3; 8398c2ecf20Sopenharmony_ci master->num_chipselect = num_cs; 8408c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32); 8418c2ecf20Sopenharmony_ci master->prepare_message = a3700_spi_prepare_message; 8428c2ecf20Sopenharmony_ci master->transfer_one = a3700_spi_transfer_one; 8438c2ecf20Sopenharmony_ci master->unprepare_message = a3700_spi_unprepare_message; 8448c2ecf20Sopenharmony_ci master->set_cs = a3700_spi_set_cs; 8458c2ecf20Sopenharmony_ci master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL | 8468c2ecf20Sopenharmony_ci SPI_RX_QUAD | SPI_TX_QUAD); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, master); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci spi = spi_master_get_devdata(master); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci spi->master = master; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci spi->base = devm_platform_ioremap_resource(pdev, 0); 8558c2ecf20Sopenharmony_ci if (IS_ERR(spi->base)) { 8568c2ecf20Sopenharmony_ci ret = PTR_ERR(spi->base); 8578c2ecf20Sopenharmony_ci goto error; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 8618c2ecf20Sopenharmony_ci if (irq < 0) { 8628c2ecf20Sopenharmony_ci ret = -ENXIO; 8638c2ecf20Sopenharmony_ci goto error; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci spi->irq = irq; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci init_completion(&spi->done); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci spi->clk = devm_clk_get(dev, NULL); 8708c2ecf20Sopenharmony_ci if (IS_ERR(spi->clk)) { 8718c2ecf20Sopenharmony_ci dev_err(dev, "could not find clk: %ld\n", PTR_ERR(spi->clk)); 8728c2ecf20Sopenharmony_ci goto error; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci ret = clk_prepare(spi->clk); 8768c2ecf20Sopenharmony_ci if (ret) { 8778c2ecf20Sopenharmony_ci dev_err(dev, "could not prepare clk: %d\n", ret); 8788c2ecf20Sopenharmony_ci goto error; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci master->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ, 8828c2ecf20Sopenharmony_ci clk_get_rate(spi->clk)); 8838c2ecf20Sopenharmony_ci master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk), 8848c2ecf20Sopenharmony_ci A3700_SPI_MAX_PRESCALE); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci a3700_spi_init(spi); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0, 8898c2ecf20Sopenharmony_ci dev_name(dev), master); 8908c2ecf20Sopenharmony_ci if (ret) { 8918c2ecf20Sopenharmony_ci dev_err(dev, "could not request IRQ: %d\n", ret); 8928c2ecf20Sopenharmony_ci goto error_clk; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci ret = devm_spi_register_master(dev, master); 8968c2ecf20Sopenharmony_ci if (ret) { 8978c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register master\n"); 8988c2ecf20Sopenharmony_ci goto error_clk; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cierror_clk: 9048c2ecf20Sopenharmony_ci clk_unprepare(spi->clk); 9058c2ecf20Sopenharmony_cierror: 9068c2ecf20Sopenharmony_ci spi_master_put(master); 9078c2ecf20Sopenharmony_ciout: 9088c2ecf20Sopenharmony_ci return ret; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic int a3700_spi_remove(struct platform_device *pdev) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct spi_master *master = platform_get_drvdata(pdev); 9148c2ecf20Sopenharmony_ci struct a3700_spi *spi = spi_master_get_devdata(master); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci clk_unprepare(spi->clk); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic struct platform_driver a3700_spi_driver = { 9228c2ecf20Sopenharmony_ci .driver = { 9238c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 9248c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(a3700_spi_dt_ids), 9258c2ecf20Sopenharmony_ci }, 9268c2ecf20Sopenharmony_ci .probe = a3700_spi_probe, 9278c2ecf20Sopenharmony_ci .remove = a3700_spi_remove, 9288c2ecf20Sopenharmony_ci}; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cimodule_platform_driver(a3700_spi_driver); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Armada-3700 SPI driver"); 9338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>"); 9348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 9358c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME); 936