1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3 * Copyright (c) 2023 Rockchip Electronics Co., Ltd.
4 */
5
6 #include <linux/delay.h>
7 #include <linux/gpio.h>
8 #include <linux/interrupt.h>
9 #include <linux/iopoll.h>
10 #include <linux/miscdevice.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/of_gpio.h>
14 #include <linux/platform_device.h>
15 #include <linux/random.h>
16 #include <linux/slab.h>
17 #include <linux/spi/spi.h>
18
19 #include <linux/platform_data/spi-rockchip.h>
20
21 #define SPI_OBJ_MAX_XFER_SIZE 0x1040
22 #define SPI_OBJ_APP_RAM_SIZE 0x10000
23
24 #define SPI_OBJ_CTRL_MSG_SIZE 0x8
25 #define SPI_OBJ_CTRL_CMD_INIT 0x99
26 #define SPI_OBJ_CTRL_CMD_READ 0x3A
27 #define SPI_OBJ_CTRL_CMD_WRITE 0x4B
28 #define SPI_OBJ_CTRL_CMD_DUPLEX 0x5C
29
30 #define SPI_OBJ_DEFAULT_TIMEOUT_US 100000
31
32 struct spi_obj_ctrl {
33 u16 cmd;
34 u16 addr;
35 u32 data;
36 };
37
38 struct spidev_rkmst_data {
39 struct device *dev;
40 struct spi_device *spi;
41 char *ctrlbuf;
42 char *rxbuf;
43 char *txbuf;
44 struct gpio_desc *ready;
45 int ready_irqnum;
46 bool ready_status;
47 bool verbose;
48 struct miscdevice misc_dev;
49 };
50
51 static u32 bit_per_word = 8;
52
spidev_mst_slave_ready_status(struct spidev_rkmst_data * spidev,bool status)53 static inline void spidev_mst_slave_ready_status(struct spidev_rkmst_data *spidev, bool status)
54 {
55 spidev->ready_status = status;
56 }
57
spidev_mst_slave_ready_interrupt(int irq,void * arg)58 static irqreturn_t spidev_mst_slave_ready_interrupt(int irq, void *arg)
59 {
60 struct spidev_rkmst_data *spidev = (struct spidev_rkmst_data *)arg;
61
62 spidev_mst_slave_ready_status(spidev, true);
63
64 return IRQ_HANDLED;
65 }
66
spidev_mst_check_slave_ready(struct spidev_rkmst_data * spidev)67 static bool spidev_mst_check_slave_ready(struct spidev_rkmst_data *spidev)
68 {
69 return spidev->ready_status;
70 }
71
spidev_mst_wait_for_slave_ready(struct spidev_rkmst_data * spidev,u32 timeout_us)72 static int spidev_mst_wait_for_slave_ready(struct spidev_rkmst_data *spidev,
73 u32 timeout_us)
74 {
75 bool ready;
76 int ret;
77
78 ret = read_poll_timeout(spidev_mst_check_slave_ready, ready,
79 ready, 100, timeout_us + 100, false, spidev);
80 if (ret) {
81 dev_err(&spidev->spi->dev, "timeout and reset slave\n");
82
83 return -ETIMEDOUT;
84 }
85
86 return true;
87 }
88
spidev_mst_write(struct spidev_rkmst_data * spidev,const void * txbuf,size_t n)89 static int spidev_mst_write(struct spidev_rkmst_data *spidev, const void *txbuf, size_t n)
90 {
91 struct spi_device *spi = spidev->spi;
92 struct spi_transfer t = {
93 .tx_buf = txbuf,
94 .len = n,
95 .bits_per_word = bit_per_word,
96 };
97 struct spi_message m;
98 int ret;
99
100 spi_message_init(&m);
101 spi_message_add_tail(&t, &m);
102
103 ret = spidev_mst_wait_for_slave_ready(spidev, SPI_OBJ_DEFAULT_TIMEOUT_US);
104 if (ret < 0)
105 return ret;
106
107 spidev_mst_slave_ready_status(spidev, false);
108 ret = spi_sync(spi, &m);
109
110 return ret;
111 }
112
spidev_mst_write_bypass(struct spidev_rkmst_data * spidev,const void * txbuf,size_t n)113 static int spidev_mst_write_bypass(struct spidev_rkmst_data *spidev, const void *txbuf, size_t n)
114 {
115 struct spi_device *spi = spidev->spi;
116 struct spi_transfer t = {
117 .tx_buf = txbuf,
118 .len = n,
119 .bits_per_word = bit_per_word,
120 };
121 struct spi_message m;
122 int ret;
123
124 spi_message_init(&m);
125 spi_message_add_tail(&t, &m);
126
127 ret = spi_sync(spi, &m);
128
129 return ret;
130 }
131
spidev_mst_read(struct spidev_rkmst_data * spidev,void * rxbuf,size_t n)132 static int spidev_mst_read(struct spidev_rkmst_data *spidev, void *rxbuf, size_t n)
133 {
134 struct spi_device *spi = spidev->spi;
135 struct spi_transfer t = {
136 .rx_buf = rxbuf,
137 .len = n,
138 .bits_per_word = bit_per_word,
139 };
140 struct spi_message m;
141 int ret;
142
143 spi_message_init(&m);
144 spi_message_add_tail(&t, &m);
145
146 ret = spidev_mst_wait_for_slave_ready(spidev, SPI_OBJ_MAX_XFER_SIZE);
147 if (ret < 0)
148 return ret;
149
150 spidev_mst_slave_ready_status(spidev, false);
151 ret = spi_sync(spi, &m);
152
153 return ret;
154 }
155
spidev_slv_write_and_read(struct spidev_rkmst_data * spidev,const void * tx_buf,void * rx_buf,size_t len)156 static int spidev_slv_write_and_read(struct spidev_rkmst_data *spidev,
157 const void *tx_buf, void *rx_buf,
158 size_t len)
159 {
160 struct spi_device *spi = spidev->spi;
161 struct spi_transfer t = {
162 .tx_buf = tx_buf,
163 .rx_buf = rx_buf,
164 .len = len,
165 };
166 struct spi_message m;
167 int ret;
168
169 spi_message_init(&m);
170 spi_message_add_tail(&t, &m);
171
172 ret = spidev_mst_wait_for_slave_ready(spidev, SPI_OBJ_MAX_XFER_SIZE);
173 if (ret < 0)
174 return ret;
175
176 spidev_mst_slave_ready_status(spidev, false);
177 ret = spi_sync(spi, &m);
178
179 return ret;
180 }
181
spidev_rkmst_reset_slave(struct spidev_rkmst_data * spidev)182 static void spidev_rkmst_reset_slave(struct spidev_rkmst_data *spidev)
183 {
184 struct spi_obj_ctrl *ctrl = (struct spi_obj_ctrl *)spidev->ctrlbuf;
185
186 ctrl->cmd = SPI_OBJ_CTRL_CMD_INIT;
187
188 spidev_mst_write_bypass(spidev, ctrl, SPI_OBJ_MAX_XFER_SIZE);
189 msleep(100);
190 spidev_mst_write_bypass(spidev, ctrl, SPI_OBJ_MAX_XFER_SIZE);
191 }
192
193
spidev_rkmst_ctrl(struct spidev_rkmst_data * spidev,u32 cmd,u16 addr,u32 data)194 static int spidev_rkmst_ctrl(struct spidev_rkmst_data *spidev, u32 cmd, u16 addr, u32 data)
195 {
196 struct spi_obj_ctrl *ctrl = (struct spi_obj_ctrl *)spidev->ctrlbuf;
197 struct spi_device *spi = spidev->spi;
198 int ret;
199
200 if (spidev->verbose)
201 dev_err(&spi->dev, "ctrl cmd=%x addr=0x%x data=0x%x\n", cmd, addr, data);
202
203 /* ctrl_xfer */
204 ctrl->cmd = cmd;
205 ctrl->addr = addr;
206 ctrl->data = data;
207 ret = spidev_mst_write(spidev, ctrl, SPI_OBJ_CTRL_MSG_SIZE);
208 if (ret) {
209 dev_err(&spi->dev, "ctrl cmd=%x addr=0x%x data=0x%x, ret=%d\n", cmd, addr, data, ret);
210 return -EIO;
211 }
212
213 return 0;
214 }
215
spidev_rkmst_xfer(struct spidev_rkmst_data * spidev,void * tx,void * rx,u16 addr,u32 len)216 static int spidev_rkmst_xfer(struct spidev_rkmst_data *spidev, void *tx,
217 void *rx, u16 addr, u32 len)
218 {
219 struct spi_device *spi = spidev->spi;
220 int ret;
221 u32 cmd;
222
223 if (tx && rx)
224 cmd = SPI_OBJ_CTRL_CMD_DUPLEX;
225 else if (rx)
226 cmd = SPI_OBJ_CTRL_CMD_READ;
227 else if (tx)
228 cmd = SPI_OBJ_CTRL_CMD_WRITE;
229 else
230 return -EINVAL;
231
232 /* ctrl_xfer */
233 ret = spidev_rkmst_ctrl(spidev, cmd, addr, len);
234 if (ret) {
235 spidev_rkmst_reset_slave(spidev);
236 return -EIO;
237 }
238
239 if (spidev->verbose)
240 dev_err(&spi->dev, "xfer len=0x%x\n", len);
241 /* data_xfer */
242 switch (cmd) {
243 case SPI_OBJ_CTRL_CMD_READ:
244 ret = spidev_mst_read(spidev, rx, len);
245 if (ret)
246 goto err_out;
247 break;
248 case SPI_OBJ_CTRL_CMD_WRITE:
249 ret = spidev_mst_write(spidev, tx, len);
250 if (ret)
251 goto err_out;
252 break;
253 case SPI_OBJ_CTRL_CMD_DUPLEX:
254 ret = spidev_slv_write_and_read(spidev, tx, rx, len);
255 if (ret)
256 goto err_out;
257 break;
258 default:
259 dev_err(&spi->dev, "%s unknown\n", __func__);
260 }
261
262 return 0;
263 err_out:
264 dev_err(&spi->dev, "xfer cmd=%x addr=0x%x len=0x%x, ret=%d\n",
265 cmd, addr, len, ret);
266
267 return ret;
268 }
269
spidev_rkmst_misc_write(struct file * filp,const char __user * buf,size_t n,loff_t * offset)270 static ssize_t spidev_rkmst_misc_write(struct file *filp, const char __user *buf,
271 size_t n, loff_t *offset)
272 {
273 struct spidev_rkmst_data *spidev;
274 struct spi_device *spi;
275 int argc = 0, i;
276 char tmp[64];
277 char *argv[16];
278 char *cmd, *data;
279
280 if (n >= 64)
281 return -EINVAL;
282
283 spidev = filp->private_data;
284
285 if (!spidev)
286 return -ESHUTDOWN;
287
288 spi = spidev->spi;
289 memset(tmp, 0, sizeof(tmp));
290 if (copy_from_user(tmp, buf, n))
291 return -EFAULT;
292 cmd = tmp;
293 data = tmp;
294
295 while (data < (tmp + n)) {
296 data = strstr(data, " ");
297 if (!data)
298 break;
299 *data = 0;
300 argv[argc] = ++data;
301 argc++;
302 if (argc >= 16)
303 break;
304 }
305
306 tmp[n - 1] = 0;
307
308 if (!strcmp(cmd, "verbose")) {
309 int val;
310
311 if (argc < 1)
312 return -EINVAL;
313
314 if (kstrtoint(argv[0], 0, &val))
315 return -EINVAL;
316
317 if (val == 1)
318 spidev->verbose = true;
319 else
320 spidev->verbose = false;
321 } else if (!strcmp(cmd, "init")) {
322 spidev_rkmst_ctrl(spidev, SPI_OBJ_CTRL_CMD_INIT, 0x55AA, 0x1234567);
323 } else if (!strcmp(cmd, "read")) {
324 int addr, len;
325
326 if (argc < 2)
327 return -EINVAL;
328
329 if (kstrtoint(argv[0], 0, &addr))
330 return -EINVAL;
331 if (kstrtoint(argv[1], 0, &len))
332 return -EINVAL;
333
334 if (!len) {
335 dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
336 return -EINVAL;
337 }
338
339 if (addr + len > SPI_OBJ_APP_RAM_SIZE) {
340 dev_err(&spi->dev, "rxbuf print out of size\n");
341 return -EINVAL;
342 }
343
344 spidev_rkmst_xfer(spidev, NULL, spidev->rxbuf, addr, len);
345
346 print_hex_dump(KERN_ERR, "m-r: ",
347 DUMP_PREFIX_OFFSET,
348 16,
349 1,
350 spidev->rxbuf,
351 len,
352 1);
353 } else if (!strcmp(cmd, "write")) {
354 int addr, len;
355
356 if (argc < 2)
357 return -EINVAL;
358
359 if (kstrtoint(argv[0], 0, &addr))
360 return -EINVAL;
361 if (kstrtoint(argv[1], 0, &len))
362 return -EINVAL;
363
364 if (!len) {
365 dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
366 return -EINVAL;
367 }
368
369 if (addr + len > SPI_OBJ_APP_RAM_SIZE) {
370 dev_err(&spi->dev, "rxbuf print out of size\n");
371 return -EINVAL;
372 }
373
374 for (i = 0; i < len; i++)
375 spidev->txbuf[i] = i & 0xFF;
376 ((u32 *)spidev->txbuf)[0] = addr;
377
378 spidev_rkmst_xfer(spidev, spidev->txbuf, NULL, addr, len);
379 } else if (!strcmp(cmd, "duplex")) {
380 int addr, len;
381
382 if (argc < 2)
383 return -EINVAL;
384
385 if (kstrtoint(argv[0], 0, &addr))
386 return -EINVAL;
387 if (kstrtoint(argv[1], 0, &len))
388 return -EINVAL;
389
390 if (!len) {
391 dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
392 return -EINVAL;
393 }
394
395 if (addr + len > SPI_OBJ_APP_RAM_SIZE) {
396 dev_err(&spi->dev, "rxbuf print out of size\n");
397 return -EINVAL;
398 }
399
400 for (i = 0; i < len; i++)
401 spidev->txbuf[i] = i & 0xFF;
402 ((u32 *)spidev->txbuf)[0] = addr;
403
404 spidev_rkmst_xfer(spidev, spidev->txbuf, spidev->rxbuf, addr, len);
405
406 print_hex_dump(KERN_ERR, "m-d: ",
407 DUMP_PREFIX_OFFSET,
408 16,
409 1,
410 spidev->rxbuf,
411 len,
412 1);
413 } else if (!strcmp(cmd, "autotest")) {
414 int addr = 0, len, loops, i;
415 unsigned long long bytes = 0;
416 unsigned long us = 0;
417 ktime_t start_time;
418 ktime_t end_time;
419 ktime_t cost_time;
420 char *tempbuf;
421
422 if (argc < 2)
423 return -EINVAL;
424
425 if (kstrtoint(argv[0], 0, &len))
426 return -EINVAL;
427
428 if (kstrtoint(argv[1], 0, &loops))
429 return -EINVAL;
430
431 if (!len) {
432 dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
433 return -EINVAL;
434 }
435
436 if (len > SPI_OBJ_APP_RAM_SIZE) {
437 dev_err(&spi->dev, "rxbuf print out of size\n");
438 return -EINVAL;
439 }
440
441 tempbuf = kzalloc(len, GFP_KERNEL);
442 if (!tempbuf)
443 return -ENOMEM;
444
445 prandom_bytes(tempbuf, len);
446 spidev_rkmst_xfer(spidev, tempbuf, NULL, addr, len);
447 start_time = ktime_get();
448 for (i = 0; i < loops; i++) {
449 prandom_bytes(spidev->txbuf, len);
450 spidev_rkmst_xfer(spidev, spidev->txbuf, spidev->rxbuf, addr, len);
451 if (memcmp(spidev->rxbuf, tempbuf, len)) {
452 dev_err(&spi->dev, "dulplex autotest failed, loops=%d\n", i);
453 print_hex_dump(KERN_ERR, "m-d-t: ",
454 DUMP_PREFIX_OFFSET,
455 16,
456 1,
457 spidev->txbuf,
458 len,
459 1);
460 print_hex_dump(KERN_ERR, "m-d-r: ",
461 DUMP_PREFIX_OFFSET,
462 16,
463 1,
464 spidev->rxbuf,
465 len,
466 1);
467 print_hex_dump(KERN_ERR, "m-d-c: ",
468 DUMP_PREFIX_OFFSET,
469 16,
470 1,
471 tempbuf,
472 len,
473 1);
474 break;
475 }
476 memcpy(tempbuf, spidev->txbuf, len);
477 }
478 end_time = ktime_get();
479 cost_time = ktime_sub(end_time, start_time);
480 us = ktime_to_us(cost_time);
481
482 bytes = (u64)len * (u64)loops * 1000;
483 do_div(bytes, us);
484 if (i >= loops)
485 dev_err(&spi->dev, "dulplex test pass, cost=%ldus, speed=%lldKB/S, %ldus/loops\n",
486 us, bytes, us / loops);
487
488 start_time = ktime_get();
489 for (i = 0; i < loops; i++) {
490 prandom_bytes(spidev->txbuf, len);
491 spidev_rkmst_xfer(spidev, spidev->txbuf, NULL, addr, len);
492 spidev_rkmst_xfer(spidev, NULL, spidev->rxbuf, addr, len);
493 if (memcmp(spidev->rxbuf, spidev->txbuf, len)) {
494 dev_err(&spi->dev, "read/write autotest failed, loops=%d\n", i);
495 print_hex_dump(KERN_ERR, "m-d-t: ",
496 DUMP_PREFIX_OFFSET,
497 16,
498 1,
499 spidev->txbuf,
500 len,
501 1);
502 print_hex_dump(KERN_ERR, "m-d-r: ",
503 DUMP_PREFIX_OFFSET,
504 16,
505 1,
506 spidev->rxbuf,
507 len,
508 1);
509 break;
510 }
511 }
512 end_time = ktime_get();
513 cost_time = ktime_sub(end_time, start_time);
514 us = ktime_to_us(cost_time);
515
516 bytes = (u64)len * (u64)loops * 2 * 1000; /* multi 2 for both write and read */
517 do_div(bytes, us);
518 if (i >= loops)
519 dev_err(&spi->dev, "read/write test pass, cost=%ldus, speed=%lldKB/S, %ldus/loops\n",
520 us, bytes, us / loops);
521 kfree(tempbuf);
522 } else {
523 dev_err(&spi->dev, "unknown command\n");
524 }
525
526 return n;
527 }
528
spidev_rkmst_misc_open(struct inode * inode,struct file * filp)529 static int spidev_rkmst_misc_open(struct inode *inode, struct file *filp)
530 {
531 struct miscdevice *miscdev = filp->private_data;
532 struct spidev_rkmst_data *spidev;
533
534 spidev = container_of(miscdev, struct spidev_rkmst_data, misc_dev);
535 filp->private_data = spidev;
536
537 return 0;
538 }
539
540 static const struct file_operations spidev_rkmst_misc_fops = {
541 .write = spidev_rkmst_misc_write,
542 .open = spidev_rkmst_misc_open,
543 };
544
spidev_rkmst_probe(struct spi_device * spi)545 static int spidev_rkmst_probe(struct spi_device *spi)
546 {
547 struct spidev_rkmst_data *spidev = NULL;
548 int ret;
549
550 if (!spi)
551 return -ENOMEM;
552
553 spidev = devm_kzalloc(&spi->dev, sizeof(struct spidev_rkmst_data), GFP_KERNEL);
554 if (!spidev)
555 return -ENOMEM;
556
557 spidev->ctrlbuf = devm_kzalloc(&spi->dev, SPI_OBJ_MAX_XFER_SIZE, GFP_KERNEL);
558 if (!spidev->ctrlbuf)
559 return -ENOMEM;
560
561 spidev->rxbuf = devm_kzalloc(&spi->dev, SPI_OBJ_APP_RAM_SIZE, GFP_KERNEL | GFP_DMA);
562 if (!spidev->rxbuf)
563 return -ENOMEM;
564
565 spidev->txbuf = devm_kzalloc(&spi->dev, SPI_OBJ_MAX_XFER_SIZE, GFP_KERNEL);
566 if (!spidev->txbuf)
567 return -ENOMEM;
568
569 spidev->spi = spi;
570 spidev->dev = &spi->dev;
571
572 spidev_mst_slave_ready_status(spidev, false);
573 spidev->ready = devm_gpiod_get_optional(&spi->dev, "ready", GPIOD_IN);
574 if (IS_ERR(spidev->ready))
575 return dev_err_probe(&spi->dev, PTR_ERR(spidev->ready),
576 "invalid ready-gpios property in node\n");
577
578 spidev->ready_irqnum = gpiod_to_irq(spidev->ready);
579 ret = devm_request_irq(&spi->dev, spidev->ready_irqnum, spidev_mst_slave_ready_interrupt,
580 IRQF_TRIGGER_FALLING, "spidev-mst-ready-in", spidev);
581 if (ret < 0) {
582 dev_err(&spi->dev, "request ready irq failed\n");
583 return ret;
584 }
585 dev_set_drvdata(&spi->dev, spidev);
586
587 dev_err(&spi->dev, "mode=%d, max_speed_hz=%d\n", spi->mode, spi->max_speed_hz);
588
589 spidev->misc_dev.minor = MISC_DYNAMIC_MINOR;
590 spidev->misc_dev.name = "spidev_rkmst_misc";
591 spidev->misc_dev.fops = &spidev_rkmst_misc_fops;
592 spidev->misc_dev.parent = &spi->dev;
593 ret = misc_register(&spidev->misc_dev);
594 if (ret) {
595 dev_err(&spi->dev, "fail to register misc device\n");
596 return ret;
597 }
598
599 spidev_rkmst_reset_slave(spidev);
600
601 return 0;
602 }
603
spidev_rkmst_remove(struct spi_device * spi)604 static int spidev_rkmst_remove(struct spi_device *spi)
605 {
606 struct spidev_rkmst_data *spidev = dev_get_drvdata(&spi->dev);
607
608 misc_deregister(&spidev->misc_dev);
609
610 return 0;
611 }
612
613 #ifdef CONFIG_OF
614 static const struct of_device_id spidev_rkmst_dt_match[] = {
615 { .compatible = "rockchip,spi-obj-master", },
616 {},
617 };
618 MODULE_DEVICE_TABLE(of, spidev_rkmst_dt_match);
619
620 #endif /* CONFIG_OF */
621
622 static struct spi_driver spidev_rkmst_driver = {
623 .driver = {
624 .name = "spidev_rkmst",
625 .owner = THIS_MODULE,
626 .of_match_table = of_match_ptr(spidev_rkmst_dt_match),
627 },
628 .probe = spidev_rkmst_probe,
629 .remove = spidev_rkmst_remove,
630 };
631 module_spi_driver(spidev_rkmst_driver);
632
633 MODULE_AUTHOR("Jon Lin <jon.lin@rock-chips.com>");
634 MODULE_DESCRIPTION("ROCKCHIP SPI Object Master Driver");
635 MODULE_LICENSE("GPL");
636 MODULE_ALIAS("spi:spidev_rkmst");
637