summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-mem.c')
-rw-r--r--drivers/spi/spi-mem.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 7916e655afc8..b12a7974b665 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -432,6 +432,210 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
432} 432}
433EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); 433EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
434 434
435static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
436 u64 offs, size_t len, void *buf)
437{
438 struct spi_mem_op op = desc->info.op_tmpl;
439 int ret;
440
441 op.addr.val = desc->info.offset + offs;
442 op.data.buf.in = buf;
443 op.data.nbytes = len;
444 ret = spi_mem_adjust_op_size(desc->mem, &op);
445 if (ret)
446 return ret;
447
448 ret = spi_mem_exec_op(desc->mem, &op);
449 if (ret)
450 return ret;
451
452 return op.data.nbytes;
453}
454
455static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc,
456 u64 offs, size_t len, const void *buf)
457{
458 struct spi_mem_op op = desc->info.op_tmpl;
459 int ret;
460
461 op.addr.val = desc->info.offset + offs;
462 op.data.buf.out = buf;
463 op.data.nbytes = len;
464 ret = spi_mem_adjust_op_size(desc->mem, &op);
465 if (ret)
466 return ret;
467
468 ret = spi_mem_exec_op(desc->mem, &op);
469 if (ret)
470 return ret;
471
472 return op.data.nbytes;
473}
474
475/**
476 * spi_mem_dirmap_create() - Create a direct mapping descriptor
477 * @mem: SPI mem device this direct mapping should be created for
478 * @info: direct mapping information
479 *
480 * This function is creating a direct mapping descriptor which can then be used
481 * to access the memory using spi_mem_dirmap_read() or spi_mem_dirmap_write().
482 * If the SPI controller driver does not support direct mapping, this function
483 * fallback to an implementation using spi_mem_exec_op(), so that the caller
484 * doesn't have to bother implementing a fallback on his own.
485 *
486 * Return: a valid pointer in case of success, and ERR_PTR() otherwise.
487 */
488struct spi_mem_dirmap_desc *
489spi_mem_dirmap_create(struct spi_mem *mem,
490 const struct spi_mem_dirmap_info *info)
491{
492 struct spi_controller *ctlr = mem->spi->controller;
493 struct spi_mem_dirmap_desc *desc;
494 int ret = -ENOTSUPP;
495
496 /* Make sure the number of address cycles is between 1 and 8 bytes. */
497 if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8)
498 return ERR_PTR(-EINVAL);
499
500 /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */
501 if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA)
502 return ERR_PTR(-EINVAL);
503
504 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
505 if (!desc)
506 return ERR_PTR(-ENOMEM);
507
508 desc->mem = mem;
509 desc->info = *info;
510 if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create)
511 ret = ctlr->mem_ops->dirmap_create(desc);
512
513 if (ret) {
514 desc->nodirmap = true;
515 if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
516 ret = -ENOTSUPP;
517 else
518 ret = 0;
519 }
520
521 if (ret) {
522 kfree(desc);
523 return ERR_PTR(ret);
524 }
525
526 return desc;
527}
528EXPORT_SYMBOL_GPL(spi_mem_dirmap_create);
529
530/**
531 * spi_mem_dirmap_destroy() - Destroy a direct mapping descriptor
532 * @desc: the direct mapping descriptor to destroy
533 * @info: direct mapping information
534 *
535 * This function destroys a direct mapping descriptor previously created by
536 * spi_mem_dirmap_create().
537 */
538void spi_mem_dirmap_destroy(struct spi_mem_dirmap_desc *desc)
539{
540 struct spi_controller *ctlr = desc->mem->spi->controller;
541
542 if (!desc->nodirmap && ctlr->mem_ops && ctlr->mem_ops->dirmap_destroy)
543 ctlr->mem_ops->dirmap_destroy(desc);
544}
545EXPORT_SYMBOL_GPL(spi_mem_dirmap_destroy);
546
547/**
548 * spi_mem_dirmap_dirmap_read() - Read data through a direct mapping
549 * @desc: direct mapping descriptor
550 * @offs: offset to start reading from. Note that this is not an absolute
551 * offset, but the offset within the direct mapping which already has
552 * its own offset
553 * @len: length in bytes
554 * @buf: destination buffer. This buffer must be DMA-able
555 *
556 * This function reads data from a memory device using a direct mapping
557 * previously instantiated with spi_mem_dirmap_create().
558 *
559 * Return: the amount of data read from the memory device or a negative error
560 * code. Note that the returned size might be smaller than @len, and the caller
561 * is responsible for calling spi_mem_dirmap_read() again when that happens.
562 */
563ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
564 u64 offs, size_t len, void *buf)
565{
566 struct spi_controller *ctlr = desc->mem->spi->controller;
567 ssize_t ret;
568
569 if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
570 return -EINVAL;
571
572 if (!len)
573 return 0;
574
575 if (desc->nodirmap) {
576 ret = spi_mem_no_dirmap_read(desc, offs, len, buf);
577 } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_read) {
578 ret = spi_mem_access_start(desc->mem);
579 if (ret)
580 return ret;
581
582 ret = ctlr->mem_ops->dirmap_read(desc, offs, len, buf);
583
584 spi_mem_access_end(desc->mem);
585 } else {
586 ret = -ENOTSUPP;
587 }
588
589 return ret;
590}
591EXPORT_SYMBOL_GPL(spi_mem_dirmap_read);
592
593/**
594 * spi_mem_dirmap_dirmap_write() - Write data through a direct mapping
595 * @desc: direct mapping descriptor
596 * @offs: offset to start writing from. Note that this is not an absolute
597 * offset, but the offset within the direct mapping which already has
598 * its own offset
599 * @len: length in bytes
600 * @buf: source buffer. This buffer must be DMA-able
601 *
602 * This function writes data to a memory device using a direct mapping
603 * previously instantiated with spi_mem_dirmap_create().
604 *
605 * Return: the amount of data written to the memory device or a negative error
606 * code. Note that the returned size might be smaller than @len, and the caller
607 * is responsible for calling spi_mem_dirmap_write() again when that happens.
608 */
609ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
610 u64 offs, size_t len, const void *buf)
611{
612 struct spi_controller *ctlr = desc->mem->spi->controller;
613 ssize_t ret;
614
615 if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_OUT)
616 return -EINVAL;
617
618 if (!len)
619 return 0;
620
621 if (desc->nodirmap) {
622 ret = spi_mem_no_dirmap_write(desc, offs, len, buf);
623 } else if (ctlr->mem_ops && ctlr->mem_ops->dirmap_write) {
624 ret = spi_mem_access_start(desc->mem);
625 if (ret)
626 return ret;
627
628 ret = ctlr->mem_ops->dirmap_write(desc, offs, len, buf);
629
630 spi_mem_access_end(desc->mem);
631 } else {
632 ret = -ENOTSUPP;
633 }
634
635 return ret;
636}
637EXPORT_SYMBOL_GPL(spi_mem_dirmap_write);
638
435static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) 639static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
436{ 640{
437 return container_of(drv, struct spi_mem_driver, spidrv.driver); 641 return container_of(drv, struct spi_mem_driver, spidrv.driver);