162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IMG SPFI controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007,2008,2013 Imagination Technologies Ltd. 662306a36Sopenharmony_ci * Copyright (C) 2014 Google, Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/dmaengine.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/irq.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1962306a36Sopenharmony_ci#include <linux/scatterlist.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/spi/spi.h> 2262306a36Sopenharmony_ci#include <linux/spinlock.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER(x) (0x00 + 0x4 * (x)) 2562306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_BITCLK_SHIFT 24 2662306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_BITCLK_MASK 0xff 2762306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSSETUP_SHIFT 16 2862306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSSETUP_MASK 0xff 2962306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSHOLD_SHIFT 8 3062306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSHOLD_MASK 0xff 3162306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSDELAY_SHIFT 0 3262306a36Sopenharmony_ci#define SPFI_DEVICE_PARAMETER_CSDELAY_MASK 0xff 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define SPFI_CONTROL 0x14 3562306a36Sopenharmony_ci#define SPFI_CONTROL_CONTINUE BIT(12) 3662306a36Sopenharmony_ci#define SPFI_CONTROL_SOFT_RESET BIT(11) 3762306a36Sopenharmony_ci#define SPFI_CONTROL_SEND_DMA BIT(10) 3862306a36Sopenharmony_ci#define SPFI_CONTROL_GET_DMA BIT(9) 3962306a36Sopenharmony_ci#define SPFI_CONTROL_SE BIT(8) 4062306a36Sopenharmony_ci#define SPFI_CONTROL_TMODE_SHIFT 5 4162306a36Sopenharmony_ci#define SPFI_CONTROL_TMODE_MASK 0x7 4262306a36Sopenharmony_ci#define SPFI_CONTROL_TMODE_SINGLE 0 4362306a36Sopenharmony_ci#define SPFI_CONTROL_TMODE_DUAL 1 4462306a36Sopenharmony_ci#define SPFI_CONTROL_TMODE_QUAD 2 4562306a36Sopenharmony_ci#define SPFI_CONTROL_SPFI_EN BIT(0) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SPFI_TRANSACTION 0x18 4862306a36Sopenharmony_ci#define SPFI_TRANSACTION_TSIZE_SHIFT 16 4962306a36Sopenharmony_ci#define SPFI_TRANSACTION_TSIZE_MASK 0xffff 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SPFI_PORT_STATE 0x1c 5262306a36Sopenharmony_ci#define SPFI_PORT_STATE_DEV_SEL_SHIFT 20 5362306a36Sopenharmony_ci#define SPFI_PORT_STATE_DEV_SEL_MASK 0x7 5462306a36Sopenharmony_ci#define SPFI_PORT_STATE_CK_POL(x) BIT(19 - (x)) 5562306a36Sopenharmony_ci#define SPFI_PORT_STATE_CK_PHASE(x) BIT(14 - (x)) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define SPFI_TX_32BIT_VALID_DATA 0x20 5862306a36Sopenharmony_ci#define SPFI_TX_8BIT_VALID_DATA 0x24 5962306a36Sopenharmony_ci#define SPFI_RX_32BIT_VALID_DATA 0x28 6062306a36Sopenharmony_ci#define SPFI_RX_8BIT_VALID_DATA 0x2c 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define SPFI_INTERRUPT_STATUS 0x30 6362306a36Sopenharmony_ci#define SPFI_INTERRUPT_ENABLE 0x34 6462306a36Sopenharmony_ci#define SPFI_INTERRUPT_CLEAR 0x38 6562306a36Sopenharmony_ci#define SPFI_INTERRUPT_IACCESS BIT(12) 6662306a36Sopenharmony_ci#define SPFI_INTERRUPT_GDEX8BIT BIT(11) 6762306a36Sopenharmony_ci#define SPFI_INTERRUPT_ALLDONETRIG BIT(9) 6862306a36Sopenharmony_ci#define SPFI_INTERRUPT_GDFUL BIT(8) 6962306a36Sopenharmony_ci#define SPFI_INTERRUPT_GDHF BIT(7) 7062306a36Sopenharmony_ci#define SPFI_INTERRUPT_GDEX32BIT BIT(6) 7162306a36Sopenharmony_ci#define SPFI_INTERRUPT_GDTRIG BIT(5) 7262306a36Sopenharmony_ci#define SPFI_INTERRUPT_SDFUL BIT(3) 7362306a36Sopenharmony_ci#define SPFI_INTERRUPT_SDHF BIT(2) 7462306a36Sopenharmony_ci#define SPFI_INTERRUPT_SDE BIT(1) 7562306a36Sopenharmony_ci#define SPFI_INTERRUPT_SDTRIG BIT(0) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * There are four parallel FIFOs of 16 bytes each. The word buffer 7962306a36Sopenharmony_ci * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an 8062306a36Sopenharmony_ci * effective FIFO size of 64 bytes. The byte buffer (*_8BIT_VALID_DATA) 8162306a36Sopenharmony_ci * accesses only a single FIFO, resulting in an effective FIFO size of 8262306a36Sopenharmony_ci * 16 bytes. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci#define SPFI_32BIT_FIFO_SIZE 64 8562306a36Sopenharmony_ci#define SPFI_8BIT_FIFO_SIZE 16 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct img_spfi { 8862306a36Sopenharmony_ci struct device *dev; 8962306a36Sopenharmony_ci struct spi_controller *host; 9062306a36Sopenharmony_ci spinlock_t lock; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci void __iomem *regs; 9362306a36Sopenharmony_ci phys_addr_t phys; 9462306a36Sopenharmony_ci int irq; 9562306a36Sopenharmony_ci struct clk *spfi_clk; 9662306a36Sopenharmony_ci struct clk *sys_clk; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci struct dma_chan *rx_ch; 9962306a36Sopenharmony_ci struct dma_chan *tx_ch; 10062306a36Sopenharmony_ci bool tx_dma_busy; 10162306a36Sopenharmony_ci bool rx_dma_busy; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci return readl(spfi->regs + reg); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic inline void spfi_writel(struct img_spfi *spfi, u32 val, u32 reg) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci writel(val, spfi->regs + reg); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline void spfi_start(struct img_spfi *spfi) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci u32 val; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci val = spfi_readl(spfi, SPFI_CONTROL); 11962306a36Sopenharmony_ci val |= SPFI_CONTROL_SPFI_EN; 12062306a36Sopenharmony_ci spfi_writel(spfi, val, SPFI_CONTROL); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline void spfi_reset(struct img_spfi *spfi) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL); 12662306a36Sopenharmony_ci spfi_writel(spfi, 0, SPFI_CONTROL); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int spfi_wait_all_done(struct img_spfi *spfi) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(50); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci while (time_before(jiffies, timeout)) { 13462306a36Sopenharmony_ci u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (status & SPFI_INTERRUPT_ALLDONETRIG) { 13762306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG, 13862306a36Sopenharmony_ci SPFI_INTERRUPT_CLEAR); 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci cpu_relax(); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci dev_err(spfi->dev, "Timed out waiting for transaction to complete\n"); 14562306a36Sopenharmony_ci spfi_reset(spfi); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return -ETIMEDOUT; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, 15162306a36Sopenharmony_ci unsigned int max) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci unsigned int count = 0; 15462306a36Sopenharmony_ci u32 status; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci while (count < max / 4) { 15762306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); 15862306a36Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 15962306a36Sopenharmony_ci if (status & SPFI_INTERRUPT_SDFUL) 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA); 16262306a36Sopenharmony_ci count++; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return count * 4; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf, 16962306a36Sopenharmony_ci unsigned int max) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci unsigned int count = 0; 17262306a36Sopenharmony_ci u32 status; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci while (count < max) { 17562306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); 17662306a36Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 17762306a36Sopenharmony_ci if (status & SPFI_INTERRUPT_SDFUL) 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci spfi_writel(spfi, buf[count], SPFI_TX_8BIT_VALID_DATA); 18062306a36Sopenharmony_ci count++; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return count; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf, 18762306a36Sopenharmony_ci unsigned int max) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci unsigned int count = 0; 19062306a36Sopenharmony_ci u32 status; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci while (count < max / 4) { 19362306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT, 19462306a36Sopenharmony_ci SPFI_INTERRUPT_CLEAR); 19562306a36Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 19662306a36Sopenharmony_ci if (!(status & SPFI_INTERRUPT_GDEX32BIT)) 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci buf[count] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); 19962306a36Sopenharmony_ci count++; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return count * 4; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf, 20662306a36Sopenharmony_ci unsigned int max) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned int count = 0; 20962306a36Sopenharmony_ci u32 status; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci while (count < max) { 21262306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_GDEX8BIT, 21362306a36Sopenharmony_ci SPFI_INTERRUPT_CLEAR); 21462306a36Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 21562306a36Sopenharmony_ci if (!(status & SPFI_INTERRUPT_GDEX8BIT)) 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci buf[count] = spfi_readl(spfi, SPFI_RX_8BIT_VALID_DATA); 21862306a36Sopenharmony_ci count++; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return count; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int img_spfi_start_pio(struct spi_controller *host, 22562306a36Sopenharmony_ci struct spi_device *spi, 22662306a36Sopenharmony_ci struct spi_transfer *xfer) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(spi->controller); 22962306a36Sopenharmony_ci unsigned int tx_bytes = 0, rx_bytes = 0; 23062306a36Sopenharmony_ci const void *tx_buf = xfer->tx_buf; 23162306a36Sopenharmony_ci void *rx_buf = xfer->rx_buf; 23262306a36Sopenharmony_ci unsigned long timeout; 23362306a36Sopenharmony_ci int ret; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (tx_buf) 23662306a36Sopenharmony_ci tx_bytes = xfer->len; 23762306a36Sopenharmony_ci if (rx_buf) 23862306a36Sopenharmony_ci rx_bytes = xfer->len; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci spfi_start(spfi); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci timeout = jiffies + 24362306a36Sopenharmony_ci msecs_to_jiffies(xfer->len * 8 * 1000 / xfer->speed_hz + 100); 24462306a36Sopenharmony_ci while ((tx_bytes > 0 || rx_bytes > 0) && 24562306a36Sopenharmony_ci time_before(jiffies, timeout)) { 24662306a36Sopenharmony_ci unsigned int tx_count, rx_count; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (tx_bytes >= 4) 24962306a36Sopenharmony_ci tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes); 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (rx_bytes >= 4) 25462306a36Sopenharmony_ci rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); 25562306a36Sopenharmony_ci else 25662306a36Sopenharmony_ci rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci tx_buf += tx_count; 25962306a36Sopenharmony_ci rx_buf += rx_count; 26062306a36Sopenharmony_ci tx_bytes -= tx_count; 26162306a36Sopenharmony_ci rx_bytes -= rx_count; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci cpu_relax(); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (rx_bytes > 0 || tx_bytes > 0) { 26762306a36Sopenharmony_ci dev_err(spfi->dev, "PIO transfer timed out\n"); 26862306a36Sopenharmony_ci return -ETIMEDOUT; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ret = spfi_wait_all_done(spfi); 27262306a36Sopenharmony_ci if (ret < 0) 27362306a36Sopenharmony_ci return ret; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void img_spfi_dma_rx_cb(void *data) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct img_spfi *spfi = data; 28162306a36Sopenharmony_ci unsigned long flags; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci spfi_wait_all_done(spfi); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci spin_lock_irqsave(&spfi->lock, flags); 28662306a36Sopenharmony_ci spfi->rx_dma_busy = false; 28762306a36Sopenharmony_ci if (!spfi->tx_dma_busy) 28862306a36Sopenharmony_ci spi_finalize_current_transfer(spfi->host); 28962306a36Sopenharmony_ci spin_unlock_irqrestore(&spfi->lock, flags); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void img_spfi_dma_tx_cb(void *data) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct img_spfi *spfi = data; 29562306a36Sopenharmony_ci unsigned long flags; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spfi_wait_all_done(spfi); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci spin_lock_irqsave(&spfi->lock, flags); 30062306a36Sopenharmony_ci spfi->tx_dma_busy = false; 30162306a36Sopenharmony_ci if (!spfi->rx_dma_busy) 30262306a36Sopenharmony_ci spi_finalize_current_transfer(spfi->host); 30362306a36Sopenharmony_ci spin_unlock_irqrestore(&spfi->lock, flags); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int img_spfi_start_dma(struct spi_controller *host, 30762306a36Sopenharmony_ci struct spi_device *spi, 30862306a36Sopenharmony_ci struct spi_transfer *xfer) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(spi->controller); 31162306a36Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; 31262306a36Sopenharmony_ci struct dma_slave_config rxconf, txconf; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spfi->rx_dma_busy = false; 31562306a36Sopenharmony_ci spfi->tx_dma_busy = false; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (xfer->rx_buf) { 31862306a36Sopenharmony_ci rxconf.direction = DMA_DEV_TO_MEM; 31962306a36Sopenharmony_ci if (xfer->len % 4 == 0) { 32062306a36Sopenharmony_ci rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; 32162306a36Sopenharmony_ci rxconf.src_addr_width = 4; 32262306a36Sopenharmony_ci rxconf.src_maxburst = 4; 32362306a36Sopenharmony_ci } else { 32462306a36Sopenharmony_ci rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; 32562306a36Sopenharmony_ci rxconf.src_addr_width = 1; 32662306a36Sopenharmony_ci rxconf.src_maxburst = 4; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci dmaengine_slave_config(spfi->rx_ch, &rxconf); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(spfi->rx_ch, xfer->rx_sg.sgl, 33162306a36Sopenharmony_ci xfer->rx_sg.nents, 33262306a36Sopenharmony_ci DMA_DEV_TO_MEM, 33362306a36Sopenharmony_ci DMA_PREP_INTERRUPT); 33462306a36Sopenharmony_ci if (!rxdesc) 33562306a36Sopenharmony_ci goto stop_dma; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci rxdesc->callback = img_spfi_dma_rx_cb; 33862306a36Sopenharmony_ci rxdesc->callback_param = spfi; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (xfer->tx_buf) { 34262306a36Sopenharmony_ci txconf.direction = DMA_MEM_TO_DEV; 34362306a36Sopenharmony_ci if (xfer->len % 4 == 0) { 34462306a36Sopenharmony_ci txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; 34562306a36Sopenharmony_ci txconf.dst_addr_width = 4; 34662306a36Sopenharmony_ci txconf.dst_maxburst = 4; 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; 34962306a36Sopenharmony_ci txconf.dst_addr_width = 1; 35062306a36Sopenharmony_ci txconf.dst_maxburst = 4; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci dmaengine_slave_config(spfi->tx_ch, &txconf); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(spfi->tx_ch, xfer->tx_sg.sgl, 35562306a36Sopenharmony_ci xfer->tx_sg.nents, 35662306a36Sopenharmony_ci DMA_MEM_TO_DEV, 35762306a36Sopenharmony_ci DMA_PREP_INTERRUPT); 35862306a36Sopenharmony_ci if (!txdesc) 35962306a36Sopenharmony_ci goto stop_dma; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci txdesc->callback = img_spfi_dma_tx_cb; 36262306a36Sopenharmony_ci txdesc->callback_param = spfi; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (xfer->rx_buf) { 36662306a36Sopenharmony_ci spfi->rx_dma_busy = true; 36762306a36Sopenharmony_ci dmaengine_submit(rxdesc); 36862306a36Sopenharmony_ci dma_async_issue_pending(spfi->rx_ch); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci spfi_start(spfi); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (xfer->tx_buf) { 37462306a36Sopenharmony_ci spfi->tx_dma_busy = true; 37562306a36Sopenharmony_ci dmaengine_submit(txdesc); 37662306a36Sopenharmony_ci dma_async_issue_pending(spfi->tx_ch); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 1; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistop_dma: 38262306a36Sopenharmony_ci dmaengine_terminate_all(spfi->rx_ch); 38362306a36Sopenharmony_ci dmaengine_terminate_all(spfi->tx_ch); 38462306a36Sopenharmony_ci return -EIO; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void img_spfi_handle_err(struct spi_controller *host, 38862306a36Sopenharmony_ci struct spi_message *msg) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 39162306a36Sopenharmony_ci unsigned long flags; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* 39462306a36Sopenharmony_ci * Stop all DMA and reset the controller if the previous transaction 39562306a36Sopenharmony_ci * timed-out and never completed it's DMA. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci spin_lock_irqsave(&spfi->lock, flags); 39862306a36Sopenharmony_ci if (spfi->tx_dma_busy || spfi->rx_dma_busy) { 39962306a36Sopenharmony_ci spfi->tx_dma_busy = false; 40062306a36Sopenharmony_ci spfi->rx_dma_busy = false; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci dmaengine_terminate_all(spfi->tx_ch); 40362306a36Sopenharmony_ci dmaengine_terminate_all(spfi->rx_ch); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci spin_unlock_irqrestore(&spfi->lock, flags); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int img_spfi_prepare(struct spi_controller *host, struct spi_message *msg) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 41162306a36Sopenharmony_ci u32 val; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci val = spfi_readl(spfi, SPFI_PORT_STATE); 41462306a36Sopenharmony_ci val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << 41562306a36Sopenharmony_ci SPFI_PORT_STATE_DEV_SEL_SHIFT); 41662306a36Sopenharmony_ci val |= spi_get_chipselect(msg->spi, 0) << SPFI_PORT_STATE_DEV_SEL_SHIFT; 41762306a36Sopenharmony_ci if (msg->spi->mode & SPI_CPHA) 41862306a36Sopenharmony_ci val |= SPFI_PORT_STATE_CK_PHASE(spi_get_chipselect(msg->spi, 0)); 41962306a36Sopenharmony_ci else 42062306a36Sopenharmony_ci val &= ~SPFI_PORT_STATE_CK_PHASE(spi_get_chipselect(msg->spi, 0)); 42162306a36Sopenharmony_ci if (msg->spi->mode & SPI_CPOL) 42262306a36Sopenharmony_ci val |= SPFI_PORT_STATE_CK_POL(spi_get_chipselect(msg->spi, 0)); 42362306a36Sopenharmony_ci else 42462306a36Sopenharmony_ci val &= ~SPFI_PORT_STATE_CK_POL(spi_get_chipselect(msg->spi, 0)); 42562306a36Sopenharmony_ci spfi_writel(spfi, val, SPFI_PORT_STATE); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int img_spfi_unprepare(struct spi_controller *host, 43162306a36Sopenharmony_ci struct spi_message *msg) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci spfi_reset(spfi); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void img_spfi_config(struct spi_controller *host, struct spi_device *spi, 44162306a36Sopenharmony_ci struct spi_transfer *xfer) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(spi->controller); 44462306a36Sopenharmony_ci u32 val, div; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* 44762306a36Sopenharmony_ci * output = spfi_clk * (BITCLK / 512), where BITCLK must be a 44862306a36Sopenharmony_ci * power of 2 up to 128 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci div = DIV_ROUND_UP(clk_get_rate(spfi->spfi_clk), xfer->speed_hz); 45162306a36Sopenharmony_ci div = clamp(512 / (1 << get_count_order(div)), 1, 128); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi_get_chipselect(spi, 0))); 45462306a36Sopenharmony_ci val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK << 45562306a36Sopenharmony_ci SPFI_DEVICE_PARAMETER_BITCLK_SHIFT); 45662306a36Sopenharmony_ci val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; 45762306a36Sopenharmony_ci spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi_get_chipselect(spi, 0))); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT, 46062306a36Sopenharmony_ci SPFI_TRANSACTION); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci val = spfi_readl(spfi, SPFI_CONTROL); 46362306a36Sopenharmony_ci val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA); 46462306a36Sopenharmony_ci if (xfer->tx_buf) 46562306a36Sopenharmony_ci val |= SPFI_CONTROL_SEND_DMA; 46662306a36Sopenharmony_ci if (xfer->rx_buf) 46762306a36Sopenharmony_ci val |= SPFI_CONTROL_GET_DMA; 46862306a36Sopenharmony_ci val &= ~(SPFI_CONTROL_TMODE_MASK << SPFI_CONTROL_TMODE_SHIFT); 46962306a36Sopenharmony_ci if (xfer->tx_nbits == SPI_NBITS_DUAL && 47062306a36Sopenharmony_ci xfer->rx_nbits == SPI_NBITS_DUAL) 47162306a36Sopenharmony_ci val |= SPFI_CONTROL_TMODE_DUAL << SPFI_CONTROL_TMODE_SHIFT; 47262306a36Sopenharmony_ci else if (xfer->tx_nbits == SPI_NBITS_QUAD && 47362306a36Sopenharmony_ci xfer->rx_nbits == SPI_NBITS_QUAD) 47462306a36Sopenharmony_ci val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; 47562306a36Sopenharmony_ci val |= SPFI_CONTROL_SE; 47662306a36Sopenharmony_ci spfi_writel(spfi, val, SPFI_CONTROL); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int img_spfi_transfer_one(struct spi_controller *host, 48062306a36Sopenharmony_ci struct spi_device *spi, 48162306a36Sopenharmony_ci struct spi_transfer *xfer) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(spi->controller); 48462306a36Sopenharmony_ci int ret; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) { 48762306a36Sopenharmony_ci dev_err(spfi->dev, 48862306a36Sopenharmony_ci "Transfer length (%d) is greater than the max supported (%d)", 48962306a36Sopenharmony_ci xfer->len, SPFI_TRANSACTION_TSIZE_MASK); 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci img_spfi_config(host, spi, xfer); 49462306a36Sopenharmony_ci if (host->can_dma && host->can_dma(host, spi, xfer)) 49562306a36Sopenharmony_ci ret = img_spfi_start_dma(host, spi, xfer); 49662306a36Sopenharmony_ci else 49762306a36Sopenharmony_ci ret = img_spfi_start_pio(host, spi, xfer); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return ret; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic bool img_spfi_can_dma(struct spi_controller *host, struct spi_device *spi, 50362306a36Sopenharmony_ci struct spi_transfer *xfer) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci if (xfer->len > SPFI_32BIT_FIFO_SIZE) 50662306a36Sopenharmony_ci return true; 50762306a36Sopenharmony_ci return false; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic irqreturn_t img_spfi_irq(int irq, void *dev_id) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct img_spfi *spfi = (struct img_spfi *)dev_id; 51362306a36Sopenharmony_ci u32 status; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); 51662306a36Sopenharmony_ci if (status & SPFI_INTERRUPT_IACCESS) { 51762306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_CLEAR); 51862306a36Sopenharmony_ci dev_err(spfi->dev, "Illegal access interrupt"); 51962306a36Sopenharmony_ci return IRQ_HANDLED; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return IRQ_NONE; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int img_spfi_probe(struct platform_device *pdev) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct spi_controller *host; 52862306a36Sopenharmony_ci struct img_spfi *spfi; 52962306a36Sopenharmony_ci struct resource *res; 53062306a36Sopenharmony_ci int ret; 53162306a36Sopenharmony_ci u32 max_speed_hz; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci host = spi_alloc_host(&pdev->dev, sizeof(*spfi)); 53462306a36Sopenharmony_ci if (!host) 53562306a36Sopenharmony_ci return -ENOMEM; 53662306a36Sopenharmony_ci platform_set_drvdata(pdev, host); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci spfi = spi_controller_get_devdata(host); 53962306a36Sopenharmony_ci spfi->dev = &pdev->dev; 54062306a36Sopenharmony_ci spfi->host = host; 54162306a36Sopenharmony_ci spin_lock_init(&spfi->lock); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci spfi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 54462306a36Sopenharmony_ci if (IS_ERR(spfi->regs)) { 54562306a36Sopenharmony_ci ret = PTR_ERR(spfi->regs); 54662306a36Sopenharmony_ci goto put_spi; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci spfi->phys = res->start; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci spfi->irq = platform_get_irq(pdev, 0); 55162306a36Sopenharmony_ci if (spfi->irq < 0) { 55262306a36Sopenharmony_ci ret = spfi->irq; 55362306a36Sopenharmony_ci goto put_spi; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci ret = devm_request_irq(spfi->dev, spfi->irq, img_spfi_irq, 55662306a36Sopenharmony_ci IRQ_TYPE_LEVEL_HIGH, dev_name(spfi->dev), spfi); 55762306a36Sopenharmony_ci if (ret) 55862306a36Sopenharmony_ci goto put_spi; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci spfi->sys_clk = devm_clk_get(spfi->dev, "sys"); 56162306a36Sopenharmony_ci if (IS_ERR(spfi->sys_clk)) { 56262306a36Sopenharmony_ci ret = PTR_ERR(spfi->sys_clk); 56362306a36Sopenharmony_ci goto put_spi; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci spfi->spfi_clk = devm_clk_get(spfi->dev, "spfi"); 56662306a36Sopenharmony_ci if (IS_ERR(spfi->spfi_clk)) { 56762306a36Sopenharmony_ci ret = PTR_ERR(spfi->spfi_clk); 56862306a36Sopenharmony_ci goto put_spi; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ret = clk_prepare_enable(spfi->sys_clk); 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci goto put_spi; 57462306a36Sopenharmony_ci ret = clk_prepare_enable(spfi->spfi_clk); 57562306a36Sopenharmony_ci if (ret) 57662306a36Sopenharmony_ci goto disable_pclk; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci spfi_reset(spfi); 57962306a36Sopenharmony_ci /* 58062306a36Sopenharmony_ci * Only enable the error (IACCESS) interrupt. In PIO mode we'll 58162306a36Sopenharmony_ci * poll the status of the FIFOs. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_ENABLE); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci host->auto_runtime_pm = true; 58662306a36Sopenharmony_ci host->bus_num = pdev->id; 58762306a36Sopenharmony_ci host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL; 58862306a36Sopenharmony_ci if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode")) 58962306a36Sopenharmony_ci host->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; 59062306a36Sopenharmony_ci host->dev.of_node = pdev->dev.of_node; 59162306a36Sopenharmony_ci host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8); 59262306a36Sopenharmony_ci host->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; 59362306a36Sopenharmony_ci host->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* 59662306a36Sopenharmony_ci * Maximum speed supported by spfi is limited to the lower value 59762306a36Sopenharmony_ci * between 1/4 of the SPFI clock or to "spfi-max-frequency" 59862306a36Sopenharmony_ci * defined in the device tree. 59962306a36Sopenharmony_ci * If no value is defined in the device tree assume the maximum 60062306a36Sopenharmony_ci * speed supported to be 1/4 of the SPFI clock. 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_ci if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency", 60362306a36Sopenharmony_ci &max_speed_hz)) { 60462306a36Sopenharmony_ci if (host->max_speed_hz > max_speed_hz) 60562306a36Sopenharmony_ci host->max_speed_hz = max_speed_hz; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci host->transfer_one = img_spfi_transfer_one; 60962306a36Sopenharmony_ci host->prepare_message = img_spfi_prepare; 61062306a36Sopenharmony_ci host->unprepare_message = img_spfi_unprepare; 61162306a36Sopenharmony_ci host->handle_err = img_spfi_handle_err; 61262306a36Sopenharmony_ci host->use_gpio_descriptors = true; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci spfi->tx_ch = dma_request_chan(spfi->dev, "tx"); 61562306a36Sopenharmony_ci if (IS_ERR(spfi->tx_ch)) { 61662306a36Sopenharmony_ci ret = PTR_ERR(spfi->tx_ch); 61762306a36Sopenharmony_ci spfi->tx_ch = NULL; 61862306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 61962306a36Sopenharmony_ci goto disable_pm; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci spfi->rx_ch = dma_request_chan(spfi->dev, "rx"); 62362306a36Sopenharmony_ci if (IS_ERR(spfi->rx_ch)) { 62462306a36Sopenharmony_ci ret = PTR_ERR(spfi->rx_ch); 62562306a36Sopenharmony_ci spfi->rx_ch = NULL; 62662306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 62762306a36Sopenharmony_ci goto disable_pm; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!spfi->tx_ch || !spfi->rx_ch) { 63162306a36Sopenharmony_ci if (spfi->tx_ch) 63262306a36Sopenharmony_ci dma_release_channel(spfi->tx_ch); 63362306a36Sopenharmony_ci if (spfi->rx_ch) 63462306a36Sopenharmony_ci dma_release_channel(spfi->rx_ch); 63562306a36Sopenharmony_ci spfi->tx_ch = NULL; 63662306a36Sopenharmony_ci spfi->rx_ch = NULL; 63762306a36Sopenharmony_ci dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n"); 63862306a36Sopenharmony_ci } else { 63962306a36Sopenharmony_ci host->dma_tx = spfi->tx_ch; 64062306a36Sopenharmony_ci host->dma_rx = spfi->rx_ch; 64162306a36Sopenharmony_ci host->can_dma = img_spfi_can_dma; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci pm_runtime_set_active(spfi->dev); 64562306a36Sopenharmony_ci pm_runtime_enable(spfi->dev); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ret = devm_spi_register_controller(spfi->dev, host); 64862306a36Sopenharmony_ci if (ret) 64962306a36Sopenharmony_ci goto disable_pm; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cidisable_pm: 65462306a36Sopenharmony_ci pm_runtime_disable(spfi->dev); 65562306a36Sopenharmony_ci if (spfi->rx_ch) 65662306a36Sopenharmony_ci dma_release_channel(spfi->rx_ch); 65762306a36Sopenharmony_ci if (spfi->tx_ch) 65862306a36Sopenharmony_ci dma_release_channel(spfi->tx_ch); 65962306a36Sopenharmony_ci clk_disable_unprepare(spfi->spfi_clk); 66062306a36Sopenharmony_cidisable_pclk: 66162306a36Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 66262306a36Sopenharmony_ciput_spi: 66362306a36Sopenharmony_ci spi_controller_put(host); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return ret; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void img_spfi_remove(struct platform_device *pdev) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct spi_controller *host = platform_get_drvdata(pdev); 67162306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (spfi->tx_ch) 67462306a36Sopenharmony_ci dma_release_channel(spfi->tx_ch); 67562306a36Sopenharmony_ci if (spfi->rx_ch) 67662306a36Sopenharmony_ci dma_release_channel(spfi->rx_ch); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci pm_runtime_disable(spfi->dev); 67962306a36Sopenharmony_ci if (!pm_runtime_status_suspended(spfi->dev)) { 68062306a36Sopenharmony_ci clk_disable_unprepare(spfi->spfi_clk); 68162306a36Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci#ifdef CONFIG_PM 68662306a36Sopenharmony_cistatic int img_spfi_runtime_suspend(struct device *dev) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct spi_controller *host = dev_get_drvdata(dev); 68962306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci clk_disable_unprepare(spfi->spfi_clk); 69262306a36Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return 0; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int img_spfi_runtime_resume(struct device *dev) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct spi_controller *host = dev_get_drvdata(dev); 70062306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 70162306a36Sopenharmony_ci int ret; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci ret = clk_prepare_enable(spfi->sys_clk); 70462306a36Sopenharmony_ci if (ret) 70562306a36Sopenharmony_ci return ret; 70662306a36Sopenharmony_ci ret = clk_prepare_enable(spfi->spfi_clk); 70762306a36Sopenharmony_ci if (ret) { 70862306a36Sopenharmony_ci clk_disable_unprepare(spfi->sys_clk); 70962306a36Sopenharmony_ci return ret; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci#endif /* CONFIG_PM */ 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 71762306a36Sopenharmony_cistatic int img_spfi_suspend(struct device *dev) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct spi_controller *host = dev_get_drvdata(dev); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return spi_controller_suspend(host); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int img_spfi_resume(struct device *dev) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct spi_controller *host = dev_get_drvdata(dev); 72762306a36Sopenharmony_ci struct img_spfi *spfi = spi_controller_get_devdata(host); 72862306a36Sopenharmony_ci int ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 73162306a36Sopenharmony_ci if (ret < 0) 73262306a36Sopenharmony_ci return ret; 73362306a36Sopenharmony_ci spfi_reset(spfi); 73462306a36Sopenharmony_ci pm_runtime_put(dev); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return spi_controller_resume(host); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic const struct dev_pm_ops img_spfi_pm_ops = { 74162306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(img_spfi_runtime_suspend, img_spfi_runtime_resume, 74262306a36Sopenharmony_ci NULL) 74362306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(img_spfi_suspend, img_spfi_resume) 74462306a36Sopenharmony_ci}; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic const struct of_device_id img_spfi_of_match[] = { 74762306a36Sopenharmony_ci { .compatible = "img,spfi", }, 74862306a36Sopenharmony_ci { }, 74962306a36Sopenharmony_ci}; 75062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, img_spfi_of_match); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic struct platform_driver img_spfi_driver = { 75362306a36Sopenharmony_ci .driver = { 75462306a36Sopenharmony_ci .name = "img-spfi", 75562306a36Sopenharmony_ci .pm = &img_spfi_pm_ops, 75662306a36Sopenharmony_ci .of_match_table = of_match_ptr(img_spfi_of_match), 75762306a36Sopenharmony_ci }, 75862306a36Sopenharmony_ci .probe = img_spfi_probe, 75962306a36Sopenharmony_ci .remove_new = img_spfi_remove, 76062306a36Sopenharmony_ci}; 76162306a36Sopenharmony_cimodule_platform_driver(img_spfi_driver); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ciMODULE_DESCRIPTION("IMG SPFI controller driver"); 76462306a36Sopenharmony_ciMODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); 76562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 766