Blame view
drivers/spi/spi-qup.c
33.3 KB
ce718dfb2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
64ff247a9 spi: Add Qualcomm... |
2 3 |
/* * Copyright (c) 2008-2014, The Linux foundation. All rights reserved. |
64ff247a9 spi: Add Qualcomm... |
4 5 6 7 8 9 10 11 12 13 |
*/ #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/list.h> #include <linux/module.h> #include <linux/of.h> |
4d023737b spi: qup: Fix QUP... |
14 |
#include <linux/of_device.h> |
64ff247a9 spi: Add Qualcomm... |
15 16 17 |
#include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/spi/spi.h> |
612762e82 spi: qup: Add DMA... |
18 19 |
#include <linux/dmaengine.h> #include <linux/dma-mapping.h> |
64ff247a9 spi: Add Qualcomm... |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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 |
#define QUP_CONFIG 0x0000 #define QUP_STATE 0x0004 #define QUP_IO_M_MODES 0x0008 #define QUP_SW_RESET 0x000c #define QUP_OPERATIONAL 0x0018 #define QUP_ERROR_FLAGS 0x001c #define QUP_ERROR_FLAGS_EN 0x0020 #define QUP_OPERATIONAL_MASK 0x0028 #define QUP_HW_VERSION 0x0030 #define QUP_MX_OUTPUT_CNT 0x0100 #define QUP_OUTPUT_FIFO 0x0110 #define QUP_MX_WRITE_CNT 0x0150 #define QUP_MX_INPUT_CNT 0x0200 #define QUP_MX_READ_CNT 0x0208 #define QUP_INPUT_FIFO 0x0218 #define SPI_CONFIG 0x0300 #define SPI_IO_CONTROL 0x0304 #define SPI_ERROR_FLAGS 0x0308 #define SPI_ERROR_FLAGS_EN 0x030c /* QUP_CONFIG fields */ #define QUP_CONFIG_SPI_MODE (1 << 8) #define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13) #define QUP_CONFIG_NO_INPUT BIT(7) #define QUP_CONFIG_NO_OUTPUT BIT(6) #define QUP_CONFIG_N 0x001f /* QUP_STATE fields */ #define QUP_STATE_VALID BIT(2) #define QUP_STATE_RESET 0 #define QUP_STATE_RUN 1 #define QUP_STATE_PAUSE 3 #define QUP_STATE_MASK 3 #define QUP_STATE_CLEAR 2 #define QUP_HW_VERSION_2_1_1 0x20010001 /* QUP_IO_M_MODES fields */ #define QUP_IO_M_PACK_EN BIT(15) #define QUP_IO_M_UNPACK_EN BIT(14) #define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12 #define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10 #define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT) #define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT) #define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0) #define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2) #define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5) #define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7) #define QUP_IO_M_MODE_FIFO 0 #define QUP_IO_M_MODE_BLOCK 1 #define QUP_IO_M_MODE_DMOV 2 #define QUP_IO_M_MODE_BAM 3 /* QUP_OPERATIONAL fields */ |
7538726f9 spi: qup: Do bloc... |
78 79 |
#define QUP_OP_IN_BLOCK_READ_REQ BIT(13) #define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12) |
64ff247a9 spi: Add Qualcomm... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11) #define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10) #define QUP_OP_IN_SERVICE_FLAG BIT(9) #define QUP_OP_OUT_SERVICE_FLAG BIT(8) #define QUP_OP_IN_FIFO_FULL BIT(7) #define QUP_OP_OUT_FIFO_FULL BIT(6) #define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5) #define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4) /* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */ #define QUP_ERROR_OUTPUT_OVER_RUN BIT(5) #define QUP_ERROR_INPUT_UNDER_RUN BIT(4) #define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3) #define QUP_ERROR_INPUT_OVER_RUN BIT(2) /* SPI_CONFIG fields */ #define SPI_CONFIG_HS_MODE BIT(10) #define SPI_CONFIG_INPUT_FIRST BIT(9) #define SPI_CONFIG_LOOPBACK BIT(8) /* SPI_IO_CONTROL fields */ #define SPI_IO_C_FORCE_CS BIT(11) #define SPI_IO_C_CLK_IDLE_HIGH BIT(10) #define SPI_IO_C_MX_CS_MODE BIT(8) #define SPI_IO_C_CS_N_POLARITY_0 BIT(4) #define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2) #define SPI_IO_C_CS_SELECT_MASK 0x000c #define SPI_IO_C_TRISTATE_CS BIT(1) #define SPI_IO_C_NO_TRI_STATE BIT(0) /* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */ #define SPI_ERROR_CLK_OVER_RUN BIT(1) #define SPI_ERROR_CLK_UNDER_RUN BIT(0) #define SPI_NUM_CHIPSELECTS 4 |
5dc47fefe spi: qup: allow b... |
115 |
#define SPI_MAX_XFER (SZ_64K - 64) |
612762e82 spi: qup: Add DMA... |
116 |
|
64ff247a9 spi: Add Qualcomm... |
117 118 119 120 121 122 |
/* high speed mode is when bus rate is greater then 26MHz */ #define SPI_HS_MIN_RATE 26000000 #define SPI_MAX_RATE 50000000 #define SPI_DELAY_THRESHOLD 1 #define SPI_DELAY_RETRY 10 |
64ff247a9 spi: Add Qualcomm... |
123 124 125 126 127 128 |
struct spi_qup { void __iomem *base; struct device *dev; struct clk *cclk; /* core clock */ struct clk *iclk; /* interface clock */ int irq; |
64ff247a9 spi: Add Qualcomm... |
129 130 131 132 133 134 135 136 137 138 139 |
spinlock_t lock; int in_fifo_sz; int out_fifo_sz; int in_blk_sz; int out_blk_sz; struct spi_transfer *xfer; struct completion done; int error; int w_size; /* bytes per SPI word */ |
612762e82 spi: qup: Add DMA... |
140 |
int n_words; |
64ff247a9 spi: Add Qualcomm... |
141 142 |
int tx_bytes; int rx_bytes; |
5dc47fefe spi: qup: allow b... |
143 144 |
const u8 *tx_buf; u8 *rx_buf; |
70cea0a95 spi: qup: Add sup... |
145 |
int qup_v1; |
612762e82 spi: qup: Add DMA... |
146 |
|
32ecab999 spi: qup: Setup D... |
147 |
int mode; |
612762e82 spi: qup: Add DMA... |
148 149 |
struct dma_slave_config rx_conf; struct dma_slave_config tx_conf; |
64ff247a9 spi: Add Qualcomm... |
150 |
}; |
3b5ea2c98 spi: qup: call io... |
151 |
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer); |
7538726f9 spi: qup: Do bloc... |
152 153 154 155 156 157 |
static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag) { u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL); return (opflag & flag) != 0; } |
32ecab999 spi: qup: Setup D... |
158 159 160 161 162 163 164 |
static inline bool spi_qup_is_dma_xfer(int mode) { if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM) return true; return false; } |
64ff247a9 spi: Add Qualcomm... |
165 |
|
5dc47fefe spi: qup: allow b... |
166 167 168 169 170 |
/* get's the transaction size length */ static inline unsigned int spi_qup_len(struct spi_qup *controller) { return controller->n_words * controller->w_size; } |
64ff247a9 spi: Add Qualcomm... |
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
static inline bool spi_qup_is_valid_state(struct spi_qup *controller) { u32 opstate = readl_relaxed(controller->base + QUP_STATE); return opstate & QUP_STATE_VALID; } static int spi_qup_set_state(struct spi_qup *controller, u32 state) { unsigned long loop; u32 cur_state; loop = 0; while (!spi_qup_is_valid_state(controller)) { usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2); if (++loop > SPI_DELAY_RETRY) return -EIO; } if (loop) dev_dbg(controller->dev, "invalid state for %ld,us %d ", loop, state); cur_state = readl_relaxed(controller->base + QUP_STATE); /* * Per spec: for PAUSE_STATE to RESET_STATE, two writes * of (b10) are required */ if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) && (state == QUP_STATE_RESET)) { writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE); writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE); } else { cur_state &= ~QUP_STATE_MASK; cur_state |= state; writel_relaxed(cur_state, controller->base + QUP_STATE); } loop = 0; while (!spi_qup_is_valid_state(controller)) { usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2); if (++loop > SPI_DELAY_RETRY) return -EIO; } return 0; } |
5dc47fefe spi: qup: allow b... |
223 |
static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words) |
64ff247a9 spi: Add Qualcomm... |
224 |
{ |
5dc47fefe spi: qup: allow b... |
225 |
u8 *rx_buf = controller->rx_buf; |
7538726f9 spi: qup: Do bloc... |
226 227 |
int i, shift, num_bytes; u32 word; |
64ff247a9 spi: Add Qualcomm... |
228 |
|
7538726f9 spi: qup: Do bloc... |
229 |
for (; num_words; num_words--) { |
64ff247a9 spi: Add Qualcomm... |
230 231 |
word = readl_relaxed(controller->base + QUP_INPUT_FIFO); |
5dc47fefe spi: qup: allow b... |
232 233 234 |
num_bytes = min_t(int, spi_qup_len(controller) - controller->rx_bytes, controller->w_size); |
7538726f9 spi: qup: Do bloc... |
235 |
|
64ff247a9 spi: Add Qualcomm... |
236 |
if (!rx_buf) { |
7538726f9 spi: qup: Do bloc... |
237 |
controller->rx_bytes += num_bytes; |
64ff247a9 spi: Add Qualcomm... |
238 239 |
continue; } |
7538726f9 spi: qup: Do bloc... |
240 |
for (i = 0; i < num_bytes; i++, controller->rx_bytes++) { |
64ff247a9 spi: Add Qualcomm... |
241 242 243 244 245 246 247 |
/* * The data format depends on bytes per SPI word: * 4 bytes: 0x12345678 * 2 bytes: 0x00001234 * 1 byte : 0x00000012 */ shift = BITS_PER_BYTE; |
7538726f9 spi: qup: Do bloc... |
248 |
shift *= (controller->w_size - i - 1); |
64ff247a9 spi: Add Qualcomm... |
249 250 251 252 |
rx_buf[controller->rx_bytes] = word >> shift; } } } |
cd595b99a spi: qup: Ensure ... |
253 |
static void spi_qup_read(struct spi_qup *controller, u32 *opflags) |
64ff247a9 spi: Add Qualcomm... |
254 |
{ |
7538726f9 spi: qup: Do bloc... |
255 256 |
u32 remainder, words_per_block, num_words; bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; |
5dc47fefe spi: qup: allow b... |
257 |
remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes, |
7538726f9 spi: qup: Do bloc... |
258 259 260 261 262 263 264 |
controller->w_size); words_per_block = controller->in_blk_sz >> 2; do { /* ACK by clearing service flag */ writel_relaxed(QUP_OP_IN_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); |
a75e91bad spi: qup: fix PIO... |
265 266 |
if (!remainder) goto exit; |
7538726f9 spi: qup: Do bloc... |
267 268 269 270 271 272 273 |
if (is_block_mode) { num_words = (remainder > words_per_block) ? words_per_block : remainder; } else { if (!spi_qup_is_flag_set(controller, QUP_OP_IN_FIFO_NOT_EMPTY)) break; |
64ff247a9 spi: Add Qualcomm... |
274 |
|
7538726f9 spi: qup: Do bloc... |
275 276 |
num_words = 1; } |
64ff247a9 spi: Add Qualcomm... |
277 |
|
7538726f9 spi: qup: Do bloc... |
278 |
/* read up to the maximum transfer size available */ |
5dc47fefe spi: qup: allow b... |
279 |
spi_qup_read_from_fifo(controller, num_words); |
64ff247a9 spi: Add Qualcomm... |
280 |
|
7538726f9 spi: qup: Do bloc... |
281 282 283 284 285 |
remainder -= num_words; /* if block mode, check to see if next block is available */ if (is_block_mode && !spi_qup_is_flag_set(controller, QUP_OP_IN_BLOCK_READ_REQ)) |
64ff247a9 spi: Add Qualcomm... |
286 |
break; |
7538726f9 spi: qup: Do bloc... |
287 288 289 290 |
} while (remainder); /* * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block |
cd595b99a spi: qup: Ensure ... |
291 292 293 |
* reads, it has to be cleared again at the very end. However, be sure * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be * present and this is used to determine if transaction is complete |
7538726f9 spi: qup: Do bloc... |
294 |
*/ |
a75e91bad spi: qup: fix PIO... |
295 296 297 298 299 300 301 |
exit: if (!remainder) { *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) writel_relaxed(QUP_OP_IN_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); } |
7538726f9 spi: qup: Do bloc... |
302 |
} |
5dc47fefe spi: qup: allow b... |
303 |
static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words) |
7538726f9 spi: qup: Do bloc... |
304 |
{ |
5dc47fefe spi: qup: allow b... |
305 |
const u8 *tx_buf = controller->tx_buf; |
7538726f9 spi: qup: Do bloc... |
306 307 308 309 |
int i, num_bytes; u32 word, data; for (; num_words; num_words--) { |
64ff247a9 spi: Add Qualcomm... |
310 |
word = 0; |
64ff247a9 spi: Add Qualcomm... |
311 |
|
5dc47fefe spi: qup: allow b... |
312 313 314 |
num_bytes = min_t(int, spi_qup_len(controller) - controller->tx_bytes, controller->w_size); |
7538726f9 spi: qup: Do bloc... |
315 316 317 318 |
if (tx_buf) for (i = 0; i < num_bytes; i++) { data = tx_buf[controller->tx_bytes + i]; word |= data << (BITS_PER_BYTE * (3 - i)); |
64ff247a9 spi: Add Qualcomm... |
319 |
} |
7538726f9 spi: qup: Do bloc... |
320 |
controller->tx_bytes += num_bytes; |
64ff247a9 spi: Add Qualcomm... |
321 322 323 324 |
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO); } } |
612762e82 spi: qup: Add DMA... |
325 326 327 328 329 330 |
static void spi_qup_dma_done(void *data) { struct spi_qup *qup = data; complete(&qup->done); } |
5dc47fefe spi: qup: allow b... |
331 |
static void spi_qup_write(struct spi_qup *controller) |
7538726f9 spi: qup: Do bloc... |
332 333 334 |
{ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; u32 remainder, words_per_block, num_words; |
5dc47fefe spi: qup: allow b... |
335 |
remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes, |
7538726f9 spi: qup: Do bloc... |
336 337 338 339 340 341 342 |
controller->w_size); words_per_block = controller->out_blk_sz >> 2; do { /* ACK by clearing service flag */ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); |
a75e91bad spi: qup: fix PIO... |
343 344 345 |
/* make sure the interrupt is valid */ if (!remainder) return; |
7538726f9 spi: qup: Do bloc... |
346 347 348 349 350 351 352 353 354 355 |
if (is_block_mode) { num_words = (remainder > words_per_block) ? words_per_block : remainder; } else { if (spi_qup_is_flag_set(controller, QUP_OP_OUT_FIFO_FULL)) break; num_words = 1; } |
5dc47fefe spi: qup: allow b... |
356 |
spi_qup_write_to_fifo(controller, num_words); |
7538726f9 spi: qup: Do bloc... |
357 358 359 360 361 362 363 364 365 366 |
remainder -= num_words; /* if block mode, check to see if next block is available */ if (is_block_mode && !spi_qup_is_flag_set(controller, QUP_OP_OUT_BLOCK_WRITE_REQ)) break; } while (remainder); } |
a841b24e6 spi: qup: refacto... |
367 368 |
static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl, unsigned int nents, enum dma_transfer_direction dir, |
612762e82 spi: qup: Add DMA... |
369 370 371 372 373 |
dma_async_tx_callback callback) { struct spi_qup *qup = spi_master_get_devdata(master); unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE; struct dma_async_tx_descriptor *desc; |
612762e82 spi: qup: Add DMA... |
374 375 |
struct dma_chan *chan; dma_cookie_t cookie; |
612762e82 spi: qup: Add DMA... |
376 |
|
a841b24e6 spi: qup: refacto... |
377 |
if (dir == DMA_MEM_TO_DEV) |
612762e82 spi: qup: Add DMA... |
378 |
chan = master->dma_tx; |
a841b24e6 spi: qup: refacto... |
379 |
else |
612762e82 spi: qup: Add DMA... |
380 |
chan = master->dma_rx; |
612762e82 spi: qup: Add DMA... |
381 382 |
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); |
d9a09a6c0 spi: qup: Fix err... |
383 384 |
if (IS_ERR_OR_NULL(desc)) return desc ? PTR_ERR(desc) : -EINVAL; |
612762e82 spi: qup: Add DMA... |
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
desc->callback = callback; desc->callback_param = qup; cookie = dmaengine_submit(desc); return dma_submit_error(cookie); } static void spi_qup_dma_terminate(struct spi_master *master, struct spi_transfer *xfer) { if (xfer->tx_buf) dmaengine_terminate_all(master->dma_tx); if (xfer->rx_buf) dmaengine_terminate_all(master->dma_rx); } |
5884e17ef spi: qup: allow m... |
402 403 404 405 406 |
static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max, u32 *nents) { struct scatterlist *sg; u32 total = 0; |
5884e17ef spi: qup: allow m... |
407 408 409 410 411 412 413 414 415 416 417 418 419 |
for (sg = sgl; sg; sg = sg_next(sg)) { unsigned int len = sg_dma_len(sg); /* check for overflow as well as limit */ if (((total + len) < total) || ((total + len) > max)) break; total += len; (*nents)++; } return total; } |
3b5ea2c98 spi: qup: call io... |
420 |
static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, |
5f13fd60b spi: qup: Add com... |
421 |
unsigned long timeout) |
612762e82 spi: qup: Add DMA... |
422 423 |
{ dma_async_tx_callback rx_done = NULL, tx_done = NULL; |
3b5ea2c98 spi: qup: call io... |
424 425 |
struct spi_master *master = spi->master; struct spi_qup *qup = spi_master_get_devdata(master); |
5884e17ef spi: qup: allow m... |
426 |
struct scatterlist *tx_sgl, *rx_sgl; |
612762e82 spi: qup: Add DMA... |
427 428 429 430 431 432 |
int ret; if (xfer->rx_buf) rx_done = spi_qup_dma_done; else if (xfer->tx_buf) tx_done = spi_qup_dma_done; |
5884e17ef spi: qup: allow m... |
433 434 |
rx_sgl = xfer->rx_sg.sgl; tx_sgl = xfer->tx_sg.sgl; |
3b5ea2c98 spi: qup: call io... |
435 |
|
5884e17ef spi: qup: allow m... |
436 |
do { |
6f38f125f spi: qup: hide wa... |
437 |
u32 rx_nents = 0, tx_nents = 0; |
5884e17ef spi: qup: allow m... |
438 439 440 441 442 443 444 445 446 |
if (rx_sgl) qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl, SPI_MAX_XFER, &rx_nents) / qup->w_size; if (tx_sgl) qup->n_words = spi_qup_sgl_get_nents_len(tx_sgl, SPI_MAX_XFER, &tx_nents) / qup->w_size; if (!qup->n_words) return -EIO; |
ce00bab31 spi: qup: Place t... |
447 |
|
5884e17ef spi: qup: allow m... |
448 |
ret = spi_qup_io_config(spi, xfer); |
612762e82 spi: qup: Add DMA... |
449 450 |
if (ret) return ret; |
5884e17ef spi: qup: allow m... |
451 452 453 454 455 |
/* before issuing the descriptors, set the QUP to run */ ret = spi_qup_set_state(qup, QUP_STATE_RUN); if (ret) { dev_warn(qup->dev, "cannot set RUN state "); |
612762e82 spi: qup: Add DMA... |
456 |
return ret; |
5884e17ef spi: qup: allow m... |
457 458 459 460 461 462 463 464 |
} if (rx_sgl) { ret = spi_qup_prep_sg(master, rx_sgl, rx_nents, DMA_DEV_TO_MEM, rx_done); if (ret) return ret; dma_async_issue_pending(master->dma_rx); } |
612762e82 spi: qup: Add DMA... |
465 |
|
5884e17ef spi: qup: allow m... |
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 |
if (tx_sgl) { ret = spi_qup_prep_sg(master, tx_sgl, tx_nents, DMA_MEM_TO_DEV, tx_done); if (ret) return ret; dma_async_issue_pending(master->dma_tx); } if (!wait_for_completion_timeout(&qup->done, timeout)) return -ETIMEDOUT; for (; rx_sgl && rx_nents--; rx_sgl = sg_next(rx_sgl)) ; for (; tx_sgl && tx_nents--; tx_sgl = sg_next(tx_sgl)) ; |
612762e82 spi: qup: Add DMA... |
482 |
|
5884e17ef spi: qup: allow m... |
483 |
} while (rx_sgl || tx_sgl); |
5f13fd60b spi: qup: Add com... |
484 |
|
612762e82 spi: qup: Add DMA... |
485 486 |
return 0; } |
3b5ea2c98 spi: qup: call io... |
487 |
static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, |
5f13fd60b spi: qup: Add com... |
488 |
unsigned long timeout) |
612762e82 spi: qup: Add DMA... |
489 |
{ |
3b5ea2c98 spi: qup: call io... |
490 |
struct spi_master *master = spi->master; |
612762e82 spi: qup: Add DMA... |
491 |
struct spi_qup *qup = spi_master_get_devdata(master); |
5dc47fefe spi: qup: allow b... |
492 |
int ret, n_words, iterations, offset = 0; |
612762e82 spi: qup: Add DMA... |
493 |
|
5dc47fefe spi: qup: allow b... |
494 495 496 497 |
n_words = qup->n_words; iterations = n_words / SPI_MAX_XFER; /* round down */ qup->rx_buf = xfer->rx_buf; qup->tx_buf = xfer->tx_buf; |
3b5ea2c98 spi: qup: call io... |
498 |
|
5dc47fefe spi: qup: allow b... |
499 500 501 502 503 |
do { if (iterations) qup->n_words = SPI_MAX_XFER; else qup->n_words = n_words % SPI_MAX_XFER; |
612762e82 spi: qup: Add DMA... |
504 |
|
5dc47fefe spi: qup: allow b... |
505 506 |
if (qup->tx_buf && offset) qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER; |
612762e82 spi: qup: Add DMA... |
507 |
|
5dc47fefe spi: qup: allow b... |
508 509 |
if (qup->rx_buf && offset) qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER; |
612762e82 spi: qup: Add DMA... |
510 |
|
5dc47fefe spi: qup: allow b... |
511 512 513 514 515 516 |
/* * if the transaction is small enough, we need * to fallback to FIFO mode */ if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32))) qup->mode = QUP_IO_M_MODE_FIFO; |
ce00bab31 spi: qup: Place t... |
517 |
|
5dc47fefe spi: qup: allow b... |
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 |
ret = spi_qup_io_config(spi, xfer); if (ret) return ret; ret = spi_qup_set_state(qup, QUP_STATE_RUN); if (ret) { dev_warn(qup->dev, "cannot set RUN state "); return ret; } ret = spi_qup_set_state(qup, QUP_STATE_PAUSE); if (ret) { dev_warn(qup->dev, "cannot set PAUSE state "); return ret; } if (qup->mode == QUP_IO_M_MODE_FIFO) spi_qup_write(qup); ret = spi_qup_set_state(qup, QUP_STATE_RUN); if (ret) { dev_warn(qup->dev, "cannot set RUN state "); return ret; } if (!wait_for_completion_timeout(&qup->done, timeout)) return -ETIMEDOUT; offset++; } while (iterations--); |
5f13fd60b spi: qup: Add com... |
551 |
|
612762e82 spi: qup: Add DMA... |
552 553 |
return 0; } |
a75e91bad spi: qup: fix PIO... |
554 555 556 557 558 559 560 561 562 563 564 565 |
static bool spi_qup_data_pending(struct spi_qup *controller) { unsigned int remainder_tx, remainder_rx; remainder_tx = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes, controller->w_size); remainder_rx = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes, controller->w_size); return remainder_tx || remainder_rx; } |
64ff247a9 spi: Add Qualcomm... |
566 567 568 |
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; |
64ff247a9 spi: Add Qualcomm... |
569 |
u32 opflags, qup_err, spi_err; |
a75e91bad spi: qup: fix PIO... |
570 |
unsigned long flags; |
64ff247a9 spi: Add Qualcomm... |
571 |
int error = 0; |
64ff247a9 spi: Add Qualcomm... |
572 573 574 575 576 577 |
qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS); opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS); writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS); |
64ff247a9 spi: Add Qualcomm... |
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
if (qup_err) { if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN) dev_warn(controller->dev, "OUTPUT_OVER_RUN "); if (qup_err & QUP_ERROR_INPUT_UNDER_RUN) dev_warn(controller->dev, "INPUT_UNDER_RUN "); if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN) dev_warn(controller->dev, "OUTPUT_UNDER_RUN "); if (qup_err & QUP_ERROR_INPUT_OVER_RUN) dev_warn(controller->dev, "INPUT_OVER_RUN "); error = -EIO; } if (spi_err) { if (spi_err & SPI_ERROR_CLK_OVER_RUN) dev_warn(controller->dev, "CLK_OVER_RUN "); if (spi_err & SPI_ERROR_CLK_UNDER_RUN) dev_warn(controller->dev, "CLK_UNDER_RUN "); error = -EIO; } |
a75e91bad spi: qup: fix PIO... |
606 607 608 609 |
spin_lock_irqsave(&controller->lock, flags); if (!controller->error) controller->error = error; spin_unlock_irqrestore(&controller->lock, flags); |
ce7dfc71c spi: qup: Fix tra... |
610 611 612 |
if (spi_qup_is_dma_xfer(controller->mode)) { writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); } else { |
612762e82 spi: qup: Add DMA... |
613 |
if (opflags & QUP_OP_IN_SERVICE_FLAG) |
cd595b99a spi: qup: Ensure ... |
614 |
spi_qup_read(controller, &opflags); |
64ff247a9 spi: Add Qualcomm... |
615 |
|
612762e82 spi: qup: Add DMA... |
616 |
if (opflags & QUP_OP_OUT_SERVICE_FLAG) |
5dc47fefe spi: qup: allow b... |
617 |
spi_qup_write(controller); |
a75e91bad spi: qup: fix PIO... |
618 619 620 |
if (!spi_qup_data_pending(controller)) complete(&controller->done); |
612762e82 spi: qup: Add DMA... |
621 |
} |
64ff247a9 spi: Add Qualcomm... |
622 |
|
a75e91bad spi: qup: fix PIO... |
623 |
if (error) |
64ff247a9 spi: Add Qualcomm... |
624 |
complete(&controller->done); |
a75e91bad spi: qup: fix PIO... |
625 626 627 628 629 630 631 |
if (opflags & QUP_OP_MAX_INPUT_DONE_FLAG) { if (!spi_qup_is_dma_xfer(controller->mode)) { if (spi_qup_data_pending(controller)) return IRQ_HANDLED; } complete(&controller->done); } |
64ff247a9 spi: Add Qualcomm... |
632 633 |
return IRQ_HANDLED; } |
94b9149fe spi: qup: refacto... |
634 635 |
/* set clock freq ... bits per word, determine mode */ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer) |
64ff247a9 spi: Add Qualcomm... |
636 |
{ |
00cce74d0 spi: qup: Get rid... |
637 |
struct spi_qup *controller = spi_master_get_devdata(spi->master); |
94b9149fe spi: qup: refacto... |
638 |
int ret; |
64ff247a9 spi: Add Qualcomm... |
639 |
|
00cce74d0 spi: qup: Get rid... |
640 |
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { |
64ff247a9 spi: Add Qualcomm... |
641 642 643 644 645 646 647 648 649 650 651 652 |
dev_err(controller->dev, "too big size for loopback %d > %d ", xfer->len, controller->in_fifo_sz); return -EIO; } ret = clk_set_rate(controller->cclk, xfer->speed_hz); if (ret) { dev_err(controller->dev, "fail to set frequency %d", xfer->speed_hz); return -EIO; } |
32ecab999 spi: qup: Setup D... |
653 654 |
controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8); controller->n_words = xfer->len / controller->w_size; |
32ecab999 spi: qup: Setup D... |
655 |
|
94b9149fe spi: qup: refacto... |
656 |
if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32))) |
32ecab999 spi: qup: Setup D... |
657 |
controller->mode = QUP_IO_M_MODE_FIFO; |
94b9149fe spi: qup: refacto... |
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
else if (spi->master->can_dma && spi->master->can_dma(spi->master, spi, xfer) && spi->master->cur_msg_mapped) controller->mode = QUP_IO_M_MODE_BAM; else controller->mode = QUP_IO_M_MODE_BLOCK; return 0; } /* prep qup for another spi transaction of specific type */ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(spi->master); u32 config, iomode, control; unsigned long flags; |
32ecab999 spi: qup: Setup D... |
674 |
|
94b9149fe spi: qup: refacto... |
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 |
spin_lock_irqsave(&controller->lock, flags); controller->xfer = xfer; controller->error = 0; controller->rx_bytes = 0; controller->tx_bytes = 0; spin_unlock_irqrestore(&controller->lock, flags); if (spi_qup_set_state(controller, QUP_STATE_RESET)) { dev_err(controller->dev, "cannot set RESET state "); return -EIO; } switch (controller->mode) { case QUP_IO_M_MODE_FIFO: writel_relaxed(controller->n_words, controller->base + QUP_MX_READ_CNT); writel_relaxed(controller->n_words, controller->base + QUP_MX_WRITE_CNT); |
64ff247a9 spi: Add Qualcomm... |
695 696 697 |
/* must be zero for FIFO */ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); |
94b9149fe spi: qup: refacto... |
698 699 700 701 702 703 |
break; case QUP_IO_M_MODE_BAM: writel_relaxed(controller->n_words, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(controller->n_words, controller->base + QUP_MX_OUTPUT_CNT); |
64ff247a9 spi: Add Qualcomm... |
704 705 706 |
/* must be zero for BLOCK and BAM */ writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); |
612762e82 spi: qup: Add DMA... |
707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
if (!controller->qup_v1) { void __iomem *input_cnt; input_cnt = controller->base + QUP_MX_INPUT_CNT; /* * for DMA transfers, both QUP_MX_INPUT_CNT and * QUP_MX_OUTPUT_CNT must be zero to all cases but one. * That case is a non-balanced transfer when there is * only a rx_buf. */ if (xfer->tx_buf) writel_relaxed(0, input_cnt); else |
94b9149fe spi: qup: refacto... |
721 |
writel_relaxed(controller->n_words, input_cnt); |
612762e82 spi: qup: Add DMA... |
722 723 724 |
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); } |
94b9149fe spi: qup: refacto... |
725 726 727 728 729 730 731 |
break; case QUP_IO_M_MODE_BLOCK: reinit_completion(&controller->done); writel_relaxed(controller->n_words, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(controller->n_words, controller->base + QUP_MX_OUTPUT_CNT); |
32ecab999 spi: qup: Setup D... |
732 733 734 |
/* must be zero for BLOCK and BAM */ writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); |
94b9149fe spi: qup: refacto... |
735 736 737 738 739 740 |
break; default: dev_err(controller->dev, "unknown mode = %d ", controller->mode); return -EIO; |
64ff247a9 spi: Add Qualcomm... |
741 742 743 744 745 |
} iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); /* Set input and output transfer mode */ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK); |
612762e82 spi: qup: Add DMA... |
746 |
|
32ecab999 spi: qup: Setup D... |
747 |
if (!spi_qup_is_dma_xfer(controller->mode)) |
612762e82 spi: qup: Add DMA... |
748 749 750 |
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); else iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN; |
32ecab999 spi: qup: Setup D... |
751 752 |
iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); |
64ff247a9 spi: Add Qualcomm... |
753 754 |
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); |
0667dd5f6 spi: qup: Add SPI... |
755 756 757 758 759 760 761 762 |
control = readl_relaxed(controller->base + SPI_IO_CONTROL); if (spi->mode & SPI_CPOL) control |= SPI_IO_C_CLK_IDLE_HIGH; else control &= ~SPI_IO_C_CLK_IDLE_HIGH; writel_relaxed(control, controller->base + SPI_IO_CONTROL); |
64ff247a9 spi: Add Qualcomm... |
763 |
config = readl_relaxed(controller->base + SPI_CONFIG); |
00cce74d0 spi: qup: Get rid... |
764 |
if (spi->mode & SPI_LOOP) |
64ff247a9 spi: Add Qualcomm... |
765 766 767 |
config |= SPI_CONFIG_LOOPBACK; else config &= ~SPI_CONFIG_LOOPBACK; |
00cce74d0 spi: qup: Get rid... |
768 |
if (spi->mode & SPI_CPHA) |
64ff247a9 spi: Add Qualcomm... |
769 770 771 772 773 774 775 776 |
config &= ~SPI_CONFIG_INPUT_FIRST; else config |= SPI_CONFIG_INPUT_FIRST; /* * HS_MODE improves signal stability for spi-clk high rates, * but is invalid in loop back mode. */ |
00cce74d0 spi: qup: Get rid... |
777 |
if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP)) |
64ff247a9 spi: Add Qualcomm... |
778 779 780 781 782 783 784 785 786 787 |
config |= SPI_CONFIG_HS_MODE; else config &= ~SPI_CONFIG_HS_MODE; writel_relaxed(config, controller->base + SPI_CONFIG); config = readl_relaxed(controller->base + QUP_CONFIG); config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N); config |= xfer->bits_per_word - 1; config |= QUP_CONFIG_SPI_MODE; |
612762e82 spi: qup: Add DMA... |
788 |
|
32ecab999 spi: qup: Setup D... |
789 |
if (spi_qup_is_dma_xfer(controller->mode)) { |
612762e82 spi: qup: Add DMA... |
790 791 792 793 794 |
if (!xfer->tx_buf) config |= QUP_CONFIG_NO_OUTPUT; if (!xfer->rx_buf) config |= QUP_CONFIG_NO_INPUT; } |
64ff247a9 spi: Add Qualcomm... |
795 |
writel_relaxed(config, controller->base + QUP_CONFIG); |
70cea0a95 spi: qup: Add sup... |
796 |
/* only write to OPERATIONAL_MASK when register is present */ |
612762e82 spi: qup: Add DMA... |
797 798 799 800 801 802 803 |
if (!controller->qup_v1) { u32 mask = 0; /* * mask INPUT and OUTPUT service flags to prevent IRQs on FIFO * status change in BAM mode */ |
32ecab999 spi: qup: Setup D... |
804 |
if (spi_qup_is_dma_xfer(controller->mode)) |
612762e82 spi: qup: Add DMA... |
805 806 807 808 |
mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG; writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK); } |
64ff247a9 spi: Add Qualcomm... |
809 810 |
return 0; } |
64ff247a9 spi: Add Qualcomm... |
811 812 813 814 815 |
static int spi_qup_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(master); |
64ff247a9 spi: Add Qualcomm... |
816 |
unsigned long timeout, flags; |
4a6c7d6f9 spi: qup: remove ... |
817 |
int ret; |
64ff247a9 spi: Add Qualcomm... |
818 |
|
94b9149fe spi: qup: refacto... |
819 820 821 |
ret = spi_qup_io_prep(spi, xfer); if (ret) return ret; |
64ff247a9 spi: Add Qualcomm... |
822 |
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC); |
5dc47fefe spi: qup: allow b... |
823 824 |
timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER, xfer->len) * 8, timeout); |
64ff247a9 spi: Add Qualcomm... |
825 826 827 828 829 830 831 832 833 834 |
timeout = 100 * msecs_to_jiffies(timeout); reinit_completion(&controller->done); spin_lock_irqsave(&controller->lock, flags); controller->xfer = xfer; controller->error = 0; controller->rx_bytes = 0; controller->tx_bytes = 0; spin_unlock_irqrestore(&controller->lock, flags); |
32ecab999 spi: qup: Setup D... |
835 |
if (spi_qup_is_dma_xfer(controller->mode)) |
3b5ea2c98 spi: qup: call io... |
836 |
ret = spi_qup_do_dma(spi, xfer, timeout); |
612762e82 spi: qup: Add DMA... |
837 |
else |
3b5ea2c98 spi: qup: call io... |
838 |
ret = spi_qup_do_pio(spi, xfer, timeout); |
64ff247a9 spi: Add Qualcomm... |
839 |
|
64ff247a9 spi: Add Qualcomm... |
840 841 |
spi_qup_set_state(controller, QUP_STATE_RESET); spin_lock_irqsave(&controller->lock, flags); |
64ff247a9 spi: Add Qualcomm... |
842 843 844 |
if (!ret) ret = controller->error; spin_unlock_irqrestore(&controller->lock, flags); |
612762e82 spi: qup: Add DMA... |
845 |
|
32ecab999 spi: qup: Setup D... |
846 |
if (ret && spi_qup_is_dma_xfer(controller->mode)) |
612762e82 spi: qup: Add DMA... |
847 848 849 850 851 852 853 854 855 856 |
spi_qup_dma_terminate(master, xfer); return ret; } static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *qup = spi_master_get_devdata(master); size_t dma_align = dma_get_cache_alignment(); |
32ecab999 spi: qup: Setup D... |
857 |
int n_words; |
612762e82 spi: qup: Add DMA... |
858 |
|
32ecab999 spi: qup: Setup D... |
859 860 861 862 863 864 865 |
if (xfer->rx_buf) { if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) || IS_ERR_OR_NULL(master->dma_rx)) return false; if (qup->qup_v1 && (xfer->len % qup->in_blk_sz)) return false; } |
612762e82 spi: qup: Add DMA... |
866 |
|
32ecab999 spi: qup: Setup D... |
867 868 869 870 871 872 873 |
if (xfer->tx_buf) { if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) || IS_ERR_OR_NULL(master->dma_tx)) return false; if (qup->qup_v1 && (xfer->len % qup->out_blk_sz)) return false; } |
612762e82 spi: qup: Add DMA... |
874 |
|
32ecab999 spi: qup: Setup D... |
875 876 |
n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8); if (n_words <= (qup->in_fifo_sz / sizeof(u32))) |
612762e82 spi: qup: Add DMA... |
877 |
return false; |
612762e82 spi: qup: Add DMA... |
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
return true; } static void spi_qup_release_dma(struct spi_master *master) { if (!IS_ERR_OR_NULL(master->dma_rx)) dma_release_channel(master->dma_rx); if (!IS_ERR_OR_NULL(master->dma_tx)) dma_release_channel(master->dma_tx); } static int spi_qup_init_dma(struct spi_master *master, resource_size_t base) { struct spi_qup *spi = spi_master_get_devdata(master); struct dma_slave_config *rx_conf = &spi->rx_conf, *tx_conf = &spi->tx_conf; struct device *dev = spi->dev; int ret; /* allocate dma resources, if available */ |
194e1d4bc spi: qup: Use dma... |
898 |
master->dma_rx = dma_request_chan(dev, "rx"); |
612762e82 spi: qup: Add DMA... |
899 900 |
if (IS_ERR(master->dma_rx)) return PTR_ERR(master->dma_rx); |
194e1d4bc spi: qup: Use dma... |
901 |
master->dma_tx = dma_request_chan(dev, "tx"); |
612762e82 spi: qup: Add DMA... |
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 |
if (IS_ERR(master->dma_tx)) { ret = PTR_ERR(master->dma_tx); goto err_tx; } /* set DMA parameters */ rx_conf->direction = DMA_DEV_TO_MEM; rx_conf->device_fc = 1; rx_conf->src_addr = base + QUP_INPUT_FIFO; rx_conf->src_maxburst = spi->in_blk_sz; tx_conf->direction = DMA_MEM_TO_DEV; tx_conf->device_fc = 1; tx_conf->dst_addr = base + QUP_OUTPUT_FIFO; tx_conf->dst_maxburst = spi->out_blk_sz; ret = dmaengine_slave_config(master->dma_rx, rx_conf); if (ret) { dev_err(dev, "failed to configure RX channel "); goto err; } ret = dmaengine_slave_config(master->dma_tx, tx_conf); if (ret) { dev_err(dev, "failed to configure TX channel "); goto err; } return 0; err: dma_release_channel(master->dma_tx); err_tx: dma_release_channel(master->dma_rx); |
64ff247a9 spi: Add Qualcomm... |
938 939 |
return ret; } |
b702b9fb3 spi: qup: Enable ... |
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
static void spi_qup_set_cs(struct spi_device *spi, bool val) { struct spi_qup *controller; u32 spi_ioc; u32 spi_ioc_orig; controller = spi_master_get_devdata(spi->master); spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL); spi_ioc_orig = spi_ioc; if (!val) spi_ioc |= SPI_IO_C_FORCE_CS; else spi_ioc &= ~SPI_IO_C_FORCE_CS; if (spi_ioc != spi_ioc_orig) writel_relaxed(spi_ioc, controller->base + SPI_IO_CONTROL); } |
64ff247a9 spi: Add Qualcomm... |
957 958 959 960 961 962 963 964 |
static int spi_qup_probe(struct platform_device *pdev) { struct spi_master *master; struct clk *iclk, *cclk; struct spi_qup *controller; struct resource *res; struct device *dev; void __iomem *base; |
12cb89e37 spi: qup: Fix cs-... |
965 |
u32 max_freq, iomode, num_cs; |
64ff247a9 spi: Add Qualcomm... |
966 967 968 969 970 971 972 973 974 |
int ret, irq, size; dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); irq = platform_get_irq(pdev, 0); |
64ff247a9 spi: Add Qualcomm... |
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
if (irq < 0) return irq; cclk = devm_clk_get(dev, "core"); if (IS_ERR(cclk)) return PTR_ERR(cclk); iclk = devm_clk_get(dev, "iface"); if (IS_ERR(iclk)) return PTR_ERR(iclk); /* This is optional parameter */ if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq)) max_freq = SPI_MAX_RATE; if (!max_freq || max_freq > SPI_MAX_RATE) { dev_err(dev, "invalid clock frequency %d ", max_freq); return -ENXIO; } ret = clk_prepare_enable(cclk); if (ret) { dev_err(dev, "cannot enable core clock "); return ret; } ret = clk_prepare_enable(iclk); if (ret) { clk_disable_unprepare(cclk); dev_err(dev, "cannot enable iface clock "); return ret; } |
64ff247a9 spi: Add Qualcomm... |
1010 1011 1012 1013 1014 1015 1016 1017 |
master = spi_alloc_master(dev, sizeof(struct spi_qup)); if (!master) { clk_disable_unprepare(cclk); clk_disable_unprepare(iclk); dev_err(dev, "cannot allocate master "); return -ENOMEM; } |
4a8573abe spi: qup: Remove ... |
1018 |
/* use num-cs unless not present or out of range */ |
12cb89e37 spi: qup: Fix cs-... |
1019 1020 |
if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) || num_cs > SPI_NUM_CHIPSELECTS) |
4a8573abe spi: qup: Remove ... |
1021 |
master->num_chipselect = SPI_NUM_CHIPSELECTS; |
12cb89e37 spi: qup: Fix cs-... |
1022 1023 |
else master->num_chipselect = num_cs; |
4a8573abe spi: qup: Remove ... |
1024 |
|
64ff247a9 spi: Add Qualcomm... |
1025 1026 |
master->bus_num = pdev->id; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; |
64ff247a9 spi: Add Qualcomm... |
1027 |
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); |
cb64ca540 spi: qup: Convert... |
1028 |
master->max_speed_hz = max_freq; |
64ff247a9 spi: Add Qualcomm... |
1029 1030 1031 |
master->transfer_one = spi_qup_transfer_one; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; |
612762e82 spi: qup: Add DMA... |
1032 |
master->dma_alignment = dma_get_cache_alignment(); |
5dc47fefe spi: qup: allow b... |
1033 |
master->max_dma_len = SPI_MAX_XFER; |
64ff247a9 spi: Add Qualcomm... |
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
platform_set_drvdata(pdev, master); controller = spi_master_get_devdata(master); controller->dev = dev; controller->base = base; controller->iclk = iclk; controller->cclk = cclk; controller->irq = irq; |
64ff247a9 spi: Add Qualcomm... |
1044 |
|
612762e82 spi: qup: Add DMA... |
1045 1046 1047 1048 1049 |
ret = spi_qup_init_dma(master, res->start); if (ret == -EPROBE_DEFER) goto error; else if (!ret) master->can_dma = spi_qup_can_dma; |
88a19814d spi: qup: fix 64-... |
1050 |
controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev); |
70cea0a95 spi: qup: Add sup... |
1051 |
|
b702b9fb3 spi: qup: Enable ... |
1052 1053 |
if (!controller->qup_v1) master->set_cs = spi_qup_set_cs; |
64ff247a9 spi: Add Qualcomm... |
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
spin_lock_init(&controller->lock); init_completion(&controller->done); iomode = readl_relaxed(base + QUP_IO_M_MODES); size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode); if (size) controller->out_blk_sz = size * 16; else controller->out_blk_sz = 4; size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode); if (size) controller->in_blk_sz = size * 16; else controller->in_blk_sz = 4; size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode); controller->out_fifo_sz = controller->out_blk_sz * (2 << size); size = QUP_IO_M_INPUT_FIFO_SIZE(iomode); controller->in_fifo_sz = controller->in_blk_sz * (2 << size); |
70cea0a95 spi: qup: Add sup... |
1076 1077 1078 |
dev_info(dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d ", controller->in_blk_sz, controller->in_fifo_sz, |
64ff247a9 spi: Add Qualcomm... |
1079 1080 1081 1082 1083 1084 1085 1086 |
controller->out_blk_sz, controller->out_fifo_sz); writel_relaxed(1, base + QUP_SW_RESET); ret = spi_qup_set_state(controller, QUP_STATE_RESET); if (ret) { dev_err(dev, "cannot set RESET state "); |
612762e82 spi: qup: Add DMA... |
1087 |
goto error_dma; |
64ff247a9 spi: Add Qualcomm... |
1088 1089 1090 1091 |
} writel_relaxed(0, base + QUP_OPERATIONAL); writel_relaxed(0, base + QUP_IO_M_MODES); |
70cea0a95 spi: qup: Add sup... |
1092 1093 1094 |
if (!controller->qup_v1) writel_relaxed(0, base + QUP_OPERATIONAL_MASK); |
64ff247a9 spi: Add Qualcomm... |
1095 1096 |
writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN, base + SPI_ERROR_FLAGS_EN); |
70cea0a95 spi: qup: Add sup... |
1097 1098 1099 1100 1101 |
/* if earlier version of the QUP, disable INPUT_OVERRUN */ if (controller->qup_v1) writel_relaxed(QUP_ERROR_OUTPUT_OVER_RUN | QUP_ERROR_INPUT_UNDER_RUN | QUP_ERROR_OUTPUT_UNDER_RUN, base + QUP_ERROR_FLAGS_EN); |
64ff247a9 spi: Add Qualcomm... |
1102 1103 1104 1105 1106 1107 |
writel_relaxed(0, base + SPI_CONFIG); writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL); ret = devm_request_irq(dev, irq, spi_qup_qup_irq, IRQF_TRIGGER_HIGH, pdev->name, controller); if (ret) |
612762e82 spi: qup: Add DMA... |
1108 |
goto error_dma; |
64ff247a9 spi: Add Qualcomm... |
1109 |
|
64ff247a9 spi: Add Qualcomm... |
1110 1111 1112 1113 |
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); |
045c243a5 spi: qup: Fix ord... |
1114 1115 1116 1117 |
ret = devm_spi_register_master(dev, master); if (ret) goto disable_pm; |
64ff247a9 spi: Add Qualcomm... |
1118 |
return 0; |
045c243a5 spi: qup: Fix ord... |
1119 1120 |
disable_pm: pm_runtime_disable(&pdev->dev); |
612762e82 spi: qup: Add DMA... |
1121 1122 |
error_dma: spi_qup_release_dma(master); |
64ff247a9 spi: Add Qualcomm... |
1123 1124 1125 1126 1127 1128 |
error: clk_disable_unprepare(cclk); clk_disable_unprepare(iclk); spi_master_put(master); return ret; } |
ec8330503 spi: Replace CONF... |
1129 |
#ifdef CONFIG_PM |
64ff247a9 spi: Add Qualcomm... |
1130 1131 1132 1133 1134 1135 1136 1137 |
static int spi_qup_pm_suspend_runtime(struct device *device) { struct spi_master *master = dev_get_drvdata(device); struct spi_qup *controller = spi_master_get_devdata(master); u32 config; /* Enable clocks auto gaiting */ config = readl(controller->base + QUP_CONFIG); |
f0ceb114a spi: qup: Fix bui... |
1138 |
config |= QUP_CONFIG_CLOCK_AUTO_GATE; |
64ff247a9 spi: Add Qualcomm... |
1139 |
writel_relaxed(config, controller->base + QUP_CONFIG); |
dae1a7700 spi: qup: Handle ... |
1140 1141 1142 |
clk_disable_unprepare(controller->cclk); clk_disable_unprepare(controller->iclk); |
64ff247a9 spi: Add Qualcomm... |
1143 1144 1145 1146 1147 1148 1149 1150 |
return 0; } static int spi_qup_pm_resume_runtime(struct device *device) { struct spi_master *master = dev_get_drvdata(device); struct spi_qup *controller = spi_master_get_devdata(master); u32 config; |
dae1a7700 spi: qup: Handle ... |
1151 1152 1153 1154 1155 1156 1157 1158 1159 |
int ret; ret = clk_prepare_enable(controller->iclk); if (ret) return ret; ret = clk_prepare_enable(controller->cclk); if (ret) return ret; |
64ff247a9 spi: Add Qualcomm... |
1160 1161 1162 |
/* Disable clocks auto gaiting */ config = readl_relaxed(controller->base + QUP_CONFIG); |
f0ceb114a spi: qup: Fix bui... |
1163 |
config &= ~QUP_CONFIG_CLOCK_AUTO_GATE; |
64ff247a9 spi: Add Qualcomm... |
1164 1165 1166 |
writel_relaxed(config, controller->base + QUP_CONFIG); return 0; } |
ec8330503 spi: Replace CONF... |
1167 |
#endif /* CONFIG_PM */ |
64ff247a9 spi: Add Qualcomm... |
1168 1169 1170 1171 1172 1173 1174 |
#ifdef CONFIG_PM_SLEEP static int spi_qup_suspend(struct device *device) { struct spi_master *master = dev_get_drvdata(device); struct spi_qup *controller = spi_master_get_devdata(master); int ret; |
136b5cd2e spi: qup: call sp... |
1175 1176 1177 1178 1179 |
if (pm_runtime_suspended(device)) { ret = spi_qup_pm_resume_runtime(device); if (ret) return ret; } |
64ff247a9 spi: Add Qualcomm... |
1180 1181 1182 1183 1184 1185 1186 |
ret = spi_master_suspend(master); if (ret) return ret; ret = spi_qup_set_state(controller, QUP_STATE_RESET); if (ret) return ret; |
136b5cd2e spi: qup: call sp... |
1187 1188 |
clk_disable_unprepare(controller->cclk); clk_disable_unprepare(controller->iclk); |
64ff247a9 spi: Add Qualcomm... |
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 |
return 0; } static int spi_qup_resume(struct device *device) { struct spi_master *master = dev_get_drvdata(device); struct spi_qup *controller = spi_master_get_devdata(master); int ret; ret = clk_prepare_enable(controller->iclk); if (ret) return ret; ret = clk_prepare_enable(controller->cclk); if (ret) return ret; ret = spi_qup_set_state(controller, QUP_STATE_RESET); if (ret) return ret; return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ static int spi_qup_remove(struct platform_device *pdev) { struct spi_master *master = dev_get_drvdata(&pdev->dev); struct spi_qup *controller = spi_master_get_devdata(master); int ret; ret = pm_runtime_get_sync(&pdev->dev); |
3d89e141b spi: qup: Fix ret... |
1221 |
if (ret < 0) |
64ff247a9 spi: Add Qualcomm... |
1222 1223 1224 1225 1226 |
return ret; ret = spi_qup_set_state(controller, QUP_STATE_RESET); if (ret) return ret; |
612762e82 spi: qup: Add DMA... |
1227 |
spi_qup_release_dma(master); |
64ff247a9 spi: Add Qualcomm... |
1228 1229 1230 1231 1232 |
clk_disable_unprepare(controller->cclk); clk_disable_unprepare(controller->iclk); pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); |
d2442287e spi: qup: Add spi... |
1233 |
|
64ff247a9 spi: Add Qualcomm... |
1234 1235 |
return 0; } |
113b1a071 spi: qup: Make of... |
1236 |
static const struct of_device_id spi_qup_dt_match[] = { |
4d023737b spi: qup: Fix QUP... |
1237 |
{ .compatible = "qcom,spi-qup-v1.1.1", .data = (void *)1, }, |
64ff247a9 spi: Add Qualcomm... |
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
{ .compatible = "qcom,spi-qup-v2.1.1", }, { .compatible = "qcom,spi-qup-v2.2.1", }, { } }; MODULE_DEVICE_TABLE(of, spi_qup_dt_match); static const struct dev_pm_ops spi_qup_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume) SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime, spi_qup_pm_resume_runtime, NULL) }; static struct platform_driver spi_qup_driver = { .driver = { .name = "spi_qup", |
64ff247a9 spi: Add Qualcomm... |
1254 1255 1256 1257 1258 1259 1260 1261 1262 |
.pm = &spi_qup_dev_pm_ops, .of_match_table = spi_qup_dt_match, }, .probe = spi_qup_probe, .remove = spi_qup_remove, }; module_platform_driver(spi_qup_driver); MODULE_LICENSE("GPL v2"); |
64ff247a9 spi: Add Qualcomm... |
1263 |
MODULE_ALIAS("platform:spi_qup"); |