18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IMG SPFI controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007,2008,2013 Imagination Technologies Ltd. 68c2ecf20Sopenharmony_ci * Copyright (C) 2014 Google, Inc. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 228c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER(x) (0x00 + 0x4 * (x)) 258c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_BITCLK_SHIFT 24 268c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_BITCLK_MASK 0xff 278c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSSETUP_SHIFT 16 288c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSSETUP_MASK 0xff 298c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSHOLD_SHIFT 8 308c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSHOLD_MASK 0xff 318c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSDELAY_SHIFT 0 328c2ecf20Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSDELAY_MASK 0xff 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define SPFI_CONTROL 0x14 358c2ecf20Sopenharmony_ci#define SPFI_CONTROL_CONTINUE BIT(12) 368c2ecf20Sopenharmony_ci#define SPFI_CONTROL_SOFT_RESET BIT(11) 378c2ecf20Sopenharmony_ci#define SPFI_CONTROL_SEND_DMA BIT(10) 388c2ecf20Sopenharmony_ci#define SPFI_CONTROL_GET_DMA BIT(9) 398c2ecf20Sopenharmony_ci#define SPFI_CONTROL_SE BIT(8) 408c2ecf20Sopenharmony_ci#define SPFI_CONTROL_TMODE_SHIFT 5 418c2ecf20Sopenharmony_ci#define SPFI_CONTROL_TMODE_MASK 0x7 428c2ecf20Sopenharmony_ci#define SPFI_CONTROL_TMODE_SINGLE 0 438c2ecf20Sopenharmony_ci#define SPFI_CONTROL_TMODE_DUAL 1 448c2ecf20Sopenharmony_ci#define SPFI_CONTROL_TMODE_QUAD 2 458c2ecf20Sopenharmony_ci#define SPFI_CONTROL_SPFI_EN BIT(0) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define SPFI_TRANSACTION 0x18 488c2ecf20Sopenharmony_ci#define SPFI_TRANSACTION_TSIZE_SHIFT 16 498c2ecf20Sopenharmony_ci#define SPFI_TRANSACTION_TSIZE_MASK 0xffff 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define SPFI_PORT_STATE 0x1c 528c2ecf20Sopenharmony_ci#define SPFI_PORT_STATE_DEV_SEL_SHIFT 20 538c2ecf20Sopenharmony_ci#define SPFI_PORT_STATE_DEV_SEL_MASK 0x7 548c2ecf20Sopenharmony_ci#define SPFI_PORT_STATE_CK_POL(x) BIT(19 - (x)) 558c2ecf20Sopenharmony_ci#define SPFI_PORT_STATE_CK_PHASE(x) BIT(14 - (x)) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define SPFI_TX_32BIT_VALID_DATA 0x20 588c2ecf20Sopenharmony_ci#define SPFI_TX_8BIT_VALID_DATA 0x24 598c2ecf20Sopenharmony_ci#define SPFI_RX_32BIT_VALID_DATA 0x28 608c2ecf20Sopenharmony_ci#define SPFI_RX_8BIT_VALID_DATA 0x2c 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_STATUS 0x30 638c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_ENABLE 0x34 648c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_CLEAR 0x38 658c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_IACCESS BIT(12) 668c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_GDEX8BIT BIT(11) 678c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_ALLDONETRIG BIT(9) 688c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_GDFUL BIT(8) 698c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_GDHF BIT(7) 708c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_GDEX32BIT BIT(6) 718c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_GDTRIG BIT(5) 728c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_SDFUL BIT(3) 738c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_SDHF BIT(2) 748c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_SDE BIT(1) 758c2ecf20Sopenharmony_ci#define SPFI_INTERRUPT_SDTRIG BIT(0) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * There are four parallel FIFOs of 16 bytes each. The word buffer 798c2ecf20Sopenharmony_ci * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an 808c2ecf20Sopenharmony_ci * effective FIFO size of 64 bytes. The byte buffer (*_8BIT_VALID_DATA) 818c2ecf20Sopenharmony_ci * accesses only a single FIFO, resulting in an effective FIFO size of 828c2ecf20Sopenharmony_ci * 16 bytes. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci#define SPFI_32BIT_FIFO_SIZE 64 858c2ecf20Sopenharmony_ci#define SPFI_8BIT_FIFO_SIZE 16 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct img_spfi { 888c2ecf20Sopenharmony_ci struct device *dev; 898c2ecf20Sopenharmony_ci struct spi_master *master; 908c2ecf20Sopenharmony_ci spinlock_t lock; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci void __iomem *regs; 938c2ecf20Sopenharmony_ci phys_addr_t phys; 948c2ecf20Sopenharmony_ci int irq; 958c2ecf20Sopenharmony_ci struct clk *spfi_clk; 968c2ecf20Sopenharmony_ci struct clk *sys_clk; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci struct dma_chan *rx_ch; 998c2ecf20Sopenharmony_ci struct dma_chan *tx_ch; 1008c2ecf20Sopenharmony_ci bool tx_dma_busy; 1018c2ecf20Sopenharmony_ci bool rx_dma_busy; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return readl(spfi->regs + reg); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline void spfi_writel(struct img_spfi *spfi, u32 val, u32 reg) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci writel(val, spfi->regs + reg); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic inline void spfi_start(struct img_spfi *spfi) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci u32 val; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci val = spfi_readl(spfi, SPFI_CONTROL); 1198c2ecf20Sopenharmony_ci val |= SPFI_CONTROL_SPFI_EN; 1208c2ecf20Sopenharmony_ci spfi_writel(spfi, val, SPFI_CONTROL); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic inline void spfi_reset(struct img_spfi *spfi) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL); 1268c2ecf20Sopenharmony_ci spfi_writel(spfi, 0, SPFI_CONTROL); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int spfi_wait_all_done(struct img_spfi *spfi) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(50); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 1348c2ecf20Sopenharmony_ci u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (status & SPFI_INTERRUPT_ALLDONETRIG) { 1378c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG, 1388c2ecf20Sopenharmony_ci SPFI_INTERRUPT_CLEAR); 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci cpu_relax(); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci dev_err(spfi->dev, "Timed out waiting for transaction to complete\n"); 1458c2ecf20Sopenharmony_ci spfi_reset(spfi); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, 1518c2ecf20Sopenharmony_ci unsigned int max) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci unsigned int count = 0; 1548c2ecf20Sopenharmony_ci u32 status; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci while (count < max / 4) { 1578c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); 1588c2ecf20Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 1598c2ecf20Sopenharmony_ci if (status & SPFI_INTERRUPT_SDFUL) 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA); 1628c2ecf20Sopenharmony_ci count++; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return count * 4; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf, 1698c2ecf20Sopenharmony_ci unsigned int max) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci unsigned int count = 0; 1728c2ecf20Sopenharmony_ci u32 status; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci while (count < max) { 1758c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); 1768c2ecf20Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 1778c2ecf20Sopenharmony_ci if (status & SPFI_INTERRUPT_SDFUL) 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci spfi_writel(spfi, buf[count], SPFI_TX_8BIT_VALID_DATA); 1808c2ecf20Sopenharmony_ci count++; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return count; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf, 1878c2ecf20Sopenharmony_ci unsigned int max) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci unsigned int count = 0; 1908c2ecf20Sopenharmony_ci u32 status; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci while (count < max / 4) { 1938c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT, 1948c2ecf20Sopenharmony_ci SPFI_INTERRUPT_CLEAR); 1958c2ecf20Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 1968c2ecf20Sopenharmony_ci if (!(status & SPFI_INTERRUPT_GDEX32BIT)) 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci buf[count] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); 1998c2ecf20Sopenharmony_ci count++; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return count * 4; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf, 2068c2ecf20Sopenharmony_ci unsigned int max) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci unsigned int count = 0; 2098c2ecf20Sopenharmony_ci u32 status; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci while (count < max) { 2128c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_GDEX8BIT, 2138c2ecf20Sopenharmony_ci SPFI_INTERRUPT_CLEAR); 2148c2ecf20Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 2158c2ecf20Sopenharmony_ci if (!(status & SPFI_INTERRUPT_GDEX8BIT)) 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci buf[count] = spfi_readl(spfi, SPFI_RX_8BIT_VALID_DATA); 2188c2ecf20Sopenharmony_ci count++; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return count; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int img_spfi_start_pio(struct spi_master *master, 2258c2ecf20Sopenharmony_ci struct spi_device *spi, 2268c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(spi->master); 2298c2ecf20Sopenharmony_ci unsigned int tx_bytes = 0, rx_bytes = 0; 2308c2ecf20Sopenharmony_ci const void *tx_buf = xfer->tx_buf; 2318c2ecf20Sopenharmony_ci void *rx_buf = xfer->rx_buf; 2328c2ecf20Sopenharmony_ci unsigned long timeout; 2338c2ecf20Sopenharmony_ci int ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (tx_buf) 2368c2ecf20Sopenharmony_ci tx_bytes = xfer->len; 2378c2ecf20Sopenharmony_ci if (rx_buf) 2388c2ecf20Sopenharmony_ci rx_bytes = xfer->len; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci spfi_start(spfi); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci timeout = jiffies + 2438c2ecf20Sopenharmony_ci msecs_to_jiffies(xfer->len * 8 * 1000 / xfer->speed_hz + 100); 2448c2ecf20Sopenharmony_ci while ((tx_bytes > 0 || rx_bytes > 0) && 2458c2ecf20Sopenharmony_ci time_before(jiffies, timeout)) { 2468c2ecf20Sopenharmony_ci unsigned int tx_count, rx_count; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (tx_bytes >= 4) 2498c2ecf20Sopenharmony_ci tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes); 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (rx_bytes >= 4) 2548c2ecf20Sopenharmony_ci rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); 2558c2ecf20Sopenharmony_ci else 2568c2ecf20Sopenharmony_ci rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci tx_buf += tx_count; 2598c2ecf20Sopenharmony_ci rx_buf += rx_count; 2608c2ecf20Sopenharmony_ci tx_bytes -= tx_count; 2618c2ecf20Sopenharmony_ci rx_bytes -= rx_count; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci cpu_relax(); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (rx_bytes > 0 || tx_bytes > 0) { 2678c2ecf20Sopenharmony_ci dev_err(spfi->dev, "PIO transfer timed out\n"); 2688c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ret = spfi_wait_all_done(spfi); 2728c2ecf20Sopenharmony_ci if (ret < 0) 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void img_spfi_dma_rx_cb(void *data) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct img_spfi *spfi = data; 2818c2ecf20Sopenharmony_ci unsigned long flags; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci spfi_wait_all_done(spfi); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci spin_lock_irqsave(&spfi->lock, flags); 2868c2ecf20Sopenharmony_ci spfi->rx_dma_busy = false; 2878c2ecf20Sopenharmony_ci if (!spfi->tx_dma_busy) 2888c2ecf20Sopenharmony_ci spi_finalize_current_transfer(spfi->master); 2898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spfi->lock, flags); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void img_spfi_dma_tx_cb(void *data) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct img_spfi *spfi = data; 2958c2ecf20Sopenharmony_ci unsigned long flags; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci spfi_wait_all_done(spfi); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci spin_lock_irqsave(&spfi->lock, flags); 3008c2ecf20Sopenharmony_ci spfi->tx_dma_busy = false; 3018c2ecf20Sopenharmony_ci if (!spfi->rx_dma_busy) 3028c2ecf20Sopenharmony_ci spi_finalize_current_transfer(spfi->master); 3038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spfi->lock, flags); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int img_spfi_start_dma(struct spi_master *master, 3078c2ecf20Sopenharmony_ci struct spi_device *spi, 3088c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(spi->master); 3118c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; 3128c2ecf20Sopenharmony_ci struct dma_slave_config rxconf, txconf; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci spfi->rx_dma_busy = false; 3158c2ecf20Sopenharmony_ci spfi->tx_dma_busy = false; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (xfer->rx_buf) { 3188c2ecf20Sopenharmony_ci rxconf.direction = DMA_DEV_TO_MEM; 3198c2ecf20Sopenharmony_ci if (xfer->len % 4 == 0) { 3208c2ecf20Sopenharmony_ci rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; 3218c2ecf20Sopenharmony_ci rxconf.src_addr_width = 4; 3228c2ecf20Sopenharmony_ci rxconf.src_maxburst = 4; 3238c2ecf20Sopenharmony_ci } else { 3248c2ecf20Sopenharmony_ci rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; 3258c2ecf20Sopenharmony_ci rxconf.src_addr_width = 1; 3268c2ecf20Sopenharmony_ci rxconf.src_maxburst = 4; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci dmaengine_slave_config(spfi->rx_ch, &rxconf); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(spfi->rx_ch, xfer->rx_sg.sgl, 3318c2ecf20Sopenharmony_ci xfer->rx_sg.nents, 3328c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 3338c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT); 3348c2ecf20Sopenharmony_ci if (!rxdesc) 3358c2ecf20Sopenharmony_ci goto stop_dma; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci rxdesc->callback = img_spfi_dma_rx_cb; 3388c2ecf20Sopenharmony_ci rxdesc->callback_param = spfi; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (xfer->tx_buf) { 3428c2ecf20Sopenharmony_ci txconf.direction = DMA_MEM_TO_DEV; 3438c2ecf20Sopenharmony_ci if (xfer->len % 4 == 0) { 3448c2ecf20Sopenharmony_ci txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; 3458c2ecf20Sopenharmony_ci txconf.dst_addr_width = 4; 3468c2ecf20Sopenharmony_ci txconf.dst_maxburst = 4; 3478c2ecf20Sopenharmony_ci } else { 3488c2ecf20Sopenharmony_ci txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; 3498c2ecf20Sopenharmony_ci txconf.dst_addr_width = 1; 3508c2ecf20Sopenharmony_ci txconf.dst_maxburst = 4; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci dmaengine_slave_config(spfi->tx_ch, &txconf); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(spfi->tx_ch, xfer->tx_sg.sgl, 3558c2ecf20Sopenharmony_ci xfer->tx_sg.nents, 3568c2ecf20Sopenharmony_ci DMA_MEM_TO_DEV, 3578c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT); 3588c2ecf20Sopenharmony_ci if (!txdesc) 3598c2ecf20Sopenharmony_ci goto stop_dma; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci txdesc->callback = img_spfi_dma_tx_cb; 3628c2ecf20Sopenharmony_ci txdesc->callback_param = spfi; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (xfer->rx_buf) { 3668c2ecf20Sopenharmony_ci spfi->rx_dma_busy = true; 3678c2ecf20Sopenharmony_ci dmaengine_submit(rxdesc); 3688c2ecf20Sopenharmony_ci dma_async_issue_pending(spfi->rx_ch); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci spfi_start(spfi); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (xfer->tx_buf) { 3748c2ecf20Sopenharmony_ci spfi->tx_dma_busy = true; 3758c2ecf20Sopenharmony_ci dmaengine_submit(txdesc); 3768c2ecf20Sopenharmony_ci dma_async_issue_pending(spfi->tx_ch); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return 1; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistop_dma: 3828c2ecf20Sopenharmony_ci dmaengine_terminate_all(spfi->rx_ch); 3838c2ecf20Sopenharmony_ci dmaengine_terminate_all(spfi->tx_ch); 3848c2ecf20Sopenharmony_ci return -EIO; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void img_spfi_handle_err(struct spi_master *master, 3888c2ecf20Sopenharmony_ci struct spi_message *msg) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 3918c2ecf20Sopenharmony_ci unsigned long flags; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* 3948c2ecf20Sopenharmony_ci * Stop all DMA and reset the controller if the previous transaction 3958c2ecf20Sopenharmony_ci * timed-out and never completed it's DMA. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci spin_lock_irqsave(&spfi->lock, flags); 3988c2ecf20Sopenharmony_ci if (spfi->tx_dma_busy || spfi->rx_dma_busy) { 3998c2ecf20Sopenharmony_ci spfi->tx_dma_busy = false; 4008c2ecf20Sopenharmony_ci spfi->rx_dma_busy = false; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci dmaengine_terminate_all(spfi->tx_ch); 4038c2ecf20Sopenharmony_ci dmaengine_terminate_all(spfi->rx_ch); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spfi->lock, flags); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int img_spfi_prepare(struct spi_master *master, struct spi_message *msg) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 4118c2ecf20Sopenharmony_ci u32 val; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci val = spfi_readl(spfi, SPFI_PORT_STATE); 4148c2ecf20Sopenharmony_ci val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << 4158c2ecf20Sopenharmony_ci SPFI_PORT_STATE_DEV_SEL_SHIFT); 4168c2ecf20Sopenharmony_ci val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT; 4178c2ecf20Sopenharmony_ci if (msg->spi->mode & SPI_CPHA) 4188c2ecf20Sopenharmony_ci val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select); 4198c2ecf20Sopenharmony_ci else 4208c2ecf20Sopenharmony_ci val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select); 4218c2ecf20Sopenharmony_ci if (msg->spi->mode & SPI_CPOL) 4228c2ecf20Sopenharmony_ci val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select); 4238c2ecf20Sopenharmony_ci else 4248c2ecf20Sopenharmony_ci val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select); 4258c2ecf20Sopenharmony_ci spfi_writel(spfi, val, SPFI_PORT_STATE); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int img_spfi_unprepare(struct spi_master *master, 4318c2ecf20Sopenharmony_ci struct spi_message *msg) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci spfi_reset(spfi); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic void img_spfi_config(struct spi_master *master, struct spi_device *spi, 4418c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(spi->master); 4448c2ecf20Sopenharmony_ci u32 val, div; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* 4478c2ecf20Sopenharmony_ci * output = spfi_clk * (BITCLK / 512), where BITCLK must be a 4488c2ecf20Sopenharmony_ci * power of 2 up to 128 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_ci div = DIV_ROUND_UP(clk_get_rate(spfi->spfi_clk), xfer->speed_hz); 4518c2ecf20Sopenharmony_ci div = clamp(512 / (1 << get_count_order(div)), 1, 128); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select)); 4548c2ecf20Sopenharmony_ci val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK << 4558c2ecf20Sopenharmony_ci SPFI_DEVICE_PARAMETER_BITCLK_SHIFT); 4568c2ecf20Sopenharmony_ci val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; 4578c2ecf20Sopenharmony_ci spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select)); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT, 4608c2ecf20Sopenharmony_ci SPFI_TRANSACTION); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci val = spfi_readl(spfi, SPFI_CONTROL); 4638c2ecf20Sopenharmony_ci val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA); 4648c2ecf20Sopenharmony_ci if (xfer->tx_buf) 4658c2ecf20Sopenharmony_ci val |= SPFI_CONTROL_SEND_DMA; 4668c2ecf20Sopenharmony_ci if (xfer->rx_buf) 4678c2ecf20Sopenharmony_ci val |= SPFI_CONTROL_GET_DMA; 4688c2ecf20Sopenharmony_ci val &= ~(SPFI_CONTROL_TMODE_MASK << SPFI_CONTROL_TMODE_SHIFT); 4698c2ecf20Sopenharmony_ci if (xfer->tx_nbits == SPI_NBITS_DUAL && 4708c2ecf20Sopenharmony_ci xfer->rx_nbits == SPI_NBITS_DUAL) 4718c2ecf20Sopenharmony_ci val |= SPFI_CONTROL_TMODE_DUAL << SPFI_CONTROL_TMODE_SHIFT; 4728c2ecf20Sopenharmony_ci else if (xfer->tx_nbits == SPI_NBITS_QUAD && 4738c2ecf20Sopenharmony_ci xfer->rx_nbits == SPI_NBITS_QUAD) 4748c2ecf20Sopenharmony_ci val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; 4758c2ecf20Sopenharmony_ci val |= SPFI_CONTROL_SE; 4768c2ecf20Sopenharmony_ci spfi_writel(spfi, val, SPFI_CONTROL); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int img_spfi_transfer_one(struct spi_master *master, 4808c2ecf20Sopenharmony_ci struct spi_device *spi, 4818c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(spi->master); 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) { 4878c2ecf20Sopenharmony_ci dev_err(spfi->dev, 4888c2ecf20Sopenharmony_ci "Transfer length (%d) is greater than the max supported (%d)", 4898c2ecf20Sopenharmony_ci xfer->len, SPFI_TRANSACTION_TSIZE_MASK); 4908c2ecf20Sopenharmony_ci return -EINVAL; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci img_spfi_config(master, spi, xfer); 4948c2ecf20Sopenharmony_ci if (master->can_dma && master->can_dma(master, spi, xfer)) 4958c2ecf20Sopenharmony_ci ret = img_spfi_start_dma(master, spi, xfer); 4968c2ecf20Sopenharmony_ci else 4978c2ecf20Sopenharmony_ci ret = img_spfi_start_pio(master, spi, xfer); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return ret; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, 5038c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci if (xfer->len > SPFI_32BIT_FIFO_SIZE) 5068c2ecf20Sopenharmony_ci return true; 5078c2ecf20Sopenharmony_ci return false; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic irqreturn_t img_spfi_irq(int irq, void *dev_id) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct img_spfi *spfi = (struct img_spfi *)dev_id; 5138c2ecf20Sopenharmony_ci u32 status; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 5168c2ecf20Sopenharmony_ci if (status & SPFI_INTERRUPT_IACCESS) { 5178c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_CLEAR); 5188c2ecf20Sopenharmony_ci dev_err(spfi->dev, "Illegal access interrupt"); 5198c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return IRQ_NONE; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int img_spfi_probe(struct platform_device *pdev) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct spi_master *master; 5288c2ecf20Sopenharmony_ci struct img_spfi *spfi; 5298c2ecf20Sopenharmony_ci struct resource *res; 5308c2ecf20Sopenharmony_ci int ret; 5318c2ecf20Sopenharmony_ci u32 max_speed_hz; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); 5348c2ecf20Sopenharmony_ci if (!master) 5358c2ecf20Sopenharmony_ci return -ENOMEM; 5368c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, master); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci spfi = spi_master_get_devdata(master); 5398c2ecf20Sopenharmony_ci spfi->dev = &pdev->dev; 5408c2ecf20Sopenharmony_ci spfi->master = master; 5418c2ecf20Sopenharmony_ci spin_lock_init(&spfi->lock); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5448c2ecf20Sopenharmony_ci spfi->regs = devm_ioremap_resource(spfi->dev, res); 5458c2ecf20Sopenharmony_ci if (IS_ERR(spfi->regs)) { 5468c2ecf20Sopenharmony_ci ret = PTR_ERR(spfi->regs); 5478c2ecf20Sopenharmony_ci goto put_spi; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci spfi->phys = res->start; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci spfi->irq = platform_get_irq(pdev, 0); 5528c2ecf20Sopenharmony_ci if (spfi->irq < 0) { 5538c2ecf20Sopenharmony_ci ret = spfi->irq; 5548c2ecf20Sopenharmony_ci goto put_spi; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci ret = devm_request_irq(spfi->dev, spfi->irq, img_spfi_irq, 5578c2ecf20Sopenharmony_ci IRQ_TYPE_LEVEL_HIGH, dev_name(spfi->dev), spfi); 5588c2ecf20Sopenharmony_ci if (ret) 5598c2ecf20Sopenharmony_ci goto put_spi; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci spfi->sys_clk = devm_clk_get(spfi->dev, "sys"); 5628c2ecf20Sopenharmony_ci if (IS_ERR(spfi->sys_clk)) { 5638c2ecf20Sopenharmony_ci ret = PTR_ERR(spfi->sys_clk); 5648c2ecf20Sopenharmony_ci goto put_spi; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci spfi->spfi_clk = devm_clk_get(spfi->dev, "spfi"); 5678c2ecf20Sopenharmony_ci if (IS_ERR(spfi->spfi_clk)) { 5688c2ecf20Sopenharmony_ci ret = PTR_ERR(spfi->spfi_clk); 5698c2ecf20Sopenharmony_ci goto put_spi; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spfi->sys_clk); 5738c2ecf20Sopenharmony_ci if (ret) 5748c2ecf20Sopenharmony_ci goto put_spi; 5758c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spfi->spfi_clk); 5768c2ecf20Sopenharmony_ci if (ret) 5778c2ecf20Sopenharmony_ci goto disable_pclk; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci spfi_reset(spfi); 5808c2ecf20Sopenharmony_ci /* 5818c2ecf20Sopenharmony_ci * Only enable the error (IACCESS) interrupt. In PIO mode we'll 5828c2ecf20Sopenharmony_ci * poll the status of the FIFOs. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_ENABLE); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci master->auto_runtime_pm = true; 5878c2ecf20Sopenharmony_ci master->bus_num = pdev->id; 5888c2ecf20Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL; 5898c2ecf20Sopenharmony_ci if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode")) 5908c2ecf20Sopenharmony_ci master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; 5918c2ecf20Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 5928c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8); 5938c2ecf20Sopenharmony_ci master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; 5948c2ecf20Sopenharmony_ci master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Maximum speed supported by spfi is limited to the lower value 5988c2ecf20Sopenharmony_ci * between 1/4 of the SPFI clock or to "spfi-max-frequency" 5998c2ecf20Sopenharmony_ci * defined in the device tree. 6008c2ecf20Sopenharmony_ci * If no value is defined in the device tree assume the maximum 6018c2ecf20Sopenharmony_ci * speed supported to be 1/4 of the SPFI clock. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency", 6048c2ecf20Sopenharmony_ci &max_speed_hz)) { 6058c2ecf20Sopenharmony_ci if (master->max_speed_hz > max_speed_hz) 6068c2ecf20Sopenharmony_ci master->max_speed_hz = max_speed_hz; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci master->transfer_one = img_spfi_transfer_one; 6108c2ecf20Sopenharmony_ci master->prepare_message = img_spfi_prepare; 6118c2ecf20Sopenharmony_ci master->unprepare_message = img_spfi_unprepare; 6128c2ecf20Sopenharmony_ci master->handle_err = img_spfi_handle_err; 6138c2ecf20Sopenharmony_ci master->use_gpio_descriptors = true; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci spfi->tx_ch = dma_request_chan(spfi->dev, "tx"); 6168c2ecf20Sopenharmony_ci if (IS_ERR(spfi->tx_ch)) { 6178c2ecf20Sopenharmony_ci ret = PTR_ERR(spfi->tx_ch); 6188c2ecf20Sopenharmony_ci spfi->tx_ch = NULL; 6198c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 6208c2ecf20Sopenharmony_ci goto disable_pm; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci spfi->rx_ch = dma_request_chan(spfi->dev, "rx"); 6248c2ecf20Sopenharmony_ci if (IS_ERR(spfi->rx_ch)) { 6258c2ecf20Sopenharmony_ci ret = PTR_ERR(spfi->rx_ch); 6268c2ecf20Sopenharmony_ci spfi->rx_ch = NULL; 6278c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 6288c2ecf20Sopenharmony_ci goto disable_pm; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (!spfi->tx_ch || !spfi->rx_ch) { 6328c2ecf20Sopenharmony_ci if (spfi->tx_ch) 6338c2ecf20Sopenharmony_ci dma_release_channel(spfi->tx_ch); 6348c2ecf20Sopenharmony_ci if (spfi->rx_ch) 6358c2ecf20Sopenharmony_ci dma_release_channel(spfi->rx_ch); 6368c2ecf20Sopenharmony_ci spfi->tx_ch = NULL; 6378c2ecf20Sopenharmony_ci spfi->rx_ch = NULL; 6388c2ecf20Sopenharmony_ci dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n"); 6398c2ecf20Sopenharmony_ci } else { 6408c2ecf20Sopenharmony_ci master->dma_tx = spfi->tx_ch; 6418c2ecf20Sopenharmony_ci master->dma_rx = spfi->rx_ch; 6428c2ecf20Sopenharmony_ci master->can_dma = img_spfi_can_dma; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci pm_runtime_set_active(spfi->dev); 6468c2ecf20Sopenharmony_ci pm_runtime_enable(spfi->dev); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ret = devm_spi_register_master(spfi->dev, master); 6498c2ecf20Sopenharmony_ci if (ret) 6508c2ecf20Sopenharmony_ci goto disable_pm; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cidisable_pm: 6558c2ecf20Sopenharmony_ci pm_runtime_disable(spfi->dev); 6568c2ecf20Sopenharmony_ci if (spfi->rx_ch) 6578c2ecf20Sopenharmony_ci dma_release_channel(spfi->rx_ch); 6588c2ecf20Sopenharmony_ci if (spfi->tx_ch) 6598c2ecf20Sopenharmony_ci dma_release_channel(spfi->tx_ch); 6608c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->spfi_clk); 6618c2ecf20Sopenharmony_cidisable_pclk: 6628c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 6638c2ecf20Sopenharmony_ciput_spi: 6648c2ecf20Sopenharmony_ci spi_master_put(master); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return ret; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic int img_spfi_remove(struct platform_device *pdev) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct spi_master *master = platform_get_drvdata(pdev); 6728c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (spfi->tx_ch) 6758c2ecf20Sopenharmony_ci dma_release_channel(spfi->tx_ch); 6768c2ecf20Sopenharmony_ci if (spfi->rx_ch) 6778c2ecf20Sopenharmony_ci dma_release_channel(spfi->rx_ch); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci pm_runtime_disable(spfi->dev); 6808c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(spfi->dev)) { 6818c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->spfi_clk); 6828c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6898c2ecf20Sopenharmony_cistatic int img_spfi_runtime_suspend(struct device *dev) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 6928c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->spfi_clk); 6958c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return 0; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic int img_spfi_runtime_resume(struct device *dev) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 7038c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 7048c2ecf20Sopenharmony_ci int ret; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spfi->sys_clk); 7078c2ecf20Sopenharmony_ci if (ret) 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spfi->spfi_clk); 7108c2ecf20Sopenharmony_ci if (ret) { 7118c2ecf20Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 7128c2ecf20Sopenharmony_ci return ret; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7208c2ecf20Sopenharmony_cistatic int img_spfi_suspend(struct device *dev) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return spi_master_suspend(master); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic int img_spfi_resume(struct device *dev) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 7308c2ecf20Sopenharmony_ci struct img_spfi *spfi = spi_master_get_devdata(master); 7318c2ecf20Sopenharmony_ci int ret; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 7348c2ecf20Sopenharmony_ci if (ret < 0) { 7358c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 7368c2ecf20Sopenharmony_ci return ret; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci spfi_reset(spfi); 7398c2ecf20Sopenharmony_ci pm_runtime_put(dev); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return spi_master_resume(master); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic const struct dev_pm_ops img_spfi_pm_ops = { 7468c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(img_spfi_runtime_suspend, img_spfi_runtime_resume, 7478c2ecf20Sopenharmony_ci NULL) 7488c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(img_spfi_suspend, img_spfi_resume) 7498c2ecf20Sopenharmony_ci}; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic const struct of_device_id img_spfi_of_match[] = { 7528c2ecf20Sopenharmony_ci { .compatible = "img,spfi", }, 7538c2ecf20Sopenharmony_ci { }, 7548c2ecf20Sopenharmony_ci}; 7558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, img_spfi_of_match); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic struct platform_driver img_spfi_driver = { 7588c2ecf20Sopenharmony_ci .driver = { 7598c2ecf20Sopenharmony_ci .name = "img-spfi", 7608c2ecf20Sopenharmony_ci .pm = &img_spfi_pm_ops, 7618c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(img_spfi_of_match), 7628c2ecf20Sopenharmony_ci }, 7638c2ecf20Sopenharmony_ci .probe = img_spfi_probe, 7648c2ecf20Sopenharmony_ci .remove = img_spfi_remove, 7658c2ecf20Sopenharmony_ci}; 7668c2ecf20Sopenharmony_cimodule_platform_driver(img_spfi_driver); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IMG SPFI controller driver"); 7698c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); 7708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 771