Commit | Line | Data |
---|---|---|
bbb6b2f9 EJ |
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 | |
9211a441 | 15 | #define FSI_MBOX_ROOT_CTRL_8_SPI_MUX 0xf0000000 |
bbb6b2f9 EJ |
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 | |
40308f96 | 27 | #define SPI_FSI_TIMEOUT_MS 1000 |
34d34a56 EJ |
28 | #define SPI_FSI_MAX_RX_SIZE 8 |
29 | #define SPI_FSI_MAX_TX_SIZE 40 | |
bbb6b2f9 EJ |
30 | |
31 | #define SPI_FSI_ERROR 0x0 | |
32 | #define SPI_FSI_COUNTER_CFG 0x1 | |
bbb6b2f9 EJ |
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 \ | |
7909eebb | 65 | (SPI_FSI_STATUS_ERROR | \ |
bbb6b2f9 EJ |
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 | ||
e954af13 EJ |
70 | struct fsi2spi { |
71 | struct fsi_device *fsi; /* FSI2SPI CFAM engine device */ | |
72 | struct mutex lock; /* lock access to the device */ | |
73 | }; | |
74 | ||
bbb6b2f9 EJ |
75 | struct fsi_spi { |
76 | struct device *dev; /* SPI controller device */ | |
e954af13 | 77 | struct fsi2spi *bridge; /* FSI2SPI device */ |
bbb6b2f9 EJ |
78 | u32 base; |
79 | }; | |
80 | ||
81 | struct fsi_spi_sequence { | |
82 | int bit; | |
83 | u64 data; | |
84 | }; | |
85 | ||
9211a441 EJ |
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(fsi->slave, FSI_MBOX_ROOT_CTRL_8, &root_ctrl_8_be, | |
93 | 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 | ||
bbb6b2f9 EJ |
106 | static int fsi_spi_check_status(struct fsi_spi *ctx) |
107 | { | |
108 | int rc; | |
109 | u32 sts; | |
110 | __be32 sts_be; | |
111 | ||
e954af13 | 112 | rc = fsi_device_read(ctx->bridge->fsi, FSI2SPI_STATUS, &sts_be, |
bbb6b2f9 EJ |
113 | 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 | { | |
e954af13 | 128 | int rc = 0; |
bbb6b2f9 EJ |
129 | __be32 cmd_be; |
130 | __be32 data_be; | |
131 | u32 cmd = offset + ctx->base; | |
e954af13 | 132 | struct fsi2spi *bridge = ctx->bridge; |
bbb6b2f9 EJ |
133 | |
134 | *value = 0ULL; | |
135 | ||
136 | if (cmd & FSI2SPI_CMD_WRITE) | |
137 | return -EINVAL; | |
138 | ||
e954af13 | 139 | rc = mutex_lock_interruptible(&bridge->lock); |
bbb6b2f9 EJ |
140 | if (rc) |
141 | return rc; | |
142 | ||
e954af13 EJ |
143 | cmd_be = cpu_to_be32(cmd); |
144 | rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be, | |
145 | sizeof(cmd_be)); | |
146 | if (rc) | |
147 | goto unlock; | |
148 | ||
bbb6b2f9 EJ |
149 | rc = fsi_spi_check_status(ctx); |
150 | if (rc) | |
e954af13 | 151 | goto unlock; |
bbb6b2f9 | 152 | |
e954af13 | 153 | rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA0, &data_be, |
bbb6b2f9 EJ |
154 | sizeof(data_be)); |
155 | if (rc) | |
e954af13 | 156 | goto unlock; |
bbb6b2f9 EJ |
157 | |
158 | *value |= (u64)be32_to_cpu(data_be) << 32; | |
159 | ||
e954af13 | 160 | rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA1, &data_be, |
bbb6b2f9 EJ |
161 | sizeof(data_be)); |
162 | if (rc) | |
e954af13 | 163 | goto unlock; |
bbb6b2f9 EJ |
164 | |
165 | *value |= (u64)be32_to_cpu(data_be); | |
166 | dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value); | |
167 | ||
e954af13 EJ |
168 | unlock: |
169 | mutex_unlock(&bridge->lock); | |
170 | return rc; | |
bbb6b2f9 EJ |
171 | } |
172 | ||
173 | static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value) | |
174 | { | |
e954af13 | 175 | int rc = 0; |
bbb6b2f9 EJ |
176 | __be32 cmd_be; |
177 | __be32 data_be; | |
178 | u32 cmd = offset + ctx->base; | |
e954af13 | 179 | struct fsi2spi *bridge = ctx->bridge; |
bbb6b2f9 EJ |
180 | |
181 | if (cmd & FSI2SPI_CMD_WRITE) | |
182 | return -EINVAL; | |
183 | ||
e954af13 EJ |
184 | rc = mutex_lock_interruptible(&bridge->lock); |
185 | if (rc) | |
186 | return rc; | |
187 | ||
bbb6b2f9 EJ |
188 | dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value); |
189 | ||
190 | data_be = cpu_to_be32(upper_32_bits(value)); | |
e954af13 | 191 | rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA0, &data_be, |
bbb6b2f9 EJ |
192 | sizeof(data_be)); |
193 | if (rc) | |
e954af13 | 194 | goto unlock; |
bbb6b2f9 EJ |
195 | |
196 | data_be = cpu_to_be32(lower_32_bits(value)); | |
e954af13 | 197 | rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA1, &data_be, |
bbb6b2f9 EJ |
198 | sizeof(data_be)); |
199 | if (rc) | |
e954af13 | 200 | goto unlock; |
bbb6b2f9 EJ |
201 | |
202 | cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE); | |
e954af13 EJ |
203 | rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be, |
204 | sizeof(cmd_be)); | |
bbb6b2f9 | 205 | if (rc) |
e954af13 EJ |
206 | goto unlock; |
207 | ||
208 | rc = fsi_spi_check_status(ctx); | |
bbb6b2f9 | 209 | |
e954af13 EJ |
210 | unlock: |
211 | mutex_unlock(&bridge->lock); | |
212 | return rc; | |
bbb6b2f9 EJ |
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 | ||
49c9fc1d EJ |
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, 0ULL); | |
bbb6b2f9 EJ |
258 | } |
259 | ||
48a78c66 EJ |
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, status); | |
263 | ||
264 | if (rc) | |
265 | return rc; | |
266 | ||
267 | if (*status & SPI_FSI_STATUS_ANY_ERROR) { | |
e954af13 | 268 | dev_err(ctx->dev, "%s error: %016llx\n", dir, *status); |
48a78c66 EJ |
269 | |
270 | rc = fsi_spi_reset(ctx); | |
271 | if (rc) | |
272 | return rc; | |
273 | ||
274 | return -EREMOTEIO; | |
275 | } | |
276 | ||
277 | return 0; | |
278 | } | |
279 | ||
34d34a56 | 280 | static void fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) |
bbb6b2f9 EJ |
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 | |
49c9fc1d EJ |
285 | * the right place. Return the index of the slot we just filled in the |
286 | * sequence register. | |
bbb6b2f9 EJ |
287 | */ |
288 | seq->data |= (u64)val << seq->bit; | |
289 | seq->bit -= 8; | |
bbb6b2f9 EJ |
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 | ||
bbb6b2f9 EJ |
298 | static int fsi_spi_transfer_data(struct fsi_spi *ctx, |
299 | struct spi_transfer *transfer) | |
300 | { | |
40308f96 | 301 | int loops; |
bbb6b2f9 | 302 | int rc = 0; |
89b35e3f | 303 | unsigned long end; |
bbb6b2f9 EJ |
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, &tx[sent], | |
314 | (int)transfer->len - sent); | |
315 | ||
316 | rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, out); | |
317 | if (rc) | |
318 | return rc; | |
319 | ||
40308f96 EJ |
320 | loops = 0; |
321 | end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS); | |
bbb6b2f9 | 322 | do { |
40308f96 | 323 | if (loops++ && time_after(jiffies, end)) |
61bf40ef EJ |
324 | return -ETIMEDOUT; |
325 | ||
48a78c66 | 326 | rc = fsi_spi_status(ctx, &status, "TX"); |
bbb6b2f9 EJ |
327 | if (rc) |
328 | return rc; | |
bbb6b2f9 EJ |
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) { | |
40308f96 EJ |
339 | loops = 0; |
340 | end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS); | |
bbb6b2f9 | 341 | do { |
40308f96 | 342 | if (loops++ && time_after(jiffies, end)) |
61bf40ef EJ |
343 | return -ETIMEDOUT; |
344 | ||
48a78c66 | 345 | rc = fsi_spi_status(ctx, &status, "RX"); |
bbb6b2f9 EJ |
346 | if (rc) |
347 | return rc; | |
bbb6b2f9 EJ |
348 | } while (!(status & SPI_FSI_STATUS_RDR_FULL)); |
349 | ||
350 | rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in); | |
351 | if (rc) | |
352 | return rc; | |
353 | ||
354 | recv += fsi_spi_data_in(in, &rx[recv], | |
355 | (int)transfer->len - recv); | |
356 | } | |
357 | } | |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
362 | static int fsi_spi_transfer_init(struct fsi_spi *ctx) | |
363 | { | |
40308f96 | 364 | int loops = 0; |
bbb6b2f9 EJ |
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 | | |
0b546bbe | 373 | FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19); |
bbb6b2f9 | 374 | |
40308f96 | 375 | end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS); |
bbb6b2f9 | 376 | do { |
40308f96 | 377 | if (loops++ && time_after(jiffies, end)) |
bbb6b2f9 EJ |
378 | return -ETIMEDOUT; |
379 | ||
380 | rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &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)) { | |
48a78c66 EJ |
389 | if (reset) { |
390 | dev_err(ctx->dev, | |
391 | "Initialization error: %08llx\n", | |
392 | status); | |
bbb6b2f9 | 393 | return -EIO; |
48a78c66 | 394 | } |
bbb6b2f9 EJ |
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 | ||
34d34a56 EJ |
405 | rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL); |
406 | if (rc) | |
407 | return rc; | |
408 | ||
bbb6b2f9 EJ |
409 | rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, &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 | 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 | { | |
9211a441 | 427 | int rc; |
9e264f3f | 428 | u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(spi_get_chipselect(mesg->spi, 0) + 1); |
34d34a56 | 429 | unsigned int len; |
bbb6b2f9 EJ |
430 | struct spi_transfer *transfer; |
431 | struct fsi_spi *ctx = spi_controller_get_devdata(ctlr); | |
432 | ||
e954af13 | 433 | rc = fsi_spi_check_mux(ctx->bridge->fsi, ctx->dev); |
9211a441 | 434 | if (rc) |
ee4ad5d0 | 435 | goto error; |
9211a441 | 436 | |
bbb6b2f9 EJ |
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. */ | |
34d34a56 | 442 | if (!transfer->tx_buf || transfer->len > SPI_FSI_MAX_TX_SIZE) { |
bbb6b2f9 EJ |
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); | |
454 | fsi_spi_sequence_add(&seq, seq_slave); | |
455 | ||
34d34a56 EJ |
456 | len = transfer->len; |
457 | while (len > 8) { | |
458 | fsi_spi_sequence_add(&seq, | |
459 | SPI_FSI_SEQUENCE_SHIFT_OUT(8)); | |
460 | len -= 8; | |
461 | } | |
462 | fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SHIFT_OUT(len)); | |
bbb6b2f9 EJ |
463 | |
464 | if (!list_is_last(&transfer->transfer_list, | |
465 | &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) { | |
34d34a56 EJ |
470 | u8 shift; |
471 | ||
472 | if (next->len > SPI_FSI_MAX_RX_SIZE) { | |
bbb6b2f9 EJ |
473 | rc = -EINVAL; |
474 | goto error; | |
475 | } | |
476 | ||
477 | dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n", | |
478 | next->len); | |
479 | ||
34d34a56 EJ |
480 | shift = SPI_FSI_SEQUENCE_SHIFT_IN(next->len); |
481 | fsi_spi_sequence_add(&seq, shift); | |
bbb6b2f9 EJ |
482 | } else { |
483 | next = NULL; | |
484 | } | |
485 | } | |
486 | ||
487 | fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SEL_SLAVE(0)); | |
488 | ||
489 | rc = fsi_spi_write_reg(ctx, SPI_FSI_SEQUENCE, 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, 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 | { | |
34d34a56 | 515 | return SPI_FSI_MAX_RX_SIZE; |
bbb6b2f9 EJ |
516 | } |
517 | ||
518 | static int fsi_spi_probe(struct device *dev) | |
519 | { | |
520 | int rc; | |
bbb6b2f9 EJ |
521 | struct device_node *np; |
522 | int num_controllers_registered = 0; | |
e954af13 | 523 | struct fsi2spi *bridge; |
bbb6b2f9 EJ |
524 | struct fsi_device *fsi = to_fsi_dev(dev); |
525 | ||
9211a441 | 526 | rc = fsi_spi_check_mux(fsi, dev); |
bbb6b2f9 | 527 | if (rc) |
bbb6b2f9 | 528 | return -ENODEV; |
bbb6b2f9 | 529 | |
e954af13 EJ |
530 | bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); |
531 | if (!bridge) | |
532 | return -ENOMEM; | |
533 | ||
534 | bridge->fsi = fsi; | |
535 | mutex_init(&bridge->lock); | |
536 | ||
bbb6b2f9 EJ |
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, "reg", &base)) | |
543 | continue; | |
544 | ||
d40f10d0 | 545 | ctlr = spi_alloc_host(dev, sizeof(*ctx)); |
24b5515a CJ |
546 | if (!ctlr) { |
547 | of_node_put(np); | |
bbb6b2f9 | 548 | break; |
24b5515a | 549 | } |
bbb6b2f9 EJ |
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; | |
e954af13 | 559 | ctx->bridge = bridge; |
bbb6b2f9 EJ |
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"); |