spi: axi-spi-engine: add support for cs_off
[linux-2.6-block.git] / drivers / spi / spi-axi-spi-engine.c
CommitLineData
fda8d26e 1// SPDX-License-Identifier: GPL-2.0-only
b1353d1c
LPC
2/*
3 * SPI-Engine SPI controller driver
4 * Copyright 2015 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
b1353d1c
LPC
6 */
7
8#include <linux/clk.h>
7f970ecb 9#include <linux/idr.h>
b1353d1c
LPC
10#include <linux/interrupt.h>
11#include <linux/io.h>
12#include <linux/of.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/spi/spi.h>
16
17#define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
18#define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
19#define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
20
21#define SPI_ENGINE_REG_VERSION 0x00
22
23#define SPI_ENGINE_REG_RESET 0x40
24
25#define SPI_ENGINE_REG_INT_ENABLE 0x80
26#define SPI_ENGINE_REG_INT_PENDING 0x84
27#define SPI_ENGINE_REG_INT_SOURCE 0x88
28
29#define SPI_ENGINE_REG_SYNC_ID 0xc0
30
31#define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xd0
32#define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xd4
33#define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xd8
34
35#define SPI_ENGINE_REG_CMD_FIFO 0xe0
36#define SPI_ENGINE_REG_SDO_DATA_FIFO 0xe4
37#define SPI_ENGINE_REG_SDI_DATA_FIFO 0xe8
38#define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xec
39
40#define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
41#define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
42#define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
43#define SPI_ENGINE_INT_SYNC BIT(3)
44
45#define SPI_ENGINE_CONFIG_CPHA BIT(0)
46#define SPI_ENGINE_CONFIG_CPOL BIT(1)
47#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
48
49#define SPI_ENGINE_INST_TRANSFER 0x0
50#define SPI_ENGINE_INST_ASSERT 0x1
51#define SPI_ENGINE_INST_WRITE 0x2
52#define SPI_ENGINE_INST_MISC 0x3
53
54#define SPI_ENGINE_CMD_REG_CLK_DIV 0x0
55#define SPI_ENGINE_CMD_REG_CONFIG 0x1
56
57#define SPI_ENGINE_MISC_SYNC 0x0
58#define SPI_ENGINE_MISC_SLEEP 0x1
59
60#define SPI_ENGINE_TRANSFER_WRITE 0x1
61#define SPI_ENGINE_TRANSFER_READ 0x2
62
63#define SPI_ENGINE_CMD(inst, arg1, arg2) \
64 (((inst) << 12) | ((arg1) << 8) | (arg2))
65
66#define SPI_ENGINE_CMD_TRANSFER(flags, n) \
67 SPI_ENGINE_CMD(SPI_ENGINE_INST_TRANSFER, (flags), (n))
68#define SPI_ENGINE_CMD_ASSERT(delay, cs) \
69 SPI_ENGINE_CMD(SPI_ENGINE_INST_ASSERT, (delay), (cs))
70#define SPI_ENGINE_CMD_WRITE(reg, val) \
71 SPI_ENGINE_CMD(SPI_ENGINE_INST_WRITE, (reg), (val))
72#define SPI_ENGINE_CMD_SLEEP(delay) \
73 SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay))
74#define SPI_ENGINE_CMD_SYNC(id) \
75 SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id))
76
77struct spi_engine_program {
78 unsigned int length;
79 uint16_t instructions[];
80};
81
7f970ecb
DL
82/**
83 * struct spi_engine_message_state - SPI engine per-message state
84 */
85struct spi_engine_message_state {
86 /** Instructions for executing this message. */
b1353d1c 87 struct spi_engine_program *p;
7f970ecb 88 /** Number of elements in cmd_buf array. */
b1353d1c 89 unsigned cmd_length;
7f970ecb 90 /** Array of commands not yet written to CMD FIFO. */
b1353d1c 91 const uint16_t *cmd_buf;
7f970ecb 92 /** Next xfer with tx_buf not yet fully written to TX FIFO. */
b1353d1c 93 struct spi_transfer *tx_xfer;
7f970ecb 94 /** Size of tx_buf in bytes. */
b1353d1c 95 unsigned int tx_length;
7f970ecb 96 /** Bytes not yet written to TX FIFO. */
b1353d1c 97 const uint8_t *tx_buf;
7f970ecb 98 /** Next xfer with rx_buf not yet fully written to RX FIFO. */
b1353d1c 99 struct spi_transfer *rx_xfer;
7f970ecb 100 /** Size of tx_buf in bytes. */
b1353d1c 101 unsigned int rx_length;
7f970ecb 102 /** Bytes not yet written to the RX FIFO. */
b1353d1c 103 uint8_t *rx_buf;
7f970ecb
DL
104 /** ID to correlate SYNC interrupts with this message. */
105 u8 sync_id;
106};
107
108struct spi_engine {
109 struct clk *clk;
110 struct clk *ref_clk;
111
112 spinlock_t lock;
113
114 void __iomem *base;
7f970ecb 115 struct ida sync_ida;
b1353d1c
LPC
116
117 unsigned int int_enable;
118};
119
120static void spi_engine_program_add_cmd(struct spi_engine_program *p,
121 bool dry, uint16_t cmd)
122{
123 if (!dry)
124 p->instructions[p->length] = cmd;
125 p->length++;
126}
127
128static unsigned int spi_engine_get_config(struct spi_device *spi)
129{
130 unsigned int config = 0;
131
132 if (spi->mode & SPI_CPOL)
133 config |= SPI_ENGINE_CONFIG_CPOL;
134 if (spi->mode & SPI_CPHA)
135 config |= SPI_ENGINE_CONFIG_CPHA;
136 if (spi->mode & SPI_3WIRE)
137 config |= SPI_ENGINE_CONFIG_3WIRE;
138
139 return config;
140}
141
142static unsigned int spi_engine_get_clk_div(struct spi_engine *spi_engine,
143 struct spi_device *spi, struct spi_transfer *xfer)
144{
145 unsigned int clk_div;
146
147 clk_div = DIV_ROUND_UP(clk_get_rate(spi_engine->ref_clk),
148 xfer->speed_hz * 2);
149 if (clk_div > 255)
150 clk_div = 255;
151 else if (clk_div > 0)
152 clk_div -= 1;
153
154 return clk_div;
155}
156
157static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
158 struct spi_transfer *xfer)
159{
160 unsigned int len = xfer->len;
161
162 while (len) {
163 unsigned int n = min(len, 256U);
164 unsigned int flags = 0;
165
166 if (xfer->tx_buf)
167 flags |= SPI_ENGINE_TRANSFER_WRITE;
168 if (xfer->rx_buf)
169 flags |= SPI_ENGINE_TRANSFER_READ;
170
171 spi_engine_program_add_cmd(p, dry,
172 SPI_ENGINE_CMD_TRANSFER(flags, n - 1));
173 len -= n;
174 }
175}
176
177static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
acc7720d
AA
178 struct spi_engine *spi_engine, unsigned int clk_div,
179 struct spi_transfer *xfer)
b1353d1c
LPC
180{
181 unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk);
182 unsigned int t;
acc7720d
AA
183 int delay;
184
93c94144
AA
185 delay = spi_delay_to_ns(&xfer->delay, xfer);
186 if (delay < 0)
187 return;
188 delay /= 1000;
b1353d1c
LPC
189
190 if (delay == 0)
191 return;
192
193 t = DIV_ROUND_UP(delay * spi_clk, (clk_div + 1) * 2);
194 while (t) {
195 unsigned int n = min(t, 256U);
196
197 spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_SLEEP(n - 1));
198 t -= n;
199 }
200}
201
202static void spi_engine_gen_cs(struct spi_engine_program *p, bool dry,
203 struct spi_device *spi, bool assert)
204{
205 unsigned int mask = 0xff;
206
207 if (assert)
9e264f3f 208 mask ^= BIT(spi_get_chipselect(spi, 0));
b1353d1c
LPC
209
210 spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(1, mask));
211}
212
213static int spi_engine_compile_message(struct spi_engine *spi_engine,
214 struct spi_message *msg, bool dry, struct spi_engine_program *p)
215{
216 struct spi_device *spi = msg->spi;
217 struct spi_transfer *xfer;
218 int clk_div, new_clk_div;
145bb2ae 219 bool keep_cs = false;
b1353d1c
LPC
220
221 clk_div = -1;
222
223 spi_engine_program_add_cmd(p, dry,
224 SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
225 spi_engine_get_config(spi)));
226
145bb2ae
DL
227 xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list);
228 spi_engine_gen_cs(p, dry, spi, !xfer->cs_off);
229
b1353d1c
LPC
230 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
231 new_clk_div = spi_engine_get_clk_div(spi_engine, spi, xfer);
232 if (new_clk_div != clk_div) {
233 clk_div = new_clk_div;
234 spi_engine_program_add_cmd(p, dry,
235 SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV,
236 clk_div));
237 }
238
b1353d1c 239 spi_engine_gen_xfer(p, dry, xfer);
acc7720d 240 spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
b1353d1c 241
145bb2ae
DL
242 if (xfer->cs_change) {
243 if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
244 keep_cs = true;
245 } else {
246 if (!xfer->cs_off)
247 spi_engine_gen_cs(p, dry, spi, false);
248
249 if (!list_next_entry(xfer, transfer_list)->cs_off)
250 spi_engine_gen_cs(p, dry, spi, true);
251 }
252 } else if (!list_is_last(&xfer->transfer_list, &msg->transfers) &&
253 xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) {
254 spi_engine_gen_cs(p, dry, spi, xfer->cs_off);
255 }
b1353d1c
LPC
256 }
257
145bb2ae
DL
258 if (!keep_cs)
259 spi_engine_gen_cs(p, dry, spi, false);
260
b1353d1c
LPC
261 return 0;
262}
263
4e991445 264static void spi_engine_xfer_next(struct spi_message *msg,
b1353d1c
LPC
265 struct spi_transfer **_xfer)
266{
b1353d1c
LPC
267 struct spi_transfer *xfer = *_xfer;
268
269 if (!xfer) {
270 xfer = list_first_entry(&msg->transfers,
271 struct spi_transfer, transfer_list);
272 } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
273 xfer = NULL;
274 } else {
275 xfer = list_next_entry(xfer, transfer_list);
276 }
277
278 *_xfer = xfer;
279}
280
4e991445 281static void spi_engine_tx_next(struct spi_message *msg)
b1353d1c 282{
4e991445 283 struct spi_engine_message_state *st = msg->state;
7f970ecb 284 struct spi_transfer *xfer = st->tx_xfer;
b1353d1c
LPC
285
286 do {
4e991445 287 spi_engine_xfer_next(msg, &xfer);
b1353d1c
LPC
288 } while (xfer && !xfer->tx_buf);
289
7f970ecb 290 st->tx_xfer = xfer;
b1353d1c 291 if (xfer) {
7f970ecb
DL
292 st->tx_length = xfer->len;
293 st->tx_buf = xfer->tx_buf;
b1353d1c 294 } else {
7f970ecb 295 st->tx_buf = NULL;
b1353d1c
LPC
296 }
297}
298
4e991445 299static void spi_engine_rx_next(struct spi_message *msg)
b1353d1c 300{
4e991445 301 struct spi_engine_message_state *st = msg->state;
7f970ecb 302 struct spi_transfer *xfer = st->rx_xfer;
b1353d1c
LPC
303
304 do {
4e991445 305 spi_engine_xfer_next(msg, &xfer);
b1353d1c
LPC
306 } while (xfer && !xfer->rx_buf);
307
7f970ecb 308 st->rx_xfer = xfer;
b1353d1c 309 if (xfer) {
7f970ecb
DL
310 st->rx_length = xfer->len;
311 st->rx_buf = xfer->rx_buf;
b1353d1c 312 } else {
7f970ecb 313 st->rx_buf = NULL;
b1353d1c
LPC
314 }
315}
316
4e991445
DL
317static bool spi_engine_write_cmd_fifo(struct spi_engine *spi_engine,
318 struct spi_message *msg)
b1353d1c
LPC
319{
320 void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_CMD_FIFO;
4e991445 321 struct spi_engine_message_state *st = msg->state;
b1353d1c
LPC
322 unsigned int n, m, i;
323 const uint16_t *buf;
324
325 n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_CMD_FIFO_ROOM);
7f970ecb
DL
326 while (n && st->cmd_length) {
327 m = min(n, st->cmd_length);
328 buf = st->cmd_buf;
b1353d1c
LPC
329 for (i = 0; i < m; i++)
330 writel_relaxed(buf[i], addr);
7f970ecb
DL
331 st->cmd_buf += m;
332 st->cmd_length -= m;
b1353d1c
LPC
333 n -= m;
334 }
335
7f970ecb 336 return st->cmd_length != 0;
b1353d1c
LPC
337}
338
4e991445
DL
339static bool spi_engine_write_tx_fifo(struct spi_engine *spi_engine,
340 struct spi_message *msg)
b1353d1c
LPC
341{
342 void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDO_DATA_FIFO;
4e991445 343 struct spi_engine_message_state *st = msg->state;
b1353d1c
LPC
344 unsigned int n, m, i;
345 const uint8_t *buf;
346
347 n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDO_FIFO_ROOM);
7f970ecb
DL
348 while (n && st->tx_length) {
349 m = min(n, st->tx_length);
350 buf = st->tx_buf;
b1353d1c
LPC
351 for (i = 0; i < m; i++)
352 writel_relaxed(buf[i], addr);
7f970ecb
DL
353 st->tx_buf += m;
354 st->tx_length -= m;
b1353d1c 355 n -= m;
7f970ecb 356 if (st->tx_length == 0)
4e991445 357 spi_engine_tx_next(msg);
b1353d1c
LPC
358 }
359
7f970ecb 360 return st->tx_length != 0;
b1353d1c
LPC
361}
362
4e991445
DL
363static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine,
364 struct spi_message *msg)
b1353d1c
LPC
365{
366 void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDI_DATA_FIFO;
4e991445 367 struct spi_engine_message_state *st = msg->state;
b1353d1c
LPC
368 unsigned int n, m, i;
369 uint8_t *buf;
370
371 n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDI_FIFO_LEVEL);
7f970ecb
DL
372 while (n && st->rx_length) {
373 m = min(n, st->rx_length);
374 buf = st->rx_buf;
b1353d1c
LPC
375 for (i = 0; i < m; i++)
376 buf[i] = readl_relaxed(addr);
7f970ecb
DL
377 st->rx_buf += m;
378 st->rx_length -= m;
b1353d1c 379 n -= m;
7f970ecb 380 if (st->rx_length == 0)
4e991445 381 spi_engine_rx_next(msg);
b1353d1c
LPC
382 }
383
7f970ecb 384 return st->rx_length != 0;
b1353d1c
LPC
385}
386
387static irqreturn_t spi_engine_irq(int irq, void *devid)
388{
9d5920b3 389 struct spi_controller *host = devid;
4e991445 390 struct spi_message *msg = host->cur_msg;
9d5920b3 391 struct spi_engine *spi_engine = spi_controller_get_devdata(host);
b1353d1c
LPC
392 unsigned int disable_int = 0;
393 unsigned int pending;
4a074dde 394 int completed_id = -1;
b1353d1c
LPC
395
396 pending = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
397
398 if (pending & SPI_ENGINE_INT_SYNC) {
399 writel_relaxed(SPI_ENGINE_INT_SYNC,
400 spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
4a074dde 401 completed_id = readl_relaxed(
b1353d1c
LPC
402 spi_engine->base + SPI_ENGINE_REG_SYNC_ID);
403 }
404
405 spin_lock(&spi_engine->lock);
406
407 if (pending & SPI_ENGINE_INT_CMD_ALMOST_EMPTY) {
4e991445 408 if (!spi_engine_write_cmd_fifo(spi_engine, msg))
b1353d1c
LPC
409 disable_int |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
410 }
411
412 if (pending & SPI_ENGINE_INT_SDO_ALMOST_EMPTY) {
4e991445 413 if (!spi_engine_write_tx_fifo(spi_engine, msg))
b1353d1c
LPC
414 disable_int |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
415 }
416
417 if (pending & (SPI_ENGINE_INT_SDI_ALMOST_FULL | SPI_ENGINE_INT_SYNC)) {
4e991445 418 if (!spi_engine_read_rx_fifo(spi_engine, msg))
b1353d1c
LPC
419 disable_int |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
420 }
421
4e991445
DL
422 if (pending & SPI_ENGINE_INT_SYNC && msg) {
423 struct spi_engine_message_state *st = msg->state;
7f970ecb 424
4a074dde 425 if (completed_id == st->sync_id) {
b1353d1c
LPC
426 msg->status = 0;
427 msg->actual_length = msg->frame_length;
9d5920b3 428 spi_finalize_current_message(host);
b1353d1c
LPC
429 disable_int |= SPI_ENGINE_INT_SYNC;
430 }
431 }
432
433 if (disable_int) {
434 spi_engine->int_enable &= ~disable_int;
435 writel_relaxed(spi_engine->int_enable,
436 spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
437 }
438
439 spin_unlock(&spi_engine->lock);
440
441 return IRQ_HANDLED;
442}
443
0c74de5c
DL
444static int spi_engine_prepare_message(struct spi_controller *host,
445 struct spi_message *msg)
b1353d1c
LPC
446{
447 struct spi_engine_program p_dry, *p;
9d5920b3 448 struct spi_engine *spi_engine = spi_controller_get_devdata(host);
7f970ecb 449 struct spi_engine_message_state *st;
b1353d1c 450 size_t size;
7f970ecb
DL
451 int ret;
452
453 st = kzalloc(sizeof(*st), GFP_KERNEL);
454 if (!st)
455 return -ENOMEM;
b1353d1c
LPC
456
457 p_dry.length = 0;
458 spi_engine_compile_message(spi_engine, msg, true, &p_dry);
459
460 size = sizeof(*p->instructions) * (p_dry.length + 1);
461 p = kzalloc(sizeof(*p) + size, GFP_KERNEL);
7f970ecb
DL
462 if (!p) {
463 kfree(st);
b1353d1c 464 return -ENOMEM;
7f970ecb
DL
465 }
466
467 ret = ida_alloc_range(&spi_engine->sync_ida, 0, U8_MAX, GFP_KERNEL);
468 if (ret < 0) {
469 kfree(p);
470 kfree(st);
471 return ret;
472 }
473
474 st->sync_id = ret;
475
b1353d1c
LPC
476 spi_engine_compile_message(spi_engine, msg, false, p);
477
7f970ecb 478 spi_engine_program_add_cmd(p, false, SPI_ENGINE_CMD_SYNC(st->sync_id));
b1353d1c 479
7f970ecb 480 st->p = p;
7f970ecb
DL
481 st->cmd_buf = p->instructions;
482 st->cmd_length = p->length;
0c74de5c
DL
483 msg->state = st;
484
485 return 0;
486}
487
488static int spi_engine_unprepare_message(struct spi_controller *host,
489 struct spi_message *msg)
490{
491 struct spi_engine *spi_engine = spi_controller_get_devdata(host);
492 struct spi_engine_message_state *st = msg->state;
493
494 ida_free(&spi_engine->sync_ida, st->sync_id);
495 kfree(st->p);
496 kfree(st);
497
498 return 0;
499}
500
501static int spi_engine_transfer_one_message(struct spi_controller *host,
502 struct spi_message *msg)
503{
504 struct spi_engine *spi_engine = spi_controller_get_devdata(host);
505 struct spi_engine_message_state *st = msg->state;
506 unsigned int int_enable = 0;
507 unsigned long flags;
508
509 spin_lock_irqsave(&spi_engine->lock, flags);
510
4e991445 511 if (spi_engine_write_cmd_fifo(spi_engine, msg))
b1353d1c
LPC
512 int_enable |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
513
4e991445
DL
514 spi_engine_tx_next(msg);
515 if (spi_engine_write_tx_fifo(spi_engine, msg))
b1353d1c
LPC
516 int_enable |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
517
4e991445 518 spi_engine_rx_next(msg);
7f970ecb 519 if (st->rx_length != 0)
b1353d1c
LPC
520 int_enable |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
521
522 int_enable |= SPI_ENGINE_INT_SYNC;
523
524 writel_relaxed(int_enable,
525 spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
526 spi_engine->int_enable = int_enable;
527 spin_unlock_irqrestore(&spi_engine->lock, flags);
528
529 return 0;
530}
531
e094de13
DL
532static void spi_engine_release_hw(void *p)
533{
534 struct spi_engine *spi_engine = p;
535
536 writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
537 writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
538 writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
539}
540
b1353d1c
LPC
541static int spi_engine_probe(struct platform_device *pdev)
542{
543 struct spi_engine *spi_engine;
9d5920b3 544 struct spi_controller *host;
b1353d1c 545 unsigned int version;
b1353d1c
LPC
546 int irq;
547 int ret;
548
549 irq = platform_get_irq(pdev, 0);
8102d64c
RJ
550 if (irq < 0)
551 return irq;
b1353d1c 552
e12cd96e 553 host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi_engine));
9d5920b3 554 if (!host)
b1353d1c
LPC
555 return -ENOMEM;
556
9e4ce522 557 spi_engine = spi_controller_get_devdata(host);
b1353d1c
LPC
558
559 spin_lock_init(&spi_engine->lock);
7f970ecb 560 ida_init(&spi_engine->sync_ida);
b1353d1c 561
a08199b3 562 spi_engine->clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
e12cd96e
DL
563 if (IS_ERR(spi_engine->clk))
564 return PTR_ERR(spi_engine->clk);
b1353d1c 565
a08199b3 566 spi_engine->ref_clk = devm_clk_get_enabled(&pdev->dev, "spi_clk");
e12cd96e
DL
567 if (IS_ERR(spi_engine->ref_clk))
568 return PTR_ERR(spi_engine->ref_clk);
b1353d1c 569
d103729a 570 spi_engine->base = devm_platform_ioremap_resource(pdev, 0);
e12cd96e
DL
571 if (IS_ERR(spi_engine->base))
572 return PTR_ERR(spi_engine->base);
d103729a
RH
573
574 version = readl(spi_engine->base + SPI_ENGINE_REG_VERSION);
575 if (SPI_ENGINE_VERSION_MAJOR(version) != 1) {
576 dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%c\n",
577 SPI_ENGINE_VERSION_MAJOR(version),
578 SPI_ENGINE_VERSION_MINOR(version),
579 SPI_ENGINE_VERSION_PATCH(version));
e12cd96e 580 return -ENODEV;
d103729a
RH
581 }
582
b1353d1c
LPC
583 writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_RESET);
584 writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
585 writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
586
e094de13
DL
587 ret = devm_add_action_or_reset(&pdev->dev, spi_engine_release_hw,
588 spi_engine);
589 if (ret)
590 return ret;
591
076f32d5
DL
592 ret = devm_request_irq(&pdev->dev, irq, spi_engine_irq, 0, pdev->name,
593 host);
b1353d1c 594 if (ret)
e12cd96e 595 return ret;
b1353d1c 596
9d5920b3
YY
597 host->dev.of_node = pdev->dev.of_node;
598 host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
599 host->bits_per_word_mask = SPI_BPW_MASK(8);
600 host->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
601 host->transfer_one_message = spi_engine_transfer_one_message;
0c74de5c
DL
602 host->prepare_message = spi_engine_prepare_message;
603 host->unprepare_message = spi_engine_unprepare_message;
9d5920b3 604 host->num_chipselect = 8;
b1353d1c 605
e6d5eb85
DL
606 if (host->max_speed_hz == 0)
607 return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0");
608
e16e71e3 609 ret = devm_spi_register_controller(&pdev->dev, host);
b1353d1c 610 if (ret)
076f32d5 611 return ret;
b1353d1c 612
9d5920b3 613 platform_set_drvdata(pdev, host);
b1353d1c
LPC
614
615 return 0;
b1353d1c
LPC
616}
617
b1353d1c
LPC
618static const struct of_device_id spi_engine_match_table[] = {
619 { .compatible = "adi,axi-spi-engine-1.00.a" },
620 { },
621};
01affe23 622MODULE_DEVICE_TABLE(of, spi_engine_match_table);
b1353d1c
LPC
623
624static struct platform_driver spi_engine_driver = {
625 .probe = spi_engine_probe,
b1353d1c
LPC
626 .driver = {
627 .name = "spi-engine",
628 .of_match_table = spi_engine_match_table,
629 },
630};
631module_platform_driver(spi_engine_driver);
632
633MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
634MODULE_DESCRIPTION("Analog Devices SPI engine peripheral driver");
635MODULE_LICENSE("GPL");