@@ -562,6 +562,36 @@ void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
562
562
}
563
563
EXPORT_SYMBOL_GPL (spi_mem_adjust_op_freq );
564
564
565
+ /**
566
+ * spi_mem_calc_op_duration() - Derives the theoretical length (in ns) of an
567
+ * operation. This helps finding the best variant
568
+ * among a list of possible choices.
569
+ * @op: the operation to benchmark
570
+ *
571
+ * Some chips have per-op frequency limitations, PCBs usually have their own
572
+ * limitations as well, and controllers can support dual, quad or even octal
573
+ * modes, sometimes in DTR. All these combinations make it impossible to
574
+ * statically list the best combination for all situations. If we want something
575
+ * accurate, all these combinations should be rated (eg. with a time estimate)
576
+ * and the best pick should be taken based on these calculations.
577
+ *
578
+ * Returns a ns estimate for the time this op would take.
579
+ */
580
+ u64 spi_mem_calc_op_duration (struct spi_mem_op * op )
581
+ {
582
+ u64 ncycles = 0 ;
583
+ u32 ns_per_cycles ;
584
+
585
+ ns_per_cycles = 1000000000 / op -> max_freq ;
586
+ ncycles += ((op -> cmd .nbytes * 8 ) / op -> cmd .buswidth ) / (op -> cmd .dtr ? 2 : 1 );
587
+ ncycles += ((op -> addr .nbytes * 8 ) / op -> addr .buswidth ) / (op -> addr .dtr ? 2 : 1 );
588
+ ncycles += ((op -> dummy .nbytes * 8 ) / op -> dummy .buswidth ) / (op -> dummy .dtr ? 2 : 1 );
589
+ ncycles += ((op -> data .nbytes * 8 ) / op -> data .buswidth ) / (op -> data .dtr ? 2 : 1 );
590
+
591
+ return ncycles * ns_per_cycles ;
592
+ }
593
+ EXPORT_SYMBOL_GPL (spi_mem_calc_op_duration );
594
+
565
595
static ssize_t spi_mem_no_dirmap_read (struct spi_mem_dirmap_desc * desc ,
566
596
u64 offs , size_t len , void * buf )
567
597
{
0 commit comments