Blame view
drivers/spi/spi-rockchip.c
22.9 KB
2025cf9e1 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
64e36824b spi/rockchip: add... |
2 3 |
/* * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd |
5dcc44ed9 spi/rockchip: cle... |
4 |
* Author: Addy Ke <addy.ke@rock-chips.com> |
64e36824b spi/rockchip: add... |
5 |
*/ |
64e36824b spi/rockchip: add... |
6 |
#include <linux/clk.h> |
ec5c5d8ac spi: rockchip: he... |
7 |
#include <linux/dmaengine.h> |
8af0c18af include/: refacto... |
8 |
#include <linux/interrupt.h> |
ec5c5d8ac spi: rockchip: he... |
9 10 |
#include <linux/module.h> #include <linux/of.h> |
23e291c2e spi: rockchip: su... |
11 |
#include <linux/pinctrl/consumer.h> |
64e36824b spi/rockchip: add... |
12 |
#include <linux/platform_device.h> |
64e36824b spi/rockchip: add... |
13 |
#include <linux/spi/spi.h> |
64e36824b spi/rockchip: add... |
14 |
#include <linux/pm_runtime.h> |
ec5c5d8ac spi: rockchip: he... |
15 |
#include <linux/scatterlist.h> |
64e36824b spi/rockchip: add... |
16 17 |
#define DRIVER_NAME "rockchip-spi" |
aa099382a spi: rockchip: Di... |
18 19 20 21 |
#define ROCKCHIP_SPI_CLR_BITS(reg, bits) \ writel_relaxed(readl_relaxed(reg) & ~(bits), reg) #define ROCKCHIP_SPI_SET_BITS(reg, bits) \ writel_relaxed(readl_relaxed(reg) | (bits), reg) |
64e36824b spi/rockchip: add... |
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/* SPI register offsets */ #define ROCKCHIP_SPI_CTRLR0 0x0000 #define ROCKCHIP_SPI_CTRLR1 0x0004 #define ROCKCHIP_SPI_SSIENR 0x0008 #define ROCKCHIP_SPI_SER 0x000c #define ROCKCHIP_SPI_BAUDR 0x0010 #define ROCKCHIP_SPI_TXFTLR 0x0014 #define ROCKCHIP_SPI_RXFTLR 0x0018 #define ROCKCHIP_SPI_TXFLR 0x001c #define ROCKCHIP_SPI_RXFLR 0x0020 #define ROCKCHIP_SPI_SR 0x0024 #define ROCKCHIP_SPI_IPR 0x0028 #define ROCKCHIP_SPI_IMR 0x002c #define ROCKCHIP_SPI_ISR 0x0030 #define ROCKCHIP_SPI_RISR 0x0034 #define ROCKCHIP_SPI_ICR 0x0038 #define ROCKCHIP_SPI_DMACR 0x003c |
13a96935e spi: rockchip: Su... |
39 40 41 |
#define ROCKCHIP_SPI_DMATDLR 0x0040 #define ROCKCHIP_SPI_DMARDLR 0x0044 #define ROCKCHIP_SPI_VERSION 0x0048 |
64e36824b spi/rockchip: add... |
42 43 44 45 46 |
#define ROCKCHIP_SPI_TXDR 0x0400 #define ROCKCHIP_SPI_RXDR 0x0800 /* Bit fields in CTRLR0 */ #define CR0_DFS_OFFSET 0 |
65498c6ae spi: rockchip: su... |
47 48 49 |
#define CR0_DFS_4BIT 0x0 #define CR0_DFS_8BIT 0x1 #define CR0_DFS_16BIT 0x2 |
64e36824b spi/rockchip: add... |
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#define CR0_CFS_OFFSET 2 #define CR0_SCPH_OFFSET 6 #define CR0_SCPOL_OFFSET 7 #define CR0_CSM_OFFSET 8 #define CR0_CSM_KEEP 0x0 /* ss_n be high for half sclk_out cycles */ #define CR0_CSM_HALF 0X1 /* ss_n be high for one sclk_out cycle */ #define CR0_CSM_ONE 0x2 /* ss_n to sclk_out delay */ #define CR0_SSD_OFFSET 10 /* * The period between ss_n active and * sclk_out active is half sclk_out cycles */ #define CR0_SSD_HALF 0x0 /* * The period between ss_n active and * sclk_out active is one sclk_out cycle */ #define CR0_SSD_ONE 0x1 #define CR0_EM_OFFSET 11 #define CR0_EM_LITTLE 0x0 #define CR0_EM_BIG 0x1 #define CR0_FBM_OFFSET 12 #define CR0_FBM_MSB 0x0 #define CR0_FBM_LSB 0x1 #define CR0_BHT_OFFSET 13 #define CR0_BHT_16BIT 0x0 #define CR0_BHT_8BIT 0x1 #define CR0_RSD_OFFSET 14 |
74b7efa82 spi: rockchip: pr... |
90 |
#define CR0_RSD_MAX 0x3 |
64e36824b spi/rockchip: add... |
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
#define CR0_FRF_OFFSET 16 #define CR0_FRF_SPI 0x0 #define CR0_FRF_SSP 0x1 #define CR0_FRF_MICROWIRE 0x2 #define CR0_XFM_OFFSET 18 #define CR0_XFM_MASK (0x03 << SPI_XFM_OFFSET) #define CR0_XFM_TR 0x0 #define CR0_XFM_TO 0x1 #define CR0_XFM_RO 0x2 #define CR0_OPM_OFFSET 20 #define CR0_OPM_MASTER 0x0 #define CR0_OPM_SLAVE 0x1 #define CR0_MTM_OFFSET 0x21 /* Bit fields in SER, 2bit */ #define SER_MASK 0x3 |
420b82f84 spi: rockchip: se... |
111 112 113 |
/* Bit fields in BAUDR */ #define BAUDR_SCKDV_MIN 2 #define BAUDR_SCKDV_MAX 65534 |
64e36824b spi/rockchip: add... |
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
/* Bit fields in SR, 5bit */ #define SR_MASK 0x1f #define SR_BUSY (1 << 0) #define SR_TF_FULL (1 << 1) #define SR_TF_EMPTY (1 << 2) #define SR_RF_EMPTY (1 << 3) #define SR_RF_FULL (1 << 4) /* Bit fields in ISR, IMR, ISR, RISR, 5bit */ #define INT_MASK 0x1f #define INT_TF_EMPTY (1 << 0) #define INT_TF_OVERFLOW (1 << 1) #define INT_RF_UNDERFLOW (1 << 2) #define INT_RF_OVERFLOW (1 << 3) #define INT_RF_FULL (1 << 4) /* Bit fields in ICR, 4bit */ #define ICR_MASK 0x0f #define ICR_ALL (1 << 0) #define ICR_RF_UNDERFLOW (1 << 1) #define ICR_RF_OVERFLOW (1 << 2) #define ICR_TF_OVERFLOW (1 << 3) /* Bit fields in DMACR */ #define RF_DMA_EN (1 << 0) #define TF_DMA_EN (1 << 1) |
fab3e4871 spi: rockchip: us... |
140 141 142 |
/* Driver state flags */ #define RXDMA (1 << 0) #define TXDMA (1 << 1) |
64e36824b spi/rockchip: add... |
143 |
|
f9cfd5226 spi/rockchip: fix... |
144 |
/* sclk_out: spi master internal logic in rk3x can support 50Mhz */ |
420b82f84 spi: rockchip: se... |
145 |
#define MAX_SCLK_OUT 50000000U |
f9cfd5226 spi/rockchip: fix... |
146 |
|
5185a81c0 spi: rockchip: li... |
147 148 149 150 151 |
/* * SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However, * the controller seems to hang when given 0x10000, so stick with this for now. */ #define ROCKCHIP_SPI_MAX_TRANLEN 0xffff |
aa099382a spi: rockchip: Di... |
152 |
#define ROCKCHIP_SPI_MAX_CS_NUM 2 |
13a96935e spi: rockchip: Su... |
153 154 |
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002 #define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 |
aa099382a spi: rockchip: Di... |
155 |
|
64e36824b spi/rockchip: add... |
156 157 |
struct rockchip_spi { struct device *dev; |
64e36824b spi/rockchip: add... |
158 159 160 161 162 |
struct clk *spiclk; struct clk *apb_pclk; void __iomem *regs; |
eee06a9ee spi: rockchip: do... |
163 164 |
dma_addr_t dma_addr_rx; dma_addr_t dma_addr_tx; |
fab3e4871 spi: rockchip: us... |
165 |
|
01b59ce5d spi: rockchip: us... |
166 167 168 169 |
const void *tx; void *rx; unsigned int tx_left; unsigned int rx_left; |
fab3e4871 spi: rockchip: us... |
170 |
atomic_t state; |
64e36824b spi/rockchip: add... |
171 172 |
/*depth of the FIFO buffer */ u32 fifo_len; |
420b82f84 spi: rockchip: se... |
173 174 |
/* frequency of spiclk */ u32 freq; |
64e36824b spi/rockchip: add... |
175 |
|
64e36824b spi/rockchip: add... |
176 |
u8 n_bytes; |
74b7efa82 spi: rockchip: pr... |
177 |
u8 rsd; |
64e36824b spi/rockchip: add... |
178 |
|
aa099382a spi: rockchip: Di... |
179 |
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; |
d065f41a3 spi: spi-rockchip... |
180 181 |
bool slave_abort; |
64e36824b spi/rockchip: add... |
182 |
}; |
30688e4e6 spi: rockchip: ma... |
183 |
static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable) |
64e36824b spi/rockchip: add... |
184 |
{ |
30688e4e6 spi: rockchip: ma... |
185 |
writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR); |
64e36824b spi/rockchip: add... |
186 |
} |
2df08e789 spi/rockchip: cal... |
187 188 189 190 191 192 193 |
static inline void wait_for_idle(struct rockchip_spi *rs) { unsigned long timeout = jiffies + msecs_to_jiffies(5); do { if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)) return; |
64bc0110f spi/rockchip: Fix... |
194 |
} while (!time_after(jiffies, timeout)); |
2df08e789 spi/rockchip: cal... |
195 196 197 198 |
dev_warn(rs->dev, "spi controller is in busy state! "); } |
64e36824b spi/rockchip: add... |
199 200 |
static u32 get_fifo_len(struct rockchip_spi *rs) { |
13a96935e spi: rockchip: Su... |
201 |
u32 ver; |
64e36824b spi/rockchip: add... |
202 |
|
13a96935e spi: rockchip: Su... |
203 |
ver = readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION); |
64e36824b spi/rockchip: add... |
204 |
|
13a96935e spi: rockchip: Su... |
205 206 207 208 209 210 211 |
switch (ver) { case ROCKCHIP_SPI_VER2_TYPE1: case ROCKCHIP_SPI_VER2_TYPE2: return 64; default: return 32; } |
64e36824b spi/rockchip: add... |
212 |
} |
64e36824b spi/rockchip: add... |
213 214 |
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) { |
d66571a20 spi: spi-rockchip... |
215 216 |
struct spi_controller *ctlr = spi->controller; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
aa099382a spi: rockchip: Di... |
217 |
bool cs_asserted = !enable; |
b920cc319 spi/rockchip: Mak... |
218 |
|
aa099382a spi: rockchip: Di... |
219 220 221 |
/* Return immediately for no-op */ if (cs_asserted == rs->cs_asserted[spi->chip_select]) return; |
64e36824b spi/rockchip: add... |
222 |
|
aa099382a spi: rockchip: Di... |
223 224 225 |
if (cs_asserted) { /* Keep things powered as long as CS is asserted */ pm_runtime_get_sync(rs->dev); |
64e36824b spi/rockchip: add... |
226 |
|
aa099382a spi: rockchip: Di... |
227 228 229 230 231 |
ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); } else { ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); |
64e36824b spi/rockchip: add... |
232 |
|
aa099382a spi: rockchip: Di... |
233 234 235 |
/* Drop reference from when we first asserted CS */ pm_runtime_put(rs->dev); } |
b920cc319 spi/rockchip: Mak... |
236 |
|
aa099382a spi: rockchip: Di... |
237 |
rs->cs_asserted[spi->chip_select] = cs_asserted; |
64e36824b spi/rockchip: add... |
238 |
} |
d66571a20 spi: spi-rockchip... |
239 |
static void rockchip_spi_handle_err(struct spi_controller *ctlr, |
2291793cc spi/rockchip: do ... |
240 |
struct spi_message *msg) |
64e36824b spi/rockchip: add... |
241 |
{ |
d66571a20 spi: spi-rockchip... |
242 |
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
64e36824b spi/rockchip: add... |
243 |
|
ce386100d spi: rockchip: di... |
244 245 |
/* stop running spi transfer * this also flushes both rx and tx fifos |
5dcc44ed9 spi/rockchip: cle... |
246 |
*/ |
ce386100d spi: rockchip: di... |
247 |
spi_enable_chip(rs, false); |
01b59ce5d spi: rockchip: us... |
248 249 |
/* make sure all interrupts are masked */ writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); |
fab3e4871 spi: rockchip: us... |
250 |
if (atomic_read(&rs->state) & TXDMA) |
d66571a20 spi: spi-rockchip... |
251 |
dmaengine_terminate_async(ctlr->dma_tx); |
64e36824b spi/rockchip: add... |
252 |
|
ce386100d spi: rockchip: di... |
253 |
if (atomic_read(&rs->state) & RXDMA) |
d66571a20 spi: spi-rockchip... |
254 |
dmaengine_terminate_async(ctlr->dma_rx); |
64e36824b spi/rockchip: add... |
255 256 257 258 |
} static void rockchip_spi_pio_writer(struct rockchip_spi *rs) { |
01b59ce5d spi: rockchip: us... |
259 260 261 262 263 264 |
u32 tx_free = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR); u32 words = min(rs->tx_left, tx_free); rs->tx_left -= words; for (; words; words--) { u32 txw; |
64e36824b spi/rockchip: add... |
265 |
|
64e36824b spi/rockchip: add... |
266 |
if (rs->n_bytes == 1) |
01b59ce5d spi: rockchip: us... |
267 |
txw = *(u8 *)rs->tx; |
64e36824b spi/rockchip: add... |
268 |
else |
01b59ce5d spi: rockchip: us... |
269 |
txw = *(u16 *)rs->tx; |
64e36824b spi/rockchip: add... |
270 271 272 273 274 275 276 277 |
writel_relaxed(txw, rs->regs + ROCKCHIP_SPI_TXDR); rs->tx += rs->n_bytes; } } static void rockchip_spi_pio_reader(struct rockchip_spi *rs) { |
01b59ce5d spi: rockchip: us... |
278 |
u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR); |
4294e4acc spi: rockchip: Fi... |
279 |
u32 rx_left = (rs->rx_left > words) ? rs->rx_left - words : 0; |
01b59ce5d spi: rockchip: us... |
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
/* the hardware doesn't allow us to change fifo threshold * level while spi is enabled, so instead make sure to leave * enough words in the rx fifo to get the last interrupt * exactly when all words have been received */ if (rx_left) { u32 ftl = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFTLR) + 1; if (rx_left < ftl) { rx_left = ftl; words = rs->rx_left - rx_left; } } rs->rx_left = rx_left; for (; words; words--) { u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR); if (!rs->rx) continue; |
64e36824b spi/rockchip: add... |
301 |
|
64e36824b spi/rockchip: add... |
302 |
if (rs->n_bytes == 1) |
01b59ce5d spi: rockchip: us... |
303 |
*(u8 *)rs->rx = (u8)rxw; |
64e36824b spi/rockchip: add... |
304 |
else |
01b59ce5d spi: rockchip: us... |
305 |
*(u16 *)rs->rx = (u16)rxw; |
64e36824b spi/rockchip: add... |
306 |
rs->rx += rs->n_bytes; |
5dcc44ed9 spi/rockchip: cle... |
307 |
} |
64e36824b spi/rockchip: add... |
308 |
} |
01b59ce5d spi: rockchip: us... |
309 |
static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) |
64e36824b spi/rockchip: add... |
310 |
{ |
d66571a20 spi: spi-rockchip... |
311 312 |
struct spi_controller *ctlr = dev_id; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
64e36824b spi/rockchip: add... |
313 |
|
01b59ce5d spi: rockchip: us... |
314 315 |
if (rs->tx_left) rockchip_spi_pio_writer(rs); |
a3c174021 spi: rockchip: si... |
316 |
|
01b59ce5d spi: rockchip: us... |
317 318 319 320 |
rockchip_spi_pio_reader(rs); if (!rs->rx_left) { spi_enable_chip(rs, false); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); |
d66571a20 spi: spi-rockchip... |
321 |
spi_finalize_current_transfer(ctlr); |
01b59ce5d spi: rockchip: us... |
322 |
} |
64e36824b spi/rockchip: add... |
323 |
|
01b59ce5d spi: rockchip: us... |
324 325 |
return IRQ_HANDLED; } |
64e36824b spi/rockchip: add... |
326 |
|
01b59ce5d spi: rockchip: us... |
327 328 329 330 331 332 333 |
static int rockchip_spi_prepare_irq(struct rockchip_spi *rs, struct spi_transfer *xfer) { rs->tx = xfer->tx_buf; rs->rx = xfer->rx_buf; rs->tx_left = rs->tx ? xfer->len / rs->n_bytes : 0; rs->rx_left = xfer->len / rs->n_bytes; |
64e36824b spi/rockchip: add... |
334 |
|
01b59ce5d spi: rockchip: us... |
335 336 |
writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR); spi_enable_chip(rs, true); |
2df08e789 spi/rockchip: cal... |
337 |
|
01b59ce5d spi: rockchip: us... |
338 339 |
if (rs->tx_left) rockchip_spi_pio_writer(rs); |
c28be31b1 spi/rockchip: fix... |
340 |
|
01b59ce5d spi: rockchip: us... |
341 342 |
/* 1 means the transfer is in progress */ return 1; |
64e36824b spi/rockchip: add... |
343 344 345 346 |
} static void rockchip_spi_dma_rxcb(void *data) { |
d66571a20 spi: spi-rockchip... |
347 348 |
struct spi_controller *ctlr = data; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
fab3e4871 spi: rockchip: us... |
349 |
int state = atomic_fetch_andnot(RXDMA, &rs->state); |
64e36824b spi/rockchip: add... |
350 |
|
d065f41a3 spi: spi-rockchip... |
351 |
if (state & TXDMA && !rs->slave_abort) |
fab3e4871 spi: rockchip: us... |
352 |
return; |
64e36824b spi/rockchip: add... |
353 |
|
fab3e4871 spi: rockchip: us... |
354 |
spi_enable_chip(rs, false); |
d66571a20 spi: spi-rockchip... |
355 |
spi_finalize_current_transfer(ctlr); |
64e36824b spi/rockchip: add... |
356 357 358 359 |
} static void rockchip_spi_dma_txcb(void *data) { |
d66571a20 spi: spi-rockchip... |
360 361 |
struct spi_controller *ctlr = data; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
fab3e4871 spi: rockchip: us... |
362 |
int state = atomic_fetch_andnot(TXDMA, &rs->state); |
d065f41a3 spi: spi-rockchip... |
363 |
if (state & RXDMA && !rs->slave_abort) |
fab3e4871 spi: rockchip: us... |
364 |
return; |
64e36824b spi/rockchip: add... |
365 |
|
2df08e789 spi/rockchip: cal... |
366 367 |
/* Wait until the FIFO data completely. */ wait_for_idle(rs); |
fab3e4871 spi: rockchip: us... |
368 |
spi_enable_chip(rs, false); |
d66571a20 spi: spi-rockchip... |
369 |
spi_finalize_current_transfer(ctlr); |
64e36824b spi/rockchip: add... |
370 |
} |
4d9ca632c spi: rockchip: Co... |
371 372 373 374 375 376 377 378 379 380 381 382 |
static u32 rockchip_spi_calc_burst_size(u32 data_len) { u32 i; /* burst size: 1, 2, 4, 8 */ for (i = 1; i < 8; i <<= 1) { if (data_len & i) break; } return i; } |
fc1ad8ee3 spi: rockchip: re... |
383 |
static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, |
d66571a20 spi: spi-rockchip... |
384 |
struct spi_controller *ctlr, struct spi_transfer *xfer) |
64e36824b spi/rockchip: add... |
385 |
{ |
64e36824b spi/rockchip: add... |
386 |
struct dma_async_tx_descriptor *rxdesc, *txdesc; |
fab3e4871 spi: rockchip: us... |
387 |
atomic_set(&rs->state, 0); |
64e36824b spi/rockchip: add... |
388 |
|
97cf56697 spi/rockchip: avo... |
389 |
rxdesc = NULL; |
fc1ad8ee3 spi: rockchip: re... |
390 |
if (xfer->rx_buf) { |
31bcb57be spi: rockchip: us... |
391 392 |
struct dma_slave_config rxconf = { .direction = DMA_DEV_TO_MEM, |
eee06a9ee spi: rockchip: do... |
393 |
.src_addr = rs->dma_addr_rx, |
31bcb57be spi: rockchip: us... |
394 |
.src_addr_width = rs->n_bytes, |
4d9ca632c spi: rockchip: Co... |
395 396 |
.src_maxburst = rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes), |
31bcb57be spi: rockchip: us... |
397 |
}; |
d66571a20 spi: spi-rockchip... |
398 |
dmaengine_slave_config(ctlr->dma_rx, &rxconf); |
64e36824b spi/rockchip: add... |
399 |
|
5dcc44ed9 spi/rockchip: cle... |
400 |
rxdesc = dmaengine_prep_slave_sg( |
d66571a20 spi: spi-rockchip... |
401 |
ctlr->dma_rx, |
fc1ad8ee3 spi: rockchip: re... |
402 |
xfer->rx_sg.sgl, xfer->rx_sg.nents, |
d9071b7e9 spi: rockchip: di... |
403 |
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); |
ea9849113 spi: rockchip: ch... |
404 405 |
if (!rxdesc) return -EINVAL; |
64e36824b spi/rockchip: add... |
406 407 |
rxdesc->callback = rockchip_spi_dma_rxcb; |
d66571a20 spi: spi-rockchip... |
408 |
rxdesc->callback_param = ctlr; |
64e36824b spi/rockchip: add... |
409 |
} |
97cf56697 spi/rockchip: avo... |
410 |
txdesc = NULL; |
fc1ad8ee3 spi: rockchip: re... |
411 |
if (xfer->tx_buf) { |
31bcb57be spi: rockchip: us... |
412 413 |
struct dma_slave_config txconf = { .direction = DMA_MEM_TO_DEV, |
eee06a9ee spi: rockchip: do... |
414 |
.dst_addr = rs->dma_addr_tx, |
31bcb57be spi: rockchip: us... |
415 |
.dst_addr_width = rs->n_bytes, |
47300728f spi: rockchip: tu... |
416 |
.dst_maxburst = rs->fifo_len / 4, |
31bcb57be spi: rockchip: us... |
417 |
}; |
d66571a20 spi: spi-rockchip... |
418 |
dmaengine_slave_config(ctlr->dma_tx, &txconf); |
64e36824b spi/rockchip: add... |
419 |
|
5dcc44ed9 spi/rockchip: cle... |
420 |
txdesc = dmaengine_prep_slave_sg( |
d66571a20 spi: spi-rockchip... |
421 |
ctlr->dma_tx, |
fc1ad8ee3 spi: rockchip: re... |
422 |
xfer->tx_sg.sgl, xfer->tx_sg.nents, |
d9071b7e9 spi: rockchip: di... |
423 |
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); |
ea9849113 spi: rockchip: ch... |
424 425 |
if (!txdesc) { if (rxdesc) |
d66571a20 spi: spi-rockchip... |
426 |
dmaengine_terminate_sync(ctlr->dma_rx); |
ea9849113 spi: rockchip: ch... |
427 428 |
return -EINVAL; } |
64e36824b spi/rockchip: add... |
429 430 |
txdesc->callback = rockchip_spi_dma_txcb; |
d66571a20 spi: spi-rockchip... |
431 |
txdesc->callback_param = ctlr; |
64e36824b spi/rockchip: add... |
432 433 434 |
} /* rx must be started before tx due to spi instinct */ |
97cf56697 spi/rockchip: avo... |
435 |
if (rxdesc) { |
fab3e4871 spi: rockchip: us... |
436 |
atomic_or(RXDMA, &rs->state); |
64e36824b spi/rockchip: add... |
437 |
dmaengine_submit(rxdesc); |
d66571a20 spi: spi-rockchip... |
438 |
dma_async_issue_pending(ctlr->dma_rx); |
64e36824b spi/rockchip: add... |
439 |
} |
30688e4e6 spi: rockchip: ma... |
440 |
spi_enable_chip(rs, true); |
a3c174021 spi: rockchip: si... |
441 |
|
97cf56697 spi/rockchip: avo... |
442 |
if (txdesc) { |
fab3e4871 spi: rockchip: us... |
443 |
atomic_or(TXDMA, &rs->state); |
64e36824b spi/rockchip: add... |
444 |
dmaengine_submit(txdesc); |
d66571a20 spi: spi-rockchip... |
445 |
dma_async_issue_pending(ctlr->dma_tx); |
64e36824b spi/rockchip: add... |
446 |
} |
ea9849113 spi: rockchip: ch... |
447 |
|
a3c174021 spi: rockchip: si... |
448 449 |
/* 1 means the transfer is in progress */ return 1; |
64e36824b spi/rockchip: add... |
450 |
} |
fc1ad8ee3 spi: rockchip: re... |
451 |
static void rockchip_spi_config(struct rockchip_spi *rs, |
eff0275e5 spi: rockchip: si... |
452 |
struct spi_device *spi, struct spi_transfer *xfer, |
d065f41a3 spi: spi-rockchip... |
453 |
bool use_dma, bool slave_mode) |
64e36824b spi/rockchip: add... |
454 |
{ |
2410d6a3c spi: rockchip: al... |
455 456 457 458 |
u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET | CR0_BHT_8BIT << CR0_BHT_OFFSET | CR0_SSD_ONE << CR0_SSD_OFFSET | CR0_EM_BIG << CR0_EM_OFFSET; |
65498c6ae spi: rockchip: su... |
459 460 |
u32 cr1; u32 dmacr = 0; |
64e36824b spi/rockchip: add... |
461 |
|
d065f41a3 spi: spi-rockchip... |
462 463 464 |
if (slave_mode) cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET; rs->slave_abort = false; |
74b7efa82 spi: rockchip: pr... |
465 |
cr0 |= rs->rsd << CR0_RSD_OFFSET; |
fc1ad8ee3 spi: rockchip: re... |
466 |
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; |
04290192f spi: rockchip: su... |
467 468 |
if (spi->mode & SPI_LSB_FIRST) cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; |
fc1ad8ee3 spi: rockchip: re... |
469 470 471 472 473 |
if (xfer->rx_buf && xfer->tx_buf) cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET; else if (xfer->rx_buf) cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET; |
01b59ce5d spi: rockchip: us... |
474 |
else if (use_dma) |
fc1ad8ee3 spi: rockchip: re... |
475 |
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET; |
64e36824b spi/rockchip: add... |
476 |
|
65498c6ae spi: rockchip: su... |
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
switch (xfer->bits_per_word) { case 4: cr0 |= CR0_DFS_4BIT << CR0_DFS_OFFSET; cr1 = xfer->len - 1; break; case 8: cr0 |= CR0_DFS_8BIT << CR0_DFS_OFFSET; cr1 = xfer->len - 1; break; case 16: cr0 |= CR0_DFS_16BIT << CR0_DFS_OFFSET; cr1 = xfer->len / 2 - 1; break; default: /* we only whitelist 4, 8 and 16 bit words in |
d66571a20 spi: spi-rockchip... |
492 |
* ctlr->bits_per_word_mask, so this shouldn't |
65498c6ae spi: rockchip: su... |
493 494 495 496 |
* happen */ unreachable(); } |
eff0275e5 spi: rockchip: si... |
497 |
if (use_dma) { |
fc1ad8ee3 spi: rockchip: re... |
498 |
if (xfer->tx_buf) |
64e36824b spi/rockchip: add... |
499 |
dmacr |= TF_DMA_EN; |
fc1ad8ee3 spi: rockchip: re... |
500 |
if (xfer->rx_buf) |
64e36824b spi/rockchip: add... |
501 502 |
dmacr |= RF_DMA_EN; } |
64e36824b spi/rockchip: add... |
503 |
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); |
65498c6ae spi: rockchip: su... |
504 |
writel_relaxed(cr1, rs->regs + ROCKCHIP_SPI_CTRLR1); |
04b37d2d0 spi: rockchip: co... |
505 |
|
01b59ce5d spi: rockchip: us... |
506 507 508 509 510 511 512 513 |
/* unfortunately setting the fifo threshold level to generate an * interrupt exactly when the fifo is full doesn't seem to work, * so we need the strict inequality here */ if (xfer->len < rs->fifo_len) writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); else writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); |
64e36824b spi/rockchip: add... |
514 |
|
47300728f spi: rockchip: tu... |
515 |
writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR); |
4d9ca632c spi: rockchip: Co... |
516 517 |
writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1, rs->regs + ROCKCHIP_SPI_DMARDLR); |
64e36824b spi/rockchip: add... |
518 |
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); |
420b82f84 spi: rockchip: se... |
519 520 521 522 523 524 |
/* the hardware only supports an even clock divisor, so * round divisor = spiclk / speed up to nearest even number * so that the resulting speed is <= the requested speed */ writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz), rs->regs + ROCKCHIP_SPI_BAUDR); |
64e36824b spi/rockchip: add... |
525 |
} |
5185a81c0 spi: rockchip: li... |
526 527 528 529 |
static size_t rockchip_spi_max_transfer_size(struct spi_device *spi) { return ROCKCHIP_SPI_MAX_TRANLEN; } |
d065f41a3 spi: spi-rockchip... |
530 531 532 533 534 535 536 537 538 |
static int rockchip_spi_slave_abort(struct spi_controller *ctlr) { struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); rs->slave_abort = true; complete(&ctlr->xfer_completion); return 0; } |
5dcc44ed9 spi/rockchip: cle... |
539 |
static int rockchip_spi_transfer_one( |
d66571a20 spi: spi-rockchip... |
540 |
struct spi_controller *ctlr, |
64e36824b spi/rockchip: add... |
541 542 543 |
struct spi_device *spi, struct spi_transfer *xfer) { |
d66571a20 spi: spi-rockchip... |
544 |
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
eff0275e5 spi: rockchip: si... |
545 |
bool use_dma; |
64e36824b spi/rockchip: add... |
546 |
|
62946172c spi/rockchip: Don... |
547 548 |
WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && (readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)); |
64e36824b spi/rockchip: add... |
549 550 551 552 553 554 |
if (!xfer->tx_buf && !xfer->rx_buf) { dev_err(rs->dev, "No buffer for transfer "); return -EINVAL; } |
5185a81c0 spi: rockchip: li... |
555 556 557 558 559 |
if (xfer->len > ROCKCHIP_SPI_MAX_TRANLEN) { dev_err(rs->dev, "Transfer is too long (%d) ", xfer->len); return -EINVAL; } |
65498c6ae spi: rockchip: su... |
560 |
rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2; |
64e36824b spi/rockchip: add... |
561 |
|
d66571a20 spi: spi-rockchip... |
562 |
use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false; |
64e36824b spi/rockchip: add... |
563 |
|
d065f41a3 spi: spi-rockchip... |
564 |
rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); |
64e36824b spi/rockchip: add... |
565 |
|
eff0275e5 spi: rockchip: si... |
566 |
if (use_dma) |
d66571a20 spi: spi-rockchip... |
567 |
return rockchip_spi_prepare_dma(rs, ctlr, xfer); |
64e36824b spi/rockchip: add... |
568 |
|
01b59ce5d spi: rockchip: us... |
569 |
return rockchip_spi_prepare_irq(rs, xfer); |
64e36824b spi/rockchip: add... |
570 |
} |
d66571a20 spi: spi-rockchip... |
571 |
static bool rockchip_spi_can_dma(struct spi_controller *ctlr, |
5dcc44ed9 spi/rockchip: cle... |
572 573 |
struct spi_device *spi, struct spi_transfer *xfer) |
64e36824b spi/rockchip: add... |
574 |
{ |
d66571a20 spi: spi-rockchip... |
575 |
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
01b59ce5d spi: rockchip: us... |
576 |
unsigned int bytes_per_word = xfer->bits_per_word <= 8 ? 1 : 2; |
64e36824b spi/rockchip: add... |
577 |
|
01b59ce5d spi: rockchip: us... |
578 579 580 581 582 |
/* if the numbor of spi words to transfer is less than the fifo * length we can just fill the fifo and wait for a single irq, * so don't bother setting up dma */ return xfer->len / bytes_per_word >= rs->fifo_len; |
64e36824b spi/rockchip: add... |
583 584 585 586 |
} static int rockchip_spi_probe(struct platform_device *pdev) { |
43de979dd spi: rockchip: Sl... |
587 |
int ret; |
64e36824b spi/rockchip: add... |
588 |
struct rockchip_spi *rs; |
d66571a20 spi: spi-rockchip... |
589 |
struct spi_controller *ctlr; |
64e36824b spi/rockchip: add... |
590 |
struct resource *mem; |
d065f41a3 spi: spi-rockchip... |
591 |
struct device_node *np = pdev->dev.of_node; |
76b17e6e4 spi/rockchip: Add... |
592 |
u32 rsd_nsecs; |
d065f41a3 spi: spi-rockchip... |
593 594 595 596 597 598 599 600 601 602 |
bool slave_mode; slave_mode = of_property_read_bool(np, "spi-slave"); if (slave_mode) ctlr = spi_alloc_slave(&pdev->dev, sizeof(struct rockchip_spi)); else ctlr = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi)); |
64e36824b spi/rockchip: add... |
603 |
|
d66571a20 spi: spi-rockchip... |
604 |
if (!ctlr) |
64e36824b spi/rockchip: add... |
605 |
return -ENOMEM; |
5dcc44ed9 spi/rockchip: cle... |
606 |
|
d66571a20 spi: spi-rockchip... |
607 |
platform_set_drvdata(pdev, ctlr); |
64e36824b spi/rockchip: add... |
608 |
|
d66571a20 spi: spi-rockchip... |
609 |
rs = spi_controller_get_devdata(ctlr); |
d065f41a3 spi: spi-rockchip... |
610 |
ctlr->slave = slave_mode; |
64e36824b spi/rockchip: add... |
611 612 613 614 615 |
/* Get basic io resource and map it */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); rs->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(rs->regs)) { |
64e36824b spi/rockchip: add... |
616 |
ret = PTR_ERR(rs->regs); |
d66571a20 spi: spi-rockchip... |
617 |
goto err_put_ctlr; |
64e36824b spi/rockchip: add... |
618 619 620 621 622 623 624 |
} rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(rs->apb_pclk)) { dev_err(&pdev->dev, "Failed to get apb_pclk "); ret = PTR_ERR(rs->apb_pclk); |
d66571a20 spi: spi-rockchip... |
625 |
goto err_put_ctlr; |
64e36824b spi/rockchip: add... |
626 627 628 629 630 631 632 |
} rs->spiclk = devm_clk_get(&pdev->dev, "spiclk"); if (IS_ERR(rs->spiclk)) { dev_err(&pdev->dev, "Failed to get spi_pclk "); ret = PTR_ERR(rs->spiclk); |
d66571a20 spi: spi-rockchip... |
633 |
goto err_put_ctlr; |
64e36824b spi/rockchip: add... |
634 635 636 |
} ret = clk_prepare_enable(rs->apb_pclk); |
43de979dd spi: rockchip: Sl... |
637 |
if (ret < 0) { |
64e36824b spi/rockchip: add... |
638 639 |
dev_err(&pdev->dev, "Failed to enable apb_pclk "); |
d66571a20 spi: spi-rockchip... |
640 |
goto err_put_ctlr; |
64e36824b spi/rockchip: add... |
641 642 643 |
} ret = clk_prepare_enable(rs->spiclk); |
43de979dd spi: rockchip: Sl... |
644 |
if (ret < 0) { |
64e36824b spi/rockchip: add... |
645 646 |
dev_err(&pdev->dev, "Failed to enable spi_clk "); |
c351587e2 spi: rockchip: fi... |
647 |
goto err_disable_apbclk; |
64e36824b spi/rockchip: add... |
648 |
} |
30688e4e6 spi: rockchip: ma... |
649 |
spi_enable_chip(rs, false); |
64e36824b spi/rockchip: add... |
650 |
|
01b59ce5d spi: rockchip: us... |
651 652 653 654 655 |
ret = platform_get_irq(pdev, 0); if (ret < 0) goto err_disable_spiclk; ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL, |
d66571a20 spi: spi-rockchip... |
656 |
IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); |
01b59ce5d spi: rockchip: us... |
657 658 |
if (ret) goto err_disable_spiclk; |
64e36824b spi/rockchip: add... |
659 |
rs->dev = &pdev->dev; |
420b82f84 spi: rockchip: se... |
660 |
rs->freq = clk_get_rate(rs->spiclk); |
64e36824b spi/rockchip: add... |
661 |
|
76b17e6e4 spi/rockchip: Add... |
662 |
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns", |
74b7efa82 spi: rockchip: pr... |
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
&rsd_nsecs)) { /* rx sample delay is expressed in parent clock cycles (max 3) */ u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 1000000000 >> 8); if (!rsd) { dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay ", rs->freq, rsd_nsecs); } else if (rsd > CR0_RSD_MAX) { rsd = CR0_RSD_MAX; dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns ", rs->freq, rsd_nsecs, CR0_RSD_MAX * 1000000000U / rs->freq); } rs->rsd = rsd; } |
76b17e6e4 spi/rockchip: Add... |
680 |
|
64e36824b spi/rockchip: add... |
681 682 683 684 |
rs->fifo_len = get_fifo_len(rs); if (!rs->fifo_len) { dev_err(&pdev->dev, "Failed to get fifo length "); |
db7e8d90c spi/rockchip: fix... |
685 |
ret = -EINVAL; |
c351587e2 spi: rockchip: fi... |
686 |
goto err_disable_spiclk; |
64e36824b spi/rockchip: add... |
687 |
} |
64e36824b spi/rockchip: add... |
688 689 |
pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); |
d66571a20 spi: spi-rockchip... |
690 691 692 |
ctlr->auto_runtime_pm = true; ctlr->bus_num = pdev->id; ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST; |
d065f41a3 spi: spi-rockchip... |
693 694 695 696 697 |
if (slave_mode) { ctlr->mode_bits |= SPI_NO_CS; ctlr->slave_abort = rockchip_spi_slave_abort; } else { ctlr->flags = SPI_MASTER_GPIO_SS; |
eb1262e3c spi: spi-rockchip... |
698 699 700 701 702 703 704 705 |
ctlr->max_native_cs = ROCKCHIP_SPI_MAX_CS_NUM; /* * rk spi0 has two native cs, spi1..5 one cs only * if num-cs is missing in the dts, default to 1 */ if (of_property_read_u16(np, "num-cs", &ctlr->num_chipselect)) ctlr->num_chipselect = 1; ctlr->use_gpio_descriptors = true; |
d065f41a3 spi: spi-rockchip... |
706 |
} |
d66571a20 spi: spi-rockchip... |
707 708 709 710 711 712 713 714 715 |
ctlr->dev.of_node = pdev->dev.of_node; ctlr->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4); ctlr->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX; ctlr->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT); ctlr->set_cs = rockchip_spi_set_cs; ctlr->transfer_one = rockchip_spi_transfer_one; ctlr->max_transfer_size = rockchip_spi_max_transfer_size; ctlr->handle_err = rockchip_spi_handle_err; |
d66571a20 spi: spi-rockchip... |
716 717 718 |
ctlr->dma_tx = dma_request_chan(rs->dev, "tx"); if (IS_ERR(ctlr->dma_tx)) { |
61cadcf46 spi: rockchip: ch... |
719 |
/* Check tx to see if we need defer probing driver */ |
d66571a20 spi: spi-rockchip... |
720 |
if (PTR_ERR(ctlr->dma_tx) == -EPROBE_DEFER) { |
61cadcf46 spi: rockchip: ch... |
721 |
ret = -EPROBE_DEFER; |
c351587e2 spi: rockchip: fi... |
722 |
goto err_disable_pm_runtime; |
61cadcf46 spi: rockchip: ch... |
723 |
} |
64e36824b spi/rockchip: add... |
724 725 |
dev_warn(rs->dev, "Failed to request TX DMA channel "); |
d66571a20 spi: spi-rockchip... |
726 |
ctlr->dma_tx = NULL; |
61cadcf46 spi: rockchip: ch... |
727 |
} |
64e36824b spi/rockchip: add... |
728 |
|
d66571a20 spi: spi-rockchip... |
729 730 731 |
ctlr->dma_rx = dma_request_chan(rs->dev, "rx"); if (IS_ERR(ctlr->dma_rx)) { if (PTR_ERR(ctlr->dma_rx) == -EPROBE_DEFER) { |
e4c0e06f9 spi: rockchip: fi... |
732 |
ret = -EPROBE_DEFER; |
5de7ed0c9 spi: rockchip: po... |
733 |
goto err_free_dma_tx; |
64e36824b spi/rockchip: add... |
734 735 736 |
} dev_warn(rs->dev, "Failed to request RX DMA channel "); |
d66571a20 spi: spi-rockchip... |
737 |
ctlr->dma_rx = NULL; |
64e36824b spi/rockchip: add... |
738 |
} |
d66571a20 spi: spi-rockchip... |
739 |
if (ctlr->dma_tx && ctlr->dma_rx) { |
eee06a9ee spi: rockchip: do... |
740 741 |
rs->dma_addr_tx = mem->start + ROCKCHIP_SPI_TXDR; rs->dma_addr_rx = mem->start + ROCKCHIP_SPI_RXDR; |
d66571a20 spi: spi-rockchip... |
742 |
ctlr->can_dma = rockchip_spi_can_dma; |
64e36824b spi/rockchip: add... |
743 |
} |
d66571a20 spi: spi-rockchip... |
744 |
ret = devm_spi_register_controller(&pdev->dev, ctlr); |
43de979dd spi: rockchip: Sl... |
745 |
if (ret < 0) { |
d66571a20 spi: spi-rockchip... |
746 747 |
dev_err(&pdev->dev, "Failed to register controller "); |
c351587e2 spi: rockchip: fi... |
748 |
goto err_free_dma_rx; |
64e36824b spi/rockchip: add... |
749 |
} |
64e36824b spi/rockchip: add... |
750 |
return 0; |
c351587e2 spi: rockchip: fi... |
751 |
err_free_dma_rx: |
d66571a20 spi: spi-rockchip... |
752 753 |
if (ctlr->dma_rx) dma_release_channel(ctlr->dma_rx); |
5de7ed0c9 spi: rockchip: po... |
754 |
err_free_dma_tx: |
d66571a20 spi: spi-rockchip... |
755 756 |
if (ctlr->dma_tx) dma_release_channel(ctlr->dma_tx); |
c351587e2 spi: rockchip: fi... |
757 758 759 |
err_disable_pm_runtime: pm_runtime_disable(&pdev->dev); err_disable_spiclk: |
64e36824b spi/rockchip: add... |
760 |
clk_disable_unprepare(rs->spiclk); |
c351587e2 spi: rockchip: fi... |
761 |
err_disable_apbclk: |
64e36824b spi/rockchip: add... |
762 |
clk_disable_unprepare(rs->apb_pclk); |
d66571a20 spi: spi-rockchip... |
763 764 |
err_put_ctlr: spi_controller_put(ctlr); |
64e36824b spi/rockchip: add... |
765 766 767 768 769 770 |
return ret; } static int rockchip_spi_remove(struct platform_device *pdev) { |
d66571a20 spi: spi-rockchip... |
771 772 |
struct spi_controller *ctlr = spi_controller_get(platform_get_drvdata(pdev)); struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
64e36824b spi/rockchip: add... |
773 |
|
6a06e895b spi: rockchip: Fi... |
774 |
pm_runtime_get_sync(&pdev->dev); |
64e36824b spi/rockchip: add... |
775 776 777 |
clk_disable_unprepare(rs->spiclk); clk_disable_unprepare(rs->apb_pclk); |
6a06e895b spi: rockchip: Fi... |
778 779 780 |
pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); |
d66571a20 spi: spi-rockchip... |
781 782 783 784 |
if (ctlr->dma_tx) dma_release_channel(ctlr->dma_tx); if (ctlr->dma_rx) dma_release_channel(ctlr->dma_rx); |
64e36824b spi/rockchip: add... |
785 |
|
d66571a20 spi: spi-rockchip... |
786 |
spi_controller_put(ctlr); |
844c9f476 spi: rockchip: ad... |
787 |
|
64e36824b spi/rockchip: add... |
788 789 790 791 792 793 |
return 0; } #ifdef CONFIG_PM_SLEEP static int rockchip_spi_suspend(struct device *dev) { |
43de979dd spi: rockchip: Sl... |
794 |
int ret; |
d66571a20 spi: spi-rockchip... |
795 |
struct spi_controller *ctlr = dev_get_drvdata(dev); |
64e36824b spi/rockchip: add... |
796 |
|
d66571a20 spi: spi-rockchip... |
797 |
ret = spi_controller_suspend(ctlr); |
43de979dd spi: rockchip: Sl... |
798 |
if (ret < 0) |
64e36824b spi/rockchip: add... |
799 |
return ret; |
d38c4ae19 spi: rockchip: Fi... |
800 801 802 |
ret = pm_runtime_force_suspend(dev); if (ret < 0) return ret; |
64e36824b spi/rockchip: add... |
803 |
|
23e291c2e spi: rockchip: su... |
804 |
pinctrl_pm_select_sleep_state(dev); |
43de979dd spi: rockchip: Sl... |
805 |
return 0; |
64e36824b spi/rockchip: add... |
806 807 808 809 |
} static int rockchip_spi_resume(struct device *dev) { |
43de979dd spi: rockchip: Sl... |
810 |
int ret; |
d66571a20 spi: spi-rockchip... |
811 812 |
struct spi_controller *ctlr = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
64e36824b spi/rockchip: add... |
813 |
|
23e291c2e spi: rockchip: su... |
814 |
pinctrl_pm_select_default_state(dev); |
d38c4ae19 spi: rockchip: Fi... |
815 816 817 |
ret = pm_runtime_force_resume(dev); if (ret < 0) return ret; |
64e36824b spi/rockchip: add... |
818 |
|
d66571a20 spi: spi-rockchip... |
819 |
ret = spi_controller_resume(ctlr); |
64e36824b spi/rockchip: add... |
820 821 822 823 |
if (ret < 0) { clk_disable_unprepare(rs->spiclk); clk_disable_unprepare(rs->apb_pclk); } |
43de979dd spi: rockchip: Sl... |
824 |
return 0; |
64e36824b spi/rockchip: add... |
825 826 |
} #endif /* CONFIG_PM_SLEEP */ |
ec8330503 spi: Replace CONF... |
827 |
#ifdef CONFIG_PM |
64e36824b spi/rockchip: add... |
828 829 |
static int rockchip_spi_runtime_suspend(struct device *dev) { |
d66571a20 spi: spi-rockchip... |
830 831 |
struct spi_controller *ctlr = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
64e36824b spi/rockchip: add... |
832 833 834 835 836 837 838 839 840 841 |
clk_disable_unprepare(rs->spiclk); clk_disable_unprepare(rs->apb_pclk); return 0; } static int rockchip_spi_runtime_resume(struct device *dev) { int ret; |
d66571a20 spi: spi-rockchip... |
842 843 |
struct spi_controller *ctlr = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); |
64e36824b spi/rockchip: add... |
844 845 |
ret = clk_prepare_enable(rs->apb_pclk); |
43de979dd spi: rockchip: Sl... |
846 |
if (ret < 0) |
64e36824b spi/rockchip: add... |
847 848 849 |
return ret; ret = clk_prepare_enable(rs->spiclk); |
43de979dd spi: rockchip: Sl... |
850 |
if (ret < 0) |
64e36824b spi/rockchip: add... |
851 |
clk_disable_unprepare(rs->apb_pclk); |
43de979dd spi: rockchip: Sl... |
852 |
return 0; |
64e36824b spi/rockchip: add... |
853 |
} |
ec8330503 spi: Replace CONF... |
854 |
#endif /* CONFIG_PM */ |
64e36824b spi/rockchip: add... |
855 856 857 858 859 860 861 862 |
static const struct dev_pm_ops rockchip_spi_pm = { SET_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume) SET_RUNTIME_PM_OPS(rockchip_spi_runtime_suspend, rockchip_spi_runtime_resume, NULL) }; static const struct of_device_id rockchip_spi_dt_match[] = { |
c6486eadb spi: rockchip: ad... |
863 |
{ .compatible = "rockchip,px30-spi", }, |
aa29ea3df spi/rockchip: add... |
864 |
{ .compatible = "rockchip,rk3036-spi", }, |
64e36824b spi/rockchip: add... |
865 |
{ .compatible = "rockchip,rk3066-spi", }, |
b839b7851 spi/rockchip: add... |
866 |
{ .compatible = "rockchip,rk3188-spi", }, |
aa29ea3df spi/rockchip: add... |
867 |
{ .compatible = "rockchip,rk3228-spi", }, |
b839b7851 spi/rockchip: add... |
868 |
{ .compatible = "rockchip,rk3288-spi", }, |
c6486eadb spi: rockchip: ad... |
869 870 |
{ .compatible = "rockchip,rk3308-spi", }, { .compatible = "rockchip,rk3328-spi", }, |
aa29ea3df spi/rockchip: add... |
871 |
{ .compatible = "rockchip,rk3368-spi", }, |
9b7a56221 spi: rockchip: ad... |
872 |
{ .compatible = "rockchip,rk3399-spi", }, |
c6486eadb spi: rockchip: ad... |
873 |
{ .compatible = "rockchip,rv1108-spi", }, |
64e36824b spi/rockchip: add... |
874 875 876 877 878 879 880 |
{ }, }; MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match); static struct platform_driver rockchip_spi_driver = { .driver = { .name = DRIVER_NAME, |
64e36824b spi/rockchip: add... |
881 882 883 884 885 886 887 888 |
.pm = &rockchip_spi_pm, .of_match_table = of_match_ptr(rockchip_spi_dt_match), }, .probe = rockchip_spi_probe, .remove = rockchip_spi_remove, }; module_platform_driver(rockchip_spi_driver); |
5dcc44ed9 spi/rockchip: cle... |
889 |
MODULE_AUTHOR("Addy Ke <addy.ke@rock-chips.com>"); |
64e36824b spi/rockchip: add... |
890 891 |
MODULE_DESCRIPTION("ROCKCHIP SPI Controller Driver"); MODULE_LICENSE("GPL v2"); |