18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (C) 2018 Spreadtrum Communications Inc. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/clk.h> 58c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 68c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 78c2ecf20Sopenharmony_ci#include <linux/dma/sprd-dma.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/of_dma.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 188c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define SPRD_SPI_TXD 0x0 218c2ecf20Sopenharmony_ci#define SPRD_SPI_CLKD 0x4 228c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL0 0x8 238c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL1 0xc 248c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL2 0x10 258c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL3 0x14 268c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL4 0x18 278c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL5 0x1c 288c2ecf20Sopenharmony_ci#define SPRD_SPI_INT_EN 0x20 298c2ecf20Sopenharmony_ci#define SPRD_SPI_INT_CLR 0x24 308c2ecf20Sopenharmony_ci#define SPRD_SPI_INT_RAW_STS 0x28 318c2ecf20Sopenharmony_ci#define SPRD_SPI_INT_MASK_STS 0x2c 328c2ecf20Sopenharmony_ci#define SPRD_SPI_STS1 0x30 338c2ecf20Sopenharmony_ci#define SPRD_SPI_STS2 0x34 348c2ecf20Sopenharmony_ci#define SPRD_SPI_DSP_WAIT 0x38 358c2ecf20Sopenharmony_ci#define SPRD_SPI_STS3 0x3c 368c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL6 0x40 378c2ecf20Sopenharmony_ci#define SPRD_SPI_STS4 0x44 388c2ecf20Sopenharmony_ci#define SPRD_SPI_FIFO_RST 0x48 398c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL7 0x4c 408c2ecf20Sopenharmony_ci#define SPRD_SPI_STS5 0x50 418c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL8 0x54 428c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL9 0x58 438c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL10 0x5c 448c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL11 0x60 458c2ecf20Sopenharmony_ci#define SPRD_SPI_CTL12 0x64 468c2ecf20Sopenharmony_ci#define SPRD_SPI_STS6 0x68 478c2ecf20Sopenharmony_ci#define SPRD_SPI_STS7 0x6c 488c2ecf20Sopenharmony_ci#define SPRD_SPI_STS8 0x70 498c2ecf20Sopenharmony_ci#define SPRD_SPI_STS9 0x74 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL0 */ 528c2ecf20Sopenharmony_ci#define SPRD_SPI_SCK_REV BIT(13) 538c2ecf20Sopenharmony_ci#define SPRD_SPI_NG_TX BIT(1) 548c2ecf20Sopenharmony_ci#define SPRD_SPI_NG_RX BIT(0) 558c2ecf20Sopenharmony_ci#define SPRD_SPI_CHNL_LEN_MASK GENMASK(4, 0) 568c2ecf20Sopenharmony_ci#define SPRD_SPI_CSN_MASK GENMASK(11, 8) 578c2ecf20Sopenharmony_ci#define SPRD_SPI_CS0_VALID BIT(8) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Bits & mask definition for register SPI_INT_EN */ 608c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_END_INT_EN BIT(8) 618c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_END_INT_EN BIT(9) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Bits & mask definition for register SPI_INT_RAW_STS */ 648c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_END_RAW BIT(8) 658c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_END_RAW BIT(9) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* Bits & mask definition for register SPI_INT_CLR */ 688c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_END_CLR BIT(8) 698c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_END_CLR BIT(9) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* Bits & mask definition for register INT_MASK_STS */ 728c2ecf20Sopenharmony_ci#define SPRD_SPI_MASK_RX_END BIT(9) 738c2ecf20Sopenharmony_ci#define SPRD_SPI_MASK_TX_END BIT(8) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* Bits & mask definition for register STS2 */ 768c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_BUSY BIT(8) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL1 */ 798c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_MODE BIT(12) 808c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_MODE BIT(13) 818c2ecf20Sopenharmony_ci#define SPRD_SPI_RTX_MD_MASK GENMASK(13, 12) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL2 */ 848c2ecf20Sopenharmony_ci#define SPRD_SPI_DMA_EN BIT(6) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL4 */ 878c2ecf20Sopenharmony_ci#define SPRD_SPI_START_RX BIT(9) 888c2ecf20Sopenharmony_ci#define SPRD_SPI_ONLY_RECV_MASK GENMASK(8, 0) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Bits & mask definition for register SPI_INT_CLR */ 918c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_END_INT_CLR BIT(9) 928c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_END_INT_CLR BIT(8) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* Bits & mask definition for register SPI_INT_RAW */ 958c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_END_IRQ BIT(9) 968c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_END_IRQ BIT(8) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL12 */ 998c2ecf20Sopenharmony_ci#define SPRD_SPI_SW_RX_REQ BIT(0) 1008c2ecf20Sopenharmony_ci#define SPRD_SPI_SW_TX_REQ BIT(1) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL7 */ 1038c2ecf20Sopenharmony_ci#define SPRD_SPI_DATA_LINE2_EN BIT(15) 1048c2ecf20Sopenharmony_ci#define SPRD_SPI_MODE_MASK GENMASK(5, 3) 1058c2ecf20Sopenharmony_ci#define SPRD_SPI_MODE_OFFSET 3 1068c2ecf20Sopenharmony_ci#define SPRD_SPI_3WIRE_MODE 4 1078c2ecf20Sopenharmony_ci#define SPRD_SPI_4WIRE_MODE 0 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL8 */ 1108c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_MAX_LEN_MASK GENMASK(19, 0) 1118c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_LEN_H_MASK GENMASK(3, 0) 1128c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_LEN_H_OFFSET 16 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL9 */ 1158c2ecf20Sopenharmony_ci#define SPRD_SPI_TX_LEN_L_MASK GENMASK(15, 0) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL10 */ 1188c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_MAX_LEN_MASK GENMASK(19, 0) 1198c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_LEN_H_MASK GENMASK(3, 0) 1208c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_LEN_H_OFFSET 16 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* Bits & mask definition for register CTL11 */ 1238c2ecf20Sopenharmony_ci#define SPRD_SPI_RX_LEN_L_MASK GENMASK(15, 0) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* Default & maximum word delay cycles */ 1268c2ecf20Sopenharmony_ci#define SPRD_SPI_MIN_DELAY_CYCLE 14 1278c2ecf20Sopenharmony_ci#define SPRD_SPI_MAX_DELAY_CYCLE 130 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define SPRD_SPI_FIFO_SIZE 32 1308c2ecf20Sopenharmony_ci#define SPRD_SPI_CHIP_CS_NUM 0x4 1318c2ecf20Sopenharmony_ci#define SPRD_SPI_CHNL_LEN 2 1328c2ecf20Sopenharmony_ci#define SPRD_SPI_DEFAULT_SOURCE 26000000 1338c2ecf20Sopenharmony_ci#define SPRD_SPI_MAX_SPEED_HZ 48000000 1348c2ecf20Sopenharmony_ci#define SPRD_SPI_AUTOSUSPEND_DELAY 100 1358c2ecf20Sopenharmony_ci#define SPRD_SPI_DMA_STEP 8 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cienum sprd_spi_dma_channel { 1388c2ecf20Sopenharmony_ci SPRD_SPI_RX, 1398c2ecf20Sopenharmony_ci SPRD_SPI_TX, 1408c2ecf20Sopenharmony_ci SPRD_SPI_MAX, 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistruct sprd_spi_dma { 1448c2ecf20Sopenharmony_ci bool enable; 1458c2ecf20Sopenharmony_ci struct dma_chan *dma_chan[SPRD_SPI_MAX]; 1468c2ecf20Sopenharmony_ci enum dma_slave_buswidth width; 1478c2ecf20Sopenharmony_ci u32 fragmens_len; 1488c2ecf20Sopenharmony_ci u32 rx_len; 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistruct sprd_spi { 1528c2ecf20Sopenharmony_ci void __iomem *base; 1538c2ecf20Sopenharmony_ci phys_addr_t phy_base; 1548c2ecf20Sopenharmony_ci struct device *dev; 1558c2ecf20Sopenharmony_ci struct clk *clk; 1568c2ecf20Sopenharmony_ci int irq; 1578c2ecf20Sopenharmony_ci u32 src_clk; 1588c2ecf20Sopenharmony_ci u32 hw_mode; 1598c2ecf20Sopenharmony_ci u32 trans_len; 1608c2ecf20Sopenharmony_ci u32 trans_mode; 1618c2ecf20Sopenharmony_ci u32 word_delay; 1628c2ecf20Sopenharmony_ci u32 hw_speed_hz; 1638c2ecf20Sopenharmony_ci u32 len; 1648c2ecf20Sopenharmony_ci int status; 1658c2ecf20Sopenharmony_ci struct sprd_spi_dma dma; 1668c2ecf20Sopenharmony_ci struct completion xfer_completion; 1678c2ecf20Sopenharmony_ci const void *tx_buf; 1688c2ecf20Sopenharmony_ci void *rx_buf; 1698c2ecf20Sopenharmony_ci int (*read_bufs)(struct sprd_spi *ss, u32 len); 1708c2ecf20Sopenharmony_ci int (*write_bufs)(struct sprd_spi *ss, u32 len); 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic u32 sprd_spi_transfer_max_timeout(struct sprd_spi *ss, 1748c2ecf20Sopenharmony_ci struct spi_transfer *t) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci /* 1778c2ecf20Sopenharmony_ci * The time spent on transmission of the full FIFO data is the maximum 1788c2ecf20Sopenharmony_ci * SPI transmission time. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci u32 size = t->bits_per_word * SPRD_SPI_FIFO_SIZE; 1818c2ecf20Sopenharmony_ci u32 bit_time_us = DIV_ROUND_UP(USEC_PER_SEC, ss->hw_speed_hz); 1828c2ecf20Sopenharmony_ci u32 total_time_us = size * bit_time_us; 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * There is an interval between data and the data in our SPI hardware, 1858c2ecf20Sopenharmony_ci * so the total transmission time need add the interval time. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci u32 interval_cycle = SPRD_SPI_FIFO_SIZE * ss->word_delay; 1888c2ecf20Sopenharmony_ci u32 interval_time_us = DIV_ROUND_UP(interval_cycle * USEC_PER_SEC, 1898c2ecf20Sopenharmony_ci ss->src_clk); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return total_time_us + interval_time_us; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int sprd_spi_wait_for_tx_end(struct sprd_spi *ss, struct spi_transfer *t) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci u32 val, us; 1978c2ecf20Sopenharmony_ci int ret; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci us = sprd_spi_transfer_max_timeout(ss, t); 2008c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val, 2018c2ecf20Sopenharmony_ci val & SPRD_SPI_TX_END_IRQ, 0, us); 2028c2ecf20Sopenharmony_ci if (ret) { 2038c2ecf20Sopenharmony_ci dev_err(ss->dev, "SPI error, spi send timeout!\n"); 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_STS2, val, 2088c2ecf20Sopenharmony_ci !(val & SPRD_SPI_TX_BUSY), 0, us); 2098c2ecf20Sopenharmony_ci if (ret) { 2108c2ecf20Sopenharmony_ci dev_err(ss->dev, "SPI error, spi busy timeout!\n"); 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_TX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int sprd_spi_wait_for_rx_end(struct sprd_spi *ss, struct spi_transfer *t) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci u32 val, us; 2228c2ecf20Sopenharmony_ci int ret; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci us = sprd_spi_transfer_max_timeout(ss, t); 2258c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val, 2268c2ecf20Sopenharmony_ci val & SPRD_SPI_RX_END_IRQ, 0, us); 2278c2ecf20Sopenharmony_ci if (ret) { 2288c2ecf20Sopenharmony_ci dev_err(ss->dev, "SPI error, spi rx timeout!\n"); 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_RX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void sprd_spi_tx_req(struct sprd_spi *ss) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_SW_TX_REQ, ss->base + SPRD_SPI_CTL12); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void sprd_spi_rx_req(struct sprd_spi *ss) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_SW_RX_REQ, ss->base + SPRD_SPI_CTL12); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void sprd_spi_enter_idle(struct sprd_spi *ss) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL1); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_RTX_MD_MASK; 2528c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL1); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void sprd_spi_set_transfer_bits(struct sprd_spi *ss, u32 bits) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL0); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Set the valid bits for every transaction */ 2608c2ecf20Sopenharmony_ci val &= ~(SPRD_SPI_CHNL_LEN_MASK << SPRD_SPI_CHNL_LEN); 2618c2ecf20Sopenharmony_ci val |= bits << SPRD_SPI_CHNL_LEN; 2628c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL0); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void sprd_spi_set_tx_length(struct sprd_spi *ss, u32 length) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL8); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci length &= SPRD_SPI_TX_MAX_LEN_MASK; 2708c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_TX_LEN_H_MASK; 2718c2ecf20Sopenharmony_ci val |= length >> SPRD_SPI_TX_LEN_H_OFFSET; 2728c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL8); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci val = length & SPRD_SPI_TX_LEN_L_MASK; 2758c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL9); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void sprd_spi_set_rx_length(struct sprd_spi *ss, u32 length) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL10); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci length &= SPRD_SPI_RX_MAX_LEN_MASK; 2838c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_RX_LEN_H_MASK; 2848c2ecf20Sopenharmony_ci val |= length >> SPRD_SPI_RX_LEN_H_OFFSET; 2858c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL10); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci val = length & SPRD_SPI_RX_LEN_L_MASK; 2888c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL11); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void sprd_spi_chipselect(struct spi_device *sdev, bool cs) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct spi_controller *sctlr = sdev->controller; 2948c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sctlr); 2958c2ecf20Sopenharmony_ci u32 val; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL0); 2988c2ecf20Sopenharmony_ci /* The SPI controller will pull down CS pin if cs is 0 */ 2998c2ecf20Sopenharmony_ci if (!cs) { 3008c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_CS0_VALID; 3018c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL0); 3028c2ecf20Sopenharmony_ci } else { 3038c2ecf20Sopenharmony_ci val |= SPRD_SPI_CSN_MASK; 3048c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL0); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int sprd_spi_write_only_receive(struct sprd_spi *ss, u32 len) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci u32 val; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* Clear the start receive bit and reset receive data number */ 3138c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL4); 3148c2ecf20Sopenharmony_ci val &= ~(SPRD_SPI_START_RX | SPRD_SPI_ONLY_RECV_MASK); 3158c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL4); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Set the receive data length */ 3188c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL4); 3198c2ecf20Sopenharmony_ci val |= len & SPRD_SPI_ONLY_RECV_MASK; 3208c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL4); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Trigger to receive data */ 3238c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL4); 3248c2ecf20Sopenharmony_ci val |= SPRD_SPI_START_RX; 3258c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL4); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return len; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int sprd_spi_write_bufs_u8(struct sprd_spi *ss, u32 len) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u8 *tx_p = (u8 *)ss->tx_buf; 3338c2ecf20Sopenharmony_ci int i; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3368c2ecf20Sopenharmony_ci writeb_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ss->tx_buf += i; 3398c2ecf20Sopenharmony_ci return i; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int sprd_spi_write_bufs_u16(struct sprd_spi *ss, u32 len) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci u16 *tx_p = (u16 *)ss->tx_buf; 3458c2ecf20Sopenharmony_ci int i; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3488c2ecf20Sopenharmony_ci writew_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ss->tx_buf += i << 1; 3518c2ecf20Sopenharmony_ci return i << 1; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int sprd_spi_write_bufs_u32(struct sprd_spi *ss, u32 len) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci u32 *tx_p = (u32 *)ss->tx_buf; 3578c2ecf20Sopenharmony_ci int i; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3608c2ecf20Sopenharmony_ci writel_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ss->tx_buf += i << 2; 3638c2ecf20Sopenharmony_ci return i << 2; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int sprd_spi_read_bufs_u8(struct sprd_spi *ss, u32 len) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci u8 *rx_p = (u8 *)ss->rx_buf; 3698c2ecf20Sopenharmony_ci int i; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3728c2ecf20Sopenharmony_ci rx_p[i] = readb_relaxed(ss->base + SPRD_SPI_TXD); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ss->rx_buf += i; 3758c2ecf20Sopenharmony_ci return i; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int sprd_spi_read_bufs_u16(struct sprd_spi *ss, u32 len) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci u16 *rx_p = (u16 *)ss->rx_buf; 3818c2ecf20Sopenharmony_ci int i; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3848c2ecf20Sopenharmony_ci rx_p[i] = readw_relaxed(ss->base + SPRD_SPI_TXD); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ss->rx_buf += i << 1; 3878c2ecf20Sopenharmony_ci return i << 1; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int sprd_spi_read_bufs_u32(struct sprd_spi *ss, u32 len) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u32 *rx_p = (u32 *)ss->rx_buf; 3938c2ecf20Sopenharmony_ci int i; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3968c2ecf20Sopenharmony_ci rx_p[i] = readl_relaxed(ss->base + SPRD_SPI_TXD); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ss->rx_buf += i << 2; 3998c2ecf20Sopenharmony_ci return i << 2; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); 4058c2ecf20Sopenharmony_ci u32 trans_len = ss->trans_len, len; 4068c2ecf20Sopenharmony_ci int ret, write_size = 0, read_size = 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci while (trans_len) { 4098c2ecf20Sopenharmony_ci len = trans_len > SPRD_SPI_FIFO_SIZE ? SPRD_SPI_FIFO_SIZE : 4108c2ecf20Sopenharmony_ci trans_len; 4118c2ecf20Sopenharmony_ci if (ss->trans_mode & SPRD_SPI_TX_MODE) { 4128c2ecf20Sopenharmony_ci sprd_spi_set_tx_length(ss, len); 4138c2ecf20Sopenharmony_ci write_size += ss->write_bufs(ss, len); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci * For our 3 wires mode or dual TX line mode, we need 4178c2ecf20Sopenharmony_ci * to request the controller to transfer. 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) 4208c2ecf20Sopenharmony_ci sprd_spi_tx_req(ss); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ret = sprd_spi_wait_for_tx_end(ss, t); 4238c2ecf20Sopenharmony_ci } else { 4248c2ecf20Sopenharmony_ci sprd_spi_set_rx_length(ss, len); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * For our 3 wires mode or dual TX line mode, we need 4288c2ecf20Sopenharmony_ci * to request the controller to read. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) 4318c2ecf20Sopenharmony_ci sprd_spi_rx_req(ss); 4328c2ecf20Sopenharmony_ci else 4338c2ecf20Sopenharmony_ci write_size += ss->write_bufs(ss, len); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ret = sprd_spi_wait_for_rx_end(ss, t); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (ret) 4398c2ecf20Sopenharmony_ci goto complete; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (ss->trans_mode & SPRD_SPI_RX_MODE) 4428c2ecf20Sopenharmony_ci read_size += ss->read_bufs(ss, len); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci trans_len -= len; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (ss->trans_mode & SPRD_SPI_TX_MODE) 4488c2ecf20Sopenharmony_ci ret = write_size; 4498c2ecf20Sopenharmony_ci else 4508c2ecf20Sopenharmony_ci ret = read_size; 4518c2ecf20Sopenharmony_cicomplete: 4528c2ecf20Sopenharmony_ci sprd_spi_enter_idle(ss); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return ret; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic void sprd_spi_irq_enable(struct sprd_spi *ss) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci u32 val; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Clear interrupt status before enabling interrupt. */ 4628c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_TX_END_CLR | SPRD_SPI_RX_END_CLR, 4638c2ecf20Sopenharmony_ci ss->base + SPRD_SPI_INT_CLR); 4648c2ecf20Sopenharmony_ci /* Enable SPI interrupt only in DMA mode. */ 4658c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_INT_EN); 4668c2ecf20Sopenharmony_ci writel_relaxed(val | SPRD_SPI_TX_END_INT_EN | 4678c2ecf20Sopenharmony_ci SPRD_SPI_RX_END_INT_EN, 4688c2ecf20Sopenharmony_ci ss->base + SPRD_SPI_INT_EN); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic void sprd_spi_irq_disable(struct sprd_spi *ss) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci writel_relaxed(0, ss->base + SPRD_SPI_INT_EN); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void sprd_spi_dma_enable(struct sprd_spi *ss, bool enable) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL2); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (enable) 4818c2ecf20Sopenharmony_ci val |= SPRD_SPI_DMA_EN; 4828c2ecf20Sopenharmony_ci else 4838c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_DMA_EN; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL2); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int sprd_spi_dma_submit(struct dma_chan *dma_chan, 4898c2ecf20Sopenharmony_ci struct dma_slave_config *c, 4908c2ecf20Sopenharmony_ci struct sg_table *sg, 4918c2ecf20Sopenharmony_ci enum dma_transfer_direction dir) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *desc; 4948c2ecf20Sopenharmony_ci dma_cookie_t cookie; 4958c2ecf20Sopenharmony_ci unsigned long flags; 4968c2ecf20Sopenharmony_ci int ret; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(dma_chan, c); 4998c2ecf20Sopenharmony_ci if (ret < 0) 5008c2ecf20Sopenharmony_ci return ret; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE, SPRD_DMA_NO_TRG, 5038c2ecf20Sopenharmony_ci SPRD_DMA_FRAG_REQ, SPRD_DMA_TRANS_INT); 5048c2ecf20Sopenharmony_ci desc = dmaengine_prep_slave_sg(dma_chan, sg->sgl, sg->nents, dir, flags); 5058c2ecf20Sopenharmony_ci if (!desc) 5068c2ecf20Sopenharmony_ci return -ENODEV; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci cookie = dmaengine_submit(desc); 5098c2ecf20Sopenharmony_ci if (dma_submit_error(cookie)) 5108c2ecf20Sopenharmony_ci return dma_submit_error(cookie); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci dma_async_issue_pending(dma_chan); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int sprd_spi_dma_rx_config(struct sprd_spi *ss, struct spi_transfer *t) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct dma_chan *dma_chan = ss->dma.dma_chan[SPRD_SPI_RX]; 5208c2ecf20Sopenharmony_ci struct dma_slave_config config = { 5218c2ecf20Sopenharmony_ci .src_addr = ss->phy_base, 5228c2ecf20Sopenharmony_ci .src_addr_width = ss->dma.width, 5238c2ecf20Sopenharmony_ci .dst_addr_width = ss->dma.width, 5248c2ecf20Sopenharmony_ci .dst_maxburst = ss->dma.fragmens_len, 5258c2ecf20Sopenharmony_ci }; 5268c2ecf20Sopenharmony_ci int ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = sprd_spi_dma_submit(dma_chan, &config, &t->rx_sg, DMA_DEV_TO_MEM); 5298c2ecf20Sopenharmony_ci if (ret) 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return ss->dma.rx_len; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic int sprd_spi_dma_tx_config(struct sprd_spi *ss, struct spi_transfer *t) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct dma_chan *dma_chan = ss->dma.dma_chan[SPRD_SPI_TX]; 5388c2ecf20Sopenharmony_ci struct dma_slave_config config = { 5398c2ecf20Sopenharmony_ci .dst_addr = ss->phy_base, 5408c2ecf20Sopenharmony_ci .src_addr_width = ss->dma.width, 5418c2ecf20Sopenharmony_ci .dst_addr_width = ss->dma.width, 5428c2ecf20Sopenharmony_ci .src_maxburst = ss->dma.fragmens_len, 5438c2ecf20Sopenharmony_ci }; 5448c2ecf20Sopenharmony_ci int ret; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci ret = sprd_spi_dma_submit(dma_chan, &config, &t->tx_sg, DMA_MEM_TO_DEV); 5478c2ecf20Sopenharmony_ci if (ret) 5488c2ecf20Sopenharmony_ci return ret; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return t->len; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int sprd_spi_dma_request(struct sprd_spi *ss) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci ss->dma.dma_chan[SPRD_SPI_RX] = dma_request_chan(ss->dev, "rx_chn"); 5568c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ss->dma.dma_chan[SPRD_SPI_RX])) 5578c2ecf20Sopenharmony_ci return dev_err_probe(ss->dev, PTR_ERR(ss->dma.dma_chan[SPRD_SPI_RX]), 5588c2ecf20Sopenharmony_ci "request RX DMA channel failed!\n"); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci ss->dma.dma_chan[SPRD_SPI_TX] = dma_request_chan(ss->dev, "tx_chn"); 5618c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ss->dma.dma_chan[SPRD_SPI_TX])) { 5628c2ecf20Sopenharmony_ci dma_release_channel(ss->dma.dma_chan[SPRD_SPI_RX]); 5638c2ecf20Sopenharmony_ci return dev_err_probe(ss->dev, PTR_ERR(ss->dma.dma_chan[SPRD_SPI_TX]), 5648c2ecf20Sopenharmony_ci "request TX DMA channel failed!\n"); 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void sprd_spi_dma_release(struct sprd_spi *ss) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci if (ss->dma.dma_chan[SPRD_SPI_RX]) 5738c2ecf20Sopenharmony_ci dma_release_channel(ss->dma.dma_chan[SPRD_SPI_RX]); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (ss->dma.dma_chan[SPRD_SPI_TX]) 5768c2ecf20Sopenharmony_ci dma_release_channel(ss->dma.dma_chan[SPRD_SPI_TX]); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int sprd_spi_dma_txrx_bufs(struct spi_device *sdev, 5808c2ecf20Sopenharmony_ci struct spi_transfer *t) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_master_get_devdata(sdev->master); 5838c2ecf20Sopenharmony_ci u32 trans_len = ss->trans_len; 5848c2ecf20Sopenharmony_ci int ret, write_size = 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci reinit_completion(&ss->xfer_completion); 5878c2ecf20Sopenharmony_ci sprd_spi_irq_enable(ss); 5888c2ecf20Sopenharmony_ci if (ss->trans_mode & SPRD_SPI_TX_MODE) { 5898c2ecf20Sopenharmony_ci write_size = sprd_spi_dma_tx_config(ss, t); 5908c2ecf20Sopenharmony_ci sprd_spi_set_tx_length(ss, trans_len); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * For our 3 wires mode or dual TX line mode, we need 5948c2ecf20Sopenharmony_ci * to request the controller to transfer. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) 5978c2ecf20Sopenharmony_ci sprd_spi_tx_req(ss); 5988c2ecf20Sopenharmony_ci } else { 5998c2ecf20Sopenharmony_ci sprd_spi_set_rx_length(ss, trans_len); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * For our 3 wires mode or dual TX line mode, we need 6038c2ecf20Sopenharmony_ci * to request the controller to read. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) 6068c2ecf20Sopenharmony_ci sprd_spi_rx_req(ss); 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci write_size = ss->write_bufs(ss, trans_len); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (write_size < 0) { 6128c2ecf20Sopenharmony_ci ret = write_size; 6138c2ecf20Sopenharmony_ci dev_err(ss->dev, "failed to write, ret = %d\n", ret); 6148c2ecf20Sopenharmony_ci goto trans_complete; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (ss->trans_mode & SPRD_SPI_RX_MODE) { 6188c2ecf20Sopenharmony_ci /* 6198c2ecf20Sopenharmony_ci * Set up the DMA receive data length, which must be an 6208c2ecf20Sopenharmony_ci * integral multiple of fragment length. But when the length 6218c2ecf20Sopenharmony_ci * of received data is less than fragment length, DMA can be 6228c2ecf20Sopenharmony_ci * configured to receive data according to the actual length 6238c2ecf20Sopenharmony_ci * of received data. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci ss->dma.rx_len = t->len > ss->dma.fragmens_len ? 6268c2ecf20Sopenharmony_ci (t->len - t->len % ss->dma.fragmens_len) : 6278c2ecf20Sopenharmony_ci t->len; 6288c2ecf20Sopenharmony_ci ret = sprd_spi_dma_rx_config(ss, t); 6298c2ecf20Sopenharmony_ci if (ret < 0) { 6308c2ecf20Sopenharmony_ci dev_err(&sdev->dev, 6318c2ecf20Sopenharmony_ci "failed to configure rx DMA, ret = %d\n", ret); 6328c2ecf20Sopenharmony_ci goto trans_complete; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci sprd_spi_dma_enable(ss, true); 6378c2ecf20Sopenharmony_ci wait_for_completion(&(ss->xfer_completion)); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (ss->trans_mode & SPRD_SPI_TX_MODE) 6408c2ecf20Sopenharmony_ci ret = write_size; 6418c2ecf20Sopenharmony_ci else 6428c2ecf20Sopenharmony_ci ret = ss->dma.rx_len; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_citrans_complete: 6458c2ecf20Sopenharmony_ci sprd_spi_dma_enable(ss, false); 6468c2ecf20Sopenharmony_ci sprd_spi_enter_idle(ss); 6478c2ecf20Sopenharmony_ci sprd_spi_irq_disable(ss); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return ret; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci /* 6558c2ecf20Sopenharmony_ci * From SPI datasheet, the prescale calculation formula: 6568c2ecf20Sopenharmony_ci * prescale = SPI source clock / (2 * SPI_freq) - 1; 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_ci u32 clk_div = DIV_ROUND_UP(ss->src_clk, speed_hz << 1) - 1; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Save the real hardware speed */ 6618c2ecf20Sopenharmony_ci ss->hw_speed_hz = (ss->src_clk >> 1) / (clk_div + 1); 6628c2ecf20Sopenharmony_ci writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci struct spi_delay *d = &t->word_delay; 6688c2ecf20Sopenharmony_ci u16 word_delay, interval; 6698c2ecf20Sopenharmony_ci u32 val; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (d->unit != SPI_DELAY_UNIT_SCK) 6728c2ecf20Sopenharmony_ci return -EINVAL; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL0); 6758c2ecf20Sopenharmony_ci val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX); 6768c2ecf20Sopenharmony_ci /* Set default chip selection, clock phase and clock polarity */ 6778c2ecf20Sopenharmony_ci val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX; 6788c2ecf20Sopenharmony_ci val |= ss->hw_mode & SPI_CPOL ? SPRD_SPI_SCK_REV : 0; 6798c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL0); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* 6828c2ecf20Sopenharmony_ci * Set the intervals of two SPI frames, and the inteval calculation 6838c2ecf20Sopenharmony_ci * formula as below per datasheet: 6848c2ecf20Sopenharmony_ci * interval time (source clock cycles) = interval * 4 + 10. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci word_delay = clamp_t(u16, d->value, SPRD_SPI_MIN_DELAY_CYCLE, 6878c2ecf20Sopenharmony_ci SPRD_SPI_MAX_DELAY_CYCLE); 6888c2ecf20Sopenharmony_ci interval = DIV_ROUND_UP(word_delay - 10, 4); 6898c2ecf20Sopenharmony_ci ss->word_delay = interval * 4 + 10; 6908c2ecf20Sopenharmony_ci writel_relaxed(interval, ss->base + SPRD_SPI_CTL5); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Reset SPI fifo */ 6938c2ecf20Sopenharmony_ci writel_relaxed(1, ss->base + SPRD_SPI_FIFO_RST); 6948c2ecf20Sopenharmony_ci writel_relaxed(0, ss->base + SPRD_SPI_FIFO_RST); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Set SPI work mode */ 6978c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL7); 6988c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_MODE_MASK; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (ss->hw_mode & SPI_3WIRE) 7018c2ecf20Sopenharmony_ci val |= SPRD_SPI_3WIRE_MODE << SPRD_SPI_MODE_OFFSET; 7028c2ecf20Sopenharmony_ci else 7038c2ecf20Sopenharmony_ci val |= SPRD_SPI_4WIRE_MODE << SPRD_SPI_MODE_OFFSET; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (ss->hw_mode & SPI_TX_DUAL) 7068c2ecf20Sopenharmony_ci val |= SPRD_SPI_DATA_LINE2_EN; 7078c2ecf20Sopenharmony_ci else 7088c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_DATA_LINE2_EN; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci writel_relaxed(val, ss->base + SPRD_SPI_CTL7); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int sprd_spi_setup_transfer(struct spi_device *sdev, 7168c2ecf20Sopenharmony_ci struct spi_transfer *t) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); 7198c2ecf20Sopenharmony_ci u8 bits_per_word = t->bits_per_word; 7208c2ecf20Sopenharmony_ci u32 val, mode = 0; 7218c2ecf20Sopenharmony_ci int ret; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ss->len = t->len; 7248c2ecf20Sopenharmony_ci ss->tx_buf = t->tx_buf; 7258c2ecf20Sopenharmony_ci ss->rx_buf = t->rx_buf; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci ss->hw_mode = sdev->mode; 7288c2ecf20Sopenharmony_ci ret = sprd_spi_init_hw(ss, t); 7298c2ecf20Sopenharmony_ci if (ret) 7308c2ecf20Sopenharmony_ci return ret; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Set tansfer speed and valid bits */ 7338c2ecf20Sopenharmony_ci sprd_spi_set_speed(ss, t->speed_hz); 7348c2ecf20Sopenharmony_ci sprd_spi_set_transfer_bits(ss, bits_per_word); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (bits_per_word > 16) 7378c2ecf20Sopenharmony_ci bits_per_word = round_up(bits_per_word, 16); 7388c2ecf20Sopenharmony_ci else 7398c2ecf20Sopenharmony_ci bits_per_word = round_up(bits_per_word, 8); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci switch (bits_per_word) { 7428c2ecf20Sopenharmony_ci case 8: 7438c2ecf20Sopenharmony_ci ss->trans_len = t->len; 7448c2ecf20Sopenharmony_ci ss->read_bufs = sprd_spi_read_bufs_u8; 7458c2ecf20Sopenharmony_ci ss->write_bufs = sprd_spi_write_bufs_u8; 7468c2ecf20Sopenharmony_ci ss->dma.width = DMA_SLAVE_BUSWIDTH_1_BYTE; 7478c2ecf20Sopenharmony_ci ss->dma.fragmens_len = SPRD_SPI_DMA_STEP; 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci case 16: 7508c2ecf20Sopenharmony_ci ss->trans_len = t->len >> 1; 7518c2ecf20Sopenharmony_ci ss->read_bufs = sprd_spi_read_bufs_u16; 7528c2ecf20Sopenharmony_ci ss->write_bufs = sprd_spi_write_bufs_u16; 7538c2ecf20Sopenharmony_ci ss->dma.width = DMA_SLAVE_BUSWIDTH_2_BYTES; 7548c2ecf20Sopenharmony_ci ss->dma.fragmens_len = SPRD_SPI_DMA_STEP << 1; 7558c2ecf20Sopenharmony_ci break; 7568c2ecf20Sopenharmony_ci case 32: 7578c2ecf20Sopenharmony_ci ss->trans_len = t->len >> 2; 7588c2ecf20Sopenharmony_ci ss->read_bufs = sprd_spi_read_bufs_u32; 7598c2ecf20Sopenharmony_ci ss->write_bufs = sprd_spi_write_bufs_u32; 7608c2ecf20Sopenharmony_ci ss->dma.width = DMA_SLAVE_BUSWIDTH_4_BYTES; 7618c2ecf20Sopenharmony_ci ss->dma.fragmens_len = SPRD_SPI_DMA_STEP << 2; 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci default: 7648c2ecf20Sopenharmony_ci return -EINVAL; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Set transfer read or write mode */ 7688c2ecf20Sopenharmony_ci val = readl_relaxed(ss->base + SPRD_SPI_CTL1); 7698c2ecf20Sopenharmony_ci val &= ~SPRD_SPI_RTX_MD_MASK; 7708c2ecf20Sopenharmony_ci if (t->tx_buf) 7718c2ecf20Sopenharmony_ci mode |= SPRD_SPI_TX_MODE; 7728c2ecf20Sopenharmony_ci if (t->rx_buf) 7738c2ecf20Sopenharmony_ci mode |= SPRD_SPI_RX_MODE; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci writel_relaxed(val | mode, ss->base + SPRD_SPI_CTL1); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ss->trans_mode = mode; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* 7808c2ecf20Sopenharmony_ci * If in only receive mode, we need to trigger the SPI controller to 7818c2ecf20Sopenharmony_ci * receive data automatically. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci if (ss->trans_mode == SPRD_SPI_RX_MODE) 7848c2ecf20Sopenharmony_ci ss->write_bufs = sprd_spi_write_only_receive; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int sprd_spi_transfer_one(struct spi_controller *sctlr, 7908c2ecf20Sopenharmony_ci struct spi_device *sdev, 7918c2ecf20Sopenharmony_ci struct spi_transfer *t) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci int ret; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci ret = sprd_spi_setup_transfer(sdev, t); 7968c2ecf20Sopenharmony_ci if (ret) 7978c2ecf20Sopenharmony_ci goto setup_err; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (sctlr->can_dma(sctlr, sdev, t)) 8008c2ecf20Sopenharmony_ci ret = sprd_spi_dma_txrx_bufs(sdev, t); 8018c2ecf20Sopenharmony_ci else 8028c2ecf20Sopenharmony_ci ret = sprd_spi_txrx_bufs(sdev, t); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (ret == t->len) 8058c2ecf20Sopenharmony_ci ret = 0; 8068c2ecf20Sopenharmony_ci else if (ret >= 0) 8078c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cisetup_err: 8108c2ecf20Sopenharmony_ci spi_finalize_current_transfer(sctlr); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return ret; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic irqreturn_t sprd_spi_handle_irq(int irq, void *data) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct sprd_spi *ss = (struct sprd_spi *)data; 8188c2ecf20Sopenharmony_ci u32 val = readl_relaxed(ss->base + SPRD_SPI_INT_MASK_STS); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (val & SPRD_SPI_MASK_TX_END) { 8218c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_TX_END_CLR, ss->base + SPRD_SPI_INT_CLR); 8228c2ecf20Sopenharmony_ci if (!(ss->trans_mode & SPRD_SPI_RX_MODE)) 8238c2ecf20Sopenharmony_ci complete(&ss->xfer_completion); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (val & SPRD_SPI_MASK_RX_END) { 8298c2ecf20Sopenharmony_ci writel_relaxed(SPRD_SPI_RX_END_CLR, ss->base + SPRD_SPI_INT_CLR); 8308c2ecf20Sopenharmony_ci if (ss->dma.rx_len < ss->len) { 8318c2ecf20Sopenharmony_ci ss->rx_buf += ss->dma.rx_len; 8328c2ecf20Sopenharmony_ci ss->dma.rx_len += 8338c2ecf20Sopenharmony_ci ss->read_bufs(ss, ss->len - ss->dma.rx_len); 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci complete(&ss->xfer_completion); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci return IRQ_NONE; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int sprd_spi_irq_init(struct platform_device *pdev, struct sprd_spi *ss) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci int ret; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci ss->irq = platform_get_irq(pdev, 0); 8488c2ecf20Sopenharmony_ci if (ss->irq < 0) 8498c2ecf20Sopenharmony_ci return ss->irq; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, ss->irq, sprd_spi_handle_irq, 8528c2ecf20Sopenharmony_ci 0, pdev->name, ss); 8538c2ecf20Sopenharmony_ci if (ret) 8548c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request spi irq %d, ret = %d\n", 8558c2ecf20Sopenharmony_ci ss->irq, ret); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct clk *clk_spi, *clk_parent; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci clk_spi = devm_clk_get(&pdev->dev, "spi"); 8658c2ecf20Sopenharmony_ci if (IS_ERR(clk_spi)) { 8668c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "can't get the spi clock\n"); 8678c2ecf20Sopenharmony_ci clk_spi = NULL; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci clk_parent = devm_clk_get(&pdev->dev, "source"); 8718c2ecf20Sopenharmony_ci if (IS_ERR(clk_parent)) { 8728c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "can't get the source clock\n"); 8738c2ecf20Sopenharmony_ci clk_parent = NULL; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci ss->clk = devm_clk_get(&pdev->dev, "enable"); 8778c2ecf20Sopenharmony_ci if (IS_ERR(ss->clk)) { 8788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't get the enable clock\n"); 8798c2ecf20Sopenharmony_ci return PTR_ERR(ss->clk); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (!clk_set_parent(clk_spi, clk_parent)) 8838c2ecf20Sopenharmony_ci ss->src_clk = clk_get_rate(clk_spi); 8848c2ecf20Sopenharmony_ci else 8858c2ecf20Sopenharmony_ci ss->src_clk = SPRD_SPI_DEFAULT_SOURCE; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci return 0; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic bool sprd_spi_can_dma(struct spi_controller *sctlr, 8918c2ecf20Sopenharmony_ci struct spi_device *spi, struct spi_transfer *t) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sctlr); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return ss->dma.enable && (t->len > SPRD_SPI_FIFO_SIZE); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic int sprd_spi_dma_init(struct platform_device *pdev, struct sprd_spi *ss) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci int ret; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci ret = sprd_spi_dma_request(ss); 9038c2ecf20Sopenharmony_ci if (ret) { 9048c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 9058c2ecf20Sopenharmony_ci return ret; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 9088c2ecf20Sopenharmony_ci "failed to request dma, enter no dma mode, ret = %d\n", 9098c2ecf20Sopenharmony_ci ret); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci ss->dma.enable = true; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return 0; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic int sprd_spi_probe(struct platform_device *pdev) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct spi_controller *sctlr; 9228c2ecf20Sopenharmony_ci struct resource *res; 9238c2ecf20Sopenharmony_ci struct sprd_spi *ss; 9248c2ecf20Sopenharmony_ci int ret; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci pdev->id = of_alias_get_id(pdev->dev.of_node, "spi"); 9278c2ecf20Sopenharmony_ci sctlr = spi_alloc_master(&pdev->dev, sizeof(*ss)); 9288c2ecf20Sopenharmony_ci if (!sctlr) 9298c2ecf20Sopenharmony_ci return -ENOMEM; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci ss = spi_controller_get_devdata(sctlr); 9328c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9338c2ecf20Sopenharmony_ci ss->base = devm_ioremap_resource(&pdev->dev, res); 9348c2ecf20Sopenharmony_ci if (IS_ERR(ss->base)) { 9358c2ecf20Sopenharmony_ci ret = PTR_ERR(ss->base); 9368c2ecf20Sopenharmony_ci goto free_controller; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci ss->phy_base = res->start; 9408c2ecf20Sopenharmony_ci ss->dev = &pdev->dev; 9418c2ecf20Sopenharmony_ci sctlr->dev.of_node = pdev->dev.of_node; 9428c2ecf20Sopenharmony_ci sctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE | SPI_TX_DUAL; 9438c2ecf20Sopenharmony_ci sctlr->bus_num = pdev->id; 9448c2ecf20Sopenharmony_ci sctlr->set_cs = sprd_spi_chipselect; 9458c2ecf20Sopenharmony_ci sctlr->transfer_one = sprd_spi_transfer_one; 9468c2ecf20Sopenharmony_ci sctlr->can_dma = sprd_spi_can_dma; 9478c2ecf20Sopenharmony_ci sctlr->auto_runtime_pm = true; 9488c2ecf20Sopenharmony_ci sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1, 9498c2ecf20Sopenharmony_ci SPRD_SPI_MAX_SPEED_HZ); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci init_completion(&ss->xfer_completion); 9528c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, sctlr); 9538c2ecf20Sopenharmony_ci ret = sprd_spi_clk_init(pdev, ss); 9548c2ecf20Sopenharmony_ci if (ret) 9558c2ecf20Sopenharmony_ci goto free_controller; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci ret = sprd_spi_irq_init(pdev, ss); 9588c2ecf20Sopenharmony_ci if (ret) 9598c2ecf20Sopenharmony_ci goto free_controller; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci ret = sprd_spi_dma_init(pdev, ss); 9628c2ecf20Sopenharmony_ci if (ret) 9638c2ecf20Sopenharmony_ci goto free_controller; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ss->clk); 9668c2ecf20Sopenharmony_ci if (ret) 9678c2ecf20Sopenharmony_ci goto release_dma; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci ret = pm_runtime_set_active(&pdev->dev); 9708c2ecf20Sopenharmony_ci if (ret < 0) 9718c2ecf20Sopenharmony_ci goto disable_clk; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, 9748c2ecf20Sopenharmony_ci SPRD_SPI_AUTOSUSPEND_DELAY); 9758c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 9768c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 9778c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(&pdev->dev); 9788c2ecf20Sopenharmony_ci if (ret < 0) { 9798c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to resume SPI controller\n"); 9808c2ecf20Sopenharmony_ci goto err_rpm_put; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci ret = devm_spi_register_controller(&pdev->dev, sctlr); 9848c2ecf20Sopenharmony_ci if (ret) 9858c2ecf20Sopenharmony_ci goto err_rpm_put; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&pdev->dev); 9888c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&pdev->dev); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cierr_rpm_put: 9938c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 9948c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 9958c2ecf20Sopenharmony_cidisable_clk: 9968c2ecf20Sopenharmony_ci clk_disable_unprepare(ss->clk); 9978c2ecf20Sopenharmony_cirelease_dma: 9988c2ecf20Sopenharmony_ci sprd_spi_dma_release(ss); 9998c2ecf20Sopenharmony_cifree_controller: 10008c2ecf20Sopenharmony_ci spi_controller_put(sctlr); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return ret; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic int sprd_spi_remove(struct platform_device *pdev) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct spi_controller *sctlr = platform_get_drvdata(pdev); 10088c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sctlr); 10098c2ecf20Sopenharmony_ci int ret; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(ss->dev); 10128c2ecf20Sopenharmony_ci if (ret < 0) { 10138c2ecf20Sopenharmony_ci pm_runtime_put_noidle(ss->dev); 10148c2ecf20Sopenharmony_ci dev_err(ss->dev, "failed to resume SPI controller\n"); 10158c2ecf20Sopenharmony_ci return ret; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci spi_controller_suspend(sctlr); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (ss->dma.enable) 10218c2ecf20Sopenharmony_ci sprd_spi_dma_release(ss); 10228c2ecf20Sopenharmony_ci clk_disable_unprepare(ss->clk); 10238c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 10248c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int __maybe_unused sprd_spi_runtime_suspend(struct device *dev) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci struct spi_controller *sctlr = dev_get_drvdata(dev); 10328c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sctlr); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (ss->dma.enable) 10358c2ecf20Sopenharmony_ci sprd_spi_dma_release(ss); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci clk_disable_unprepare(ss->clk); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci return 0; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic int __maybe_unused sprd_spi_runtime_resume(struct device *dev) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct spi_controller *sctlr = dev_get_drvdata(dev); 10458c2ecf20Sopenharmony_ci struct sprd_spi *ss = spi_controller_get_devdata(sctlr); 10468c2ecf20Sopenharmony_ci int ret; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ss->clk); 10498c2ecf20Sopenharmony_ci if (ret) 10508c2ecf20Sopenharmony_ci return ret; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (!ss->dma.enable) 10538c2ecf20Sopenharmony_ci return 0; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci ret = sprd_spi_dma_request(ss); 10568c2ecf20Sopenharmony_ci if (ret) 10578c2ecf20Sopenharmony_ci clk_disable_unprepare(ss->clk); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return ret; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sprd_spi_pm_ops = { 10638c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(sprd_spi_runtime_suspend, 10648c2ecf20Sopenharmony_ci sprd_spi_runtime_resume, NULL) 10658c2ecf20Sopenharmony_ci}; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic const struct of_device_id sprd_spi_of_match[] = { 10688c2ecf20Sopenharmony_ci { .compatible = "sprd,sc9860-spi", }, 10698c2ecf20Sopenharmony_ci { /* sentinel */ } 10708c2ecf20Sopenharmony_ci}; 10718c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sprd_spi_of_match); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic struct platform_driver sprd_spi_driver = { 10748c2ecf20Sopenharmony_ci .driver = { 10758c2ecf20Sopenharmony_ci .name = "sprd-spi", 10768c2ecf20Sopenharmony_ci .of_match_table = sprd_spi_of_match, 10778c2ecf20Sopenharmony_ci .pm = &sprd_spi_pm_ops, 10788c2ecf20Sopenharmony_ci }, 10798c2ecf20Sopenharmony_ci .probe = sprd_spi_probe, 10808c2ecf20Sopenharmony_ci .remove = sprd_spi_remove, 10818c2ecf20Sopenharmony_ci}; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cimodule_platform_driver(sprd_spi_driver); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Spreadtrum SPI Controller driver"); 10868c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lanqing Liu <lanqing.liu@spreadtrum.com>"); 10878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1088