1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | // Copyright (C) IBM Corporation 2020 |
3 | |
4 | #include <linux/bitfield.h> |
5 | #include <linux/bits.h> |
6 | #include <linux/fsi.h> |
7 | #include <linux/jiffies.h> |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/spi/spi.h> |
12 | |
13 | #define FSI_ENGID_SPI 0x23 |
14 | #define FSI_MBOX_ROOT_CTRL_8 0x2860 |
15 | #define FSI_MBOX_ROOT_CTRL_8_SPI_MUX 0xf0000000 |
16 | |
17 | #define FSI2SPI_DATA0 0x00 |
18 | #define FSI2SPI_DATA1 0x04 |
19 | #define FSI2SPI_CMD 0x08 |
20 | #define FSI2SPI_CMD_WRITE BIT(31) |
21 | #define FSI2SPI_RESET 0x18 |
22 | #define FSI2SPI_STATUS 0x1c |
23 | #define FSI2SPI_STATUS_ANY_ERROR BIT(31) |
24 | #define FSI2SPI_IRQ 0x20 |
25 | |
26 | #define SPI_FSI_BASE 0x70000 |
27 | #define SPI_FSI_TIMEOUT_MS 1000 |
28 | #define SPI_FSI_MAX_RX_SIZE 8 |
29 | #define SPI_FSI_MAX_TX_SIZE 40 |
30 | |
31 | #define SPI_FSI_ERROR 0x0 |
32 | #define SPI_FSI_COUNTER_CFG 0x1 |
33 | #define SPI_FSI_CFG1 0x2 |
34 | #define SPI_FSI_CLOCK_CFG 0x3 |
35 | #define SPI_FSI_CLOCK_CFG_MM_ENABLE BIT_ULL(32) |
36 | #define SPI_FSI_CLOCK_CFG_ECC_DISABLE (BIT_ULL(35) | BIT_ULL(33)) |
37 | #define SPI_FSI_CLOCK_CFG_RESET1 (BIT_ULL(36) | BIT_ULL(38)) |
38 | #define SPI_FSI_CLOCK_CFG_RESET2 (BIT_ULL(37) | BIT_ULL(39)) |
39 | #define SPI_FSI_CLOCK_CFG_MODE (BIT_ULL(41) | BIT_ULL(42)) |
40 | #define SPI_FSI_CLOCK_CFG_SCK_RECV_DEL GENMASK_ULL(51, 44) |
41 | #define SPI_FSI_CLOCK_CFG_SCK_NO_DEL BIT_ULL(51) |
42 | #define SPI_FSI_CLOCK_CFG_SCK_DIV GENMASK_ULL(63, 52) |
43 | #define SPI_FSI_MMAP 0x4 |
44 | #define SPI_FSI_DATA_TX 0x5 |
45 | #define SPI_FSI_DATA_RX 0x6 |
46 | #define SPI_FSI_SEQUENCE 0x7 |
47 | #define SPI_FSI_SEQUENCE_STOP 0x00 |
48 | #define SPI_FSI_SEQUENCE_SEL_SLAVE(x) (0x10 | ((x) & 0xf)) |
49 | #define SPI_FSI_SEQUENCE_SHIFT_OUT(x) (0x30 | ((x) & 0xf)) |
50 | #define SPI_FSI_SEQUENCE_SHIFT_IN(x) (0x40 | ((x) & 0xf)) |
51 | #define SPI_FSI_SEQUENCE_COPY_DATA_TX 0xc0 |
52 | #define SPI_FSI_SEQUENCE_BRANCH(x) (0xe0 | ((x) & 0xf)) |
53 | #define SPI_FSI_STATUS 0x8 |
54 | #define SPI_FSI_STATUS_ERROR \ |
55 | (GENMASK_ULL(31, 21) | GENMASK_ULL(15, 12)) |
56 | #define SPI_FSI_STATUS_SEQ_STATE GENMASK_ULL(55, 48) |
57 | #define SPI_FSI_STATUS_SEQ_STATE_IDLE BIT_ULL(48) |
58 | #define SPI_FSI_STATUS_TDR_UNDERRUN BIT_ULL(57) |
59 | #define SPI_FSI_STATUS_TDR_OVERRUN BIT_ULL(58) |
60 | #define SPI_FSI_STATUS_TDR_FULL BIT_ULL(59) |
61 | #define SPI_FSI_STATUS_RDR_UNDERRUN BIT_ULL(61) |
62 | #define SPI_FSI_STATUS_RDR_OVERRUN BIT_ULL(62) |
63 | #define SPI_FSI_STATUS_RDR_FULL BIT_ULL(63) |
64 | #define SPI_FSI_STATUS_ANY_ERROR \ |
65 | (SPI_FSI_STATUS_ERROR | \ |
66 | SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \ |
67 | SPI_FSI_STATUS_RDR_OVERRUN) |
68 | #define SPI_FSI_PORT_CTRL 0x9 |
69 | |
70 | struct fsi2spi { |
71 | struct fsi_device *fsi; /* FSI2SPI CFAM engine device */ |
72 | struct mutex lock; /* lock access to the device */ |
73 | }; |
74 | |
75 | struct fsi_spi { |
76 | struct device *dev; /* SPI controller device */ |
77 | struct fsi2spi *bridge; /* FSI2SPI device */ |
78 | u32 base; |
79 | }; |
80 | |
81 | struct fsi_spi_sequence { |
82 | int bit; |
83 | u64 data; |
84 | }; |
85 | |
86 | static int fsi_spi_check_mux(struct fsi_device *fsi, struct device *dev) |
87 | { |
88 | int rc; |
89 | u32 root_ctrl_8; |
90 | __be32 root_ctrl_8_be; |
91 | |
92 | rc = fsi_slave_read(slave: fsi->slave, FSI_MBOX_ROOT_CTRL_8, val: &root_ctrl_8_be, |
93 | size: sizeof(root_ctrl_8_be)); |
94 | if (rc) |
95 | return rc; |
96 | |
97 | root_ctrl_8 = be32_to_cpu(root_ctrl_8_be); |
98 | dev_dbg(dev, "Root control register 8: %08x\n" , root_ctrl_8); |
99 | if ((root_ctrl_8 & FSI_MBOX_ROOT_CTRL_8_SPI_MUX) == |
100 | FSI_MBOX_ROOT_CTRL_8_SPI_MUX) |
101 | return 0; |
102 | |
103 | return -ENOLINK; |
104 | } |
105 | |
106 | static int fsi_spi_check_status(struct fsi_spi *ctx) |
107 | { |
108 | int rc; |
109 | u32 sts; |
110 | __be32 sts_be; |
111 | |
112 | rc = fsi_device_read(dev: ctx->bridge->fsi, FSI2SPI_STATUS, val: &sts_be, |
113 | size: sizeof(sts_be)); |
114 | if (rc) |
115 | return rc; |
116 | |
117 | sts = be32_to_cpu(sts_be); |
118 | if (sts & FSI2SPI_STATUS_ANY_ERROR) { |
119 | dev_err(ctx->dev, "Error with FSI2SPI interface: %08x.\n" , sts); |
120 | return -EIO; |
121 | } |
122 | |
123 | return 0; |
124 | } |
125 | |
126 | static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value) |
127 | { |
128 | int rc = 0; |
129 | __be32 cmd_be; |
130 | __be32 data_be; |
131 | u32 cmd = offset + ctx->base; |
132 | struct fsi2spi *bridge = ctx->bridge; |
133 | |
134 | *value = 0ULL; |
135 | |
136 | if (cmd & FSI2SPI_CMD_WRITE) |
137 | return -EINVAL; |
138 | |
139 | rc = mutex_lock_interruptible(&bridge->lock); |
140 | if (rc) |
141 | return rc; |
142 | |
143 | cmd_be = cpu_to_be32(cmd); |
144 | rc = fsi_device_write(dev: bridge->fsi, FSI2SPI_CMD, val: &cmd_be, |
145 | size: sizeof(cmd_be)); |
146 | if (rc) |
147 | goto unlock; |
148 | |
149 | rc = fsi_spi_check_status(ctx); |
150 | if (rc) |
151 | goto unlock; |
152 | |
153 | rc = fsi_device_read(dev: bridge->fsi, FSI2SPI_DATA0, val: &data_be, |
154 | size: sizeof(data_be)); |
155 | if (rc) |
156 | goto unlock; |
157 | |
158 | *value |= (u64)be32_to_cpu(data_be) << 32; |
159 | |
160 | rc = fsi_device_read(dev: bridge->fsi, FSI2SPI_DATA1, val: &data_be, |
161 | size: sizeof(data_be)); |
162 | if (rc) |
163 | goto unlock; |
164 | |
165 | *value |= (u64)be32_to_cpu(data_be); |
166 | dev_dbg(ctx->dev, "Read %02x[%016llx].\n" , offset, *value); |
167 | |
168 | unlock: |
169 | mutex_unlock(lock: &bridge->lock); |
170 | return rc; |
171 | } |
172 | |
173 | static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value) |
174 | { |
175 | int rc = 0; |
176 | __be32 cmd_be; |
177 | __be32 data_be; |
178 | u32 cmd = offset + ctx->base; |
179 | struct fsi2spi *bridge = ctx->bridge; |
180 | |
181 | if (cmd & FSI2SPI_CMD_WRITE) |
182 | return -EINVAL; |
183 | |
184 | rc = mutex_lock_interruptible(&bridge->lock); |
185 | if (rc) |
186 | return rc; |
187 | |
188 | dev_dbg(ctx->dev, "Write %02x[%016llx].\n" , offset, value); |
189 | |
190 | data_be = cpu_to_be32(upper_32_bits(value)); |
191 | rc = fsi_device_write(dev: bridge->fsi, FSI2SPI_DATA0, val: &data_be, |
192 | size: sizeof(data_be)); |
193 | if (rc) |
194 | goto unlock; |
195 | |
196 | data_be = cpu_to_be32(lower_32_bits(value)); |
197 | rc = fsi_device_write(dev: bridge->fsi, FSI2SPI_DATA1, val: &data_be, |
198 | size: sizeof(data_be)); |
199 | if (rc) |
200 | goto unlock; |
201 | |
202 | cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE); |
203 | rc = fsi_device_write(dev: bridge->fsi, FSI2SPI_CMD, val: &cmd_be, |
204 | size: sizeof(cmd_be)); |
205 | if (rc) |
206 | goto unlock; |
207 | |
208 | rc = fsi_spi_check_status(ctx); |
209 | |
210 | unlock: |
211 | mutex_unlock(lock: &bridge->lock); |
212 | return rc; |
213 | } |
214 | |
215 | static int fsi_spi_data_in(u64 in, u8 *rx, int len) |
216 | { |
217 | int i; |
218 | int num_bytes = min(len, 8); |
219 | |
220 | for (i = 0; i < num_bytes; ++i) |
221 | rx[i] = (u8)(in >> (8 * ((num_bytes - 1) - i))); |
222 | |
223 | return num_bytes; |
224 | } |
225 | |
226 | static int fsi_spi_data_out(u64 *out, const u8 *tx, int len) |
227 | { |
228 | int i; |
229 | int num_bytes = min(len, 8); |
230 | u8 *out_bytes = (u8 *)out; |
231 | |
232 | /* Unused bytes of the tx data should be 0. */ |
233 | *out = 0ULL; |
234 | |
235 | for (i = 0; i < num_bytes; ++i) |
236 | out_bytes[8 - (i + 1)] = tx[i]; |
237 | |
238 | return num_bytes; |
239 | } |
240 | |
241 | static int fsi_spi_reset(struct fsi_spi *ctx) |
242 | { |
243 | int rc; |
244 | |
245 | dev_dbg(ctx->dev, "Resetting SPI controller.\n" ); |
246 | |
247 | rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, |
248 | SPI_FSI_CLOCK_CFG_RESET1); |
249 | if (rc) |
250 | return rc; |
251 | |
252 | rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, |
253 | SPI_FSI_CLOCK_CFG_RESET2); |
254 | if (rc) |
255 | return rc; |
256 | |
257 | return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, value: 0ULL); |
258 | } |
259 | |
260 | static int fsi_spi_status(struct fsi_spi *ctx, u64 *status, const char *dir) |
261 | { |
262 | int rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, value: status); |
263 | |
264 | if (rc) |
265 | return rc; |
266 | |
267 | if (*status & SPI_FSI_STATUS_ANY_ERROR) { |
268 | dev_err(ctx->dev, "%s error: %016llx\n" , dir, *status); |
269 | |
270 | rc = fsi_spi_reset(ctx); |
271 | if (rc) |
272 | return rc; |
273 | |
274 | return -EREMOTEIO; |
275 | } |
276 | |
277 | return 0; |
278 | } |
279 | |
280 | static void fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) |
281 | { |
282 | /* |
283 | * Add the next byte of instruction to the 8-byte sequence register. |
284 | * Then decrement the counter so that the next instruction will go in |
285 | * the right place. Return the index of the slot we just filled in the |
286 | * sequence register. |
287 | */ |
288 | seq->data |= (u64)val << seq->bit; |
289 | seq->bit -= 8; |
290 | } |
291 | |
292 | static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq) |
293 | { |
294 | seq->bit = 56; |
295 | seq->data = 0ULL; |
296 | } |
297 | |
298 | static int fsi_spi_transfer_data(struct fsi_spi *ctx, |
299 | struct spi_transfer *transfer) |
300 | { |
301 | int loops; |
302 | int rc = 0; |
303 | unsigned long end; |
304 | u64 status = 0ULL; |
305 | |
306 | if (transfer->tx_buf) { |
307 | int nb; |
308 | int sent = 0; |
309 | u64 out = 0ULL; |
310 | const u8 *tx = transfer->tx_buf; |
311 | |
312 | while (transfer->len > sent) { |
313 | nb = fsi_spi_data_out(out: &out, tx: &tx[sent], |
314 | len: (int)transfer->len - sent); |
315 | |
316 | rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, value: out); |
317 | if (rc) |
318 | return rc; |
319 | |
320 | loops = 0; |
321 | end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS); |
322 | do { |
323 | if (loops++ && time_after(jiffies, end)) |
324 | return -ETIMEDOUT; |
325 | |
326 | rc = fsi_spi_status(ctx, status: &status, dir: "TX" ); |
327 | if (rc) |
328 | return rc; |
329 | } while (status & SPI_FSI_STATUS_TDR_FULL); |
330 | |
331 | sent += nb; |
332 | } |
333 | } else if (transfer->rx_buf) { |
334 | int recv = 0; |
335 | u64 in = 0ULL; |
336 | u8 *rx = transfer->rx_buf; |
337 | |
338 | while (transfer->len > recv) { |
339 | loops = 0; |
340 | end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS); |
341 | do { |
342 | if (loops++ && time_after(jiffies, end)) |
343 | return -ETIMEDOUT; |
344 | |
345 | rc = fsi_spi_status(ctx, status: &status, dir: "RX" ); |
346 | if (rc) |
347 | return rc; |
348 | } while (!(status & SPI_FSI_STATUS_RDR_FULL)); |
349 | |
350 | rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, value: &in); |
351 | if (rc) |
352 | return rc; |
353 | |
354 | recv += fsi_spi_data_in(in, rx: &rx[recv], |
355 | len: (int)transfer->len - recv); |
356 | } |
357 | } |
358 | |
359 | return 0; |
360 | } |
361 | |
362 | static int fsi_spi_transfer_init(struct fsi_spi *ctx) |
363 | { |
364 | int loops = 0; |
365 | int rc; |
366 | bool reset = false; |
367 | unsigned long end; |
368 | u64 seq_state; |
369 | u64 clock_cfg = 0ULL; |
370 | u64 status = 0ULL; |
371 | u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE | |
372 | SPI_FSI_CLOCK_CFG_SCK_NO_DEL | |
373 | FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19); |
374 | |
375 | end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS); |
376 | do { |
377 | if (loops++ && time_after(jiffies, end)) |
378 | return -ETIMEDOUT; |
379 | |
380 | rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, value: &status); |
381 | if (rc) |
382 | return rc; |
383 | |
384 | seq_state = status & SPI_FSI_STATUS_SEQ_STATE; |
385 | |
386 | if (status & (SPI_FSI_STATUS_ANY_ERROR | |
387 | SPI_FSI_STATUS_TDR_FULL | |
388 | SPI_FSI_STATUS_RDR_FULL)) { |
389 | if (reset) { |
390 | dev_err(ctx->dev, |
391 | "Initialization error: %08llx\n" , |
392 | status); |
393 | return -EIO; |
394 | } |
395 | |
396 | rc = fsi_spi_reset(ctx); |
397 | if (rc) |
398 | return rc; |
399 | |
400 | reset = true; |
401 | continue; |
402 | } |
403 | } while (seq_state && (seq_state != SPI_FSI_STATUS_SEQ_STATE_IDLE)); |
404 | |
405 | rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, value: 0ULL); |
406 | if (rc) |
407 | return rc; |
408 | |
409 | rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, value: &clock_cfg); |
410 | if (rc) |
411 | return rc; |
412 | |
413 | if ((clock_cfg & (SPI_FSI_CLOCK_CFG_MM_ENABLE | |
414 | SPI_FSI_CLOCK_CFG_ECC_DISABLE | |
415 | SPI_FSI_CLOCK_CFG_MODE | |
416 | SPI_FSI_CLOCK_CFG_SCK_RECV_DEL | |
417 | SPI_FSI_CLOCK_CFG_SCK_DIV)) != wanted_clock_cfg) |
418 | rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG, |
419 | value: wanted_clock_cfg); |
420 | |
421 | return rc; |
422 | } |
423 | |
424 | static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, |
425 | struct spi_message *mesg) |
426 | { |
427 | int rc; |
428 | u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(spi_get_chipselect(mesg->spi, 0) + 1); |
429 | unsigned int len; |
430 | struct spi_transfer *transfer; |
431 | struct fsi_spi *ctx = spi_controller_get_devdata(ctlr); |
432 | |
433 | rc = fsi_spi_check_mux(fsi: ctx->bridge->fsi, dev: ctx->dev); |
434 | if (rc) |
435 | goto error; |
436 | |
437 | list_for_each_entry(transfer, &mesg->transfers, transfer_list) { |
438 | struct fsi_spi_sequence seq; |
439 | struct spi_transfer *next = NULL; |
440 | |
441 | /* Sequencer must do shift out (tx) first. */ |
442 | if (!transfer->tx_buf || transfer->len > SPI_FSI_MAX_TX_SIZE) { |
443 | rc = -EINVAL; |
444 | goto error; |
445 | } |
446 | |
447 | dev_dbg(ctx->dev, "Start tx of %d bytes.\n" , transfer->len); |
448 | |
449 | rc = fsi_spi_transfer_init(ctx); |
450 | if (rc < 0) |
451 | goto error; |
452 | |
453 | fsi_spi_sequence_init(seq: &seq); |
454 | fsi_spi_sequence_add(seq: &seq, val: seq_slave); |
455 | |
456 | len = transfer->len; |
457 | while (len > 8) { |
458 | fsi_spi_sequence_add(seq: &seq, |
459 | SPI_FSI_SEQUENCE_SHIFT_OUT(8)); |
460 | len -= 8; |
461 | } |
462 | fsi_spi_sequence_add(seq: &seq, SPI_FSI_SEQUENCE_SHIFT_OUT(len)); |
463 | |
464 | if (!list_is_last(list: &transfer->transfer_list, |
465 | head: &mesg->transfers)) { |
466 | next = list_next_entry(transfer, transfer_list); |
467 | |
468 | /* Sequencer can only do shift in (rx) after tx. */ |
469 | if (next->rx_buf) { |
470 | u8 shift; |
471 | |
472 | if (next->len > SPI_FSI_MAX_RX_SIZE) { |
473 | rc = -EINVAL; |
474 | goto error; |
475 | } |
476 | |
477 | dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n" , |
478 | next->len); |
479 | |
480 | shift = SPI_FSI_SEQUENCE_SHIFT_IN(next->len); |
481 | fsi_spi_sequence_add(seq: &seq, val: shift); |
482 | } else { |
483 | next = NULL; |
484 | } |
485 | } |
486 | |
487 | fsi_spi_sequence_add(seq: &seq, SPI_FSI_SEQUENCE_SEL_SLAVE(0)); |
488 | |
489 | rc = fsi_spi_write_reg(ctx, SPI_FSI_SEQUENCE, value: seq.data); |
490 | if (rc) |
491 | goto error; |
492 | |
493 | rc = fsi_spi_transfer_data(ctx, transfer); |
494 | if (rc) |
495 | goto error; |
496 | |
497 | if (next) { |
498 | rc = fsi_spi_transfer_data(ctx, transfer: next); |
499 | if (rc) |
500 | goto error; |
501 | |
502 | transfer = next; |
503 | } |
504 | } |
505 | |
506 | error: |
507 | mesg->status = rc; |
508 | spi_finalize_current_message(ctlr); |
509 | |
510 | return rc; |
511 | } |
512 | |
513 | static size_t fsi_spi_max_transfer_size(struct spi_device *spi) |
514 | { |
515 | return SPI_FSI_MAX_RX_SIZE; |
516 | } |
517 | |
518 | static int fsi_spi_probe(struct device *dev) |
519 | { |
520 | int rc; |
521 | struct device_node *np; |
522 | int num_controllers_registered = 0; |
523 | struct fsi2spi *bridge; |
524 | struct fsi_device *fsi = to_fsi_dev(dev); |
525 | |
526 | rc = fsi_spi_check_mux(fsi, dev); |
527 | if (rc) |
528 | return -ENODEV; |
529 | |
530 | bridge = devm_kzalloc(dev, size: sizeof(*bridge), GFP_KERNEL); |
531 | if (!bridge) |
532 | return -ENOMEM; |
533 | |
534 | bridge->fsi = fsi; |
535 | mutex_init(&bridge->lock); |
536 | |
537 | for_each_available_child_of_node(dev->of_node, np) { |
538 | u32 base; |
539 | struct fsi_spi *ctx; |
540 | struct spi_controller *ctlr; |
541 | |
542 | if (of_property_read_u32(np, propname: "reg" , out_value: &base)) |
543 | continue; |
544 | |
545 | ctlr = spi_alloc_host(dev, size: sizeof(*ctx)); |
546 | if (!ctlr) { |
547 | of_node_put(node: np); |
548 | break; |
549 | } |
550 | |
551 | ctlr->dev.of_node = np; |
552 | ctlr->num_chipselect = of_get_available_child_count(np) ?: 1; |
553 | ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; |
554 | ctlr->max_transfer_size = fsi_spi_max_transfer_size; |
555 | ctlr->transfer_one_message = fsi_spi_transfer_one_message; |
556 | |
557 | ctx = spi_controller_get_devdata(ctlr); |
558 | ctx->dev = &ctlr->dev; |
559 | ctx->bridge = bridge; |
560 | ctx->base = base + SPI_FSI_BASE; |
561 | |
562 | rc = devm_spi_register_controller(dev, ctlr); |
563 | if (rc) |
564 | spi_controller_put(ctlr); |
565 | else |
566 | num_controllers_registered++; |
567 | } |
568 | |
569 | if (!num_controllers_registered) |
570 | return -ENODEV; |
571 | |
572 | return 0; |
573 | } |
574 | |
575 | static const struct fsi_device_id fsi_spi_ids[] = { |
576 | { FSI_ENGID_SPI, FSI_VERSION_ANY }, |
577 | { } |
578 | }; |
579 | MODULE_DEVICE_TABLE(fsi, fsi_spi_ids); |
580 | |
581 | static struct fsi_driver fsi_spi_driver = { |
582 | .id_table = fsi_spi_ids, |
583 | .drv = { |
584 | .name = "spi-fsi" , |
585 | .bus = &fsi_bus_type, |
586 | .probe = fsi_spi_probe, |
587 | }, |
588 | }; |
589 | module_fsi_driver(fsi_spi_driver); |
590 | |
591 | MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>" ); |
592 | MODULE_DESCRIPTION("FSI attached SPI controller" ); |
593 | MODULE_LICENSE("GPL" ); |
594 | |