aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/spi/spi-mem.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-07-31 13:43:02 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-07-31 13:43:02 -0700
commitcbbf0a759ff96c80dfc32192a2cc427b79447f74 (patch)
treea2d1c6fef1c0347581e9f537ff18485a8f65e68c /drivers/spi/spi-mem.c
parentMerge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux (diff)
parentMerge tag 'nand/for-6.17' into mtd/next (diff)
downloadwireguard-linux-cbbf0a759ff96c80dfc32192a2cc427b79447f74.tar.xz
wireguard-linux-cbbf0a759ff96c80dfc32192a2cc427b79447f74.zip
Merge tag 'mtd/for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull mtd updates from Miquel Raynal: "MTD changes: - Apart from a binding conversion to yaml, only minor changes/small fixes have been merged. Raw NAND changes: - Minor fixes for various controller drivers like DMA mapping checks, better timing derivations or bitflip statistics. - some Hynix NAND flashes were not supporting read-retries, so don't even try to do it SPI NAND changes: - In order to support high-speed modes, certain chips need extra configuration like adding more dummy cycles. This is now possible, especially on Winbond chips. - Aside from that, Gigadevice gets support for a new chip (GD5F1GM9). SPI NOR changes: - A notable changes is the fix for exiting 4-byte addressing on Infineon SEMPER flashes. These flashes do not support the standard EX4B opcode (E9h), and use a vendor-specific opcode (B8h) instead. - There is also a fix for unlocking flashes that are write-protected at power-on. This was caused by using an uninitialized mtd_info in spi_nor_try_unlock_all()" * tag 'mtd/for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (26 commits) mtd: spinand: winbond: Add comment about the maximum frequency mtd: spinand: winbond: Enable high-speed modes on w35n0xjw mtd: spinand: winbond: Enable high-speed modes on w25n0xjw mtd: spinand: Add a ->configure_chip() hook mtd: spinand: Add a frequency field to all READ_FROM_CACHE variants mtd: spinand: Fix macro alignment spi: spi-mem: Take into account the actual maximum frequency spi: spi-mem: Use picoseconds for calculating the op durations mtd: rawnand: atmel: set pmecc data setup time mtd: spinand: propagate spinand_wait() errors from spinand_write_page() mtd: rawnand: fsmc: Add missing check after DMA map mtd: rawnand: rockchip: Add missing check after DMA map mtd: rawnand: hynix: don't try read-retry on SLC NANDs mtd: rawnand: atmel: Fix dma_mapping_error() address mtd: nand: brcmnand: fix mtd corrected bits stat mtd: rawnand: renesas: Add missing check after DMA map mtd: spinand: gigadevice: Add support for GD5F1GM9 chips mtd: nand: brcmnand: replace manual string choices with standard helpers mtd: map: Don't use "proxy" headers mtd: spi-nor: Fix spi_nor_try_unlock_all() ...
Diffstat (limited to 'drivers/spi/spi-mem.c')
-rw-r--r--drivers/spi/spi-mem.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 5db0639d3b01..d3b7e857b377 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -586,14 +586,26 @@ EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
* accurate, all these combinations should be rated (eg. with a time estimate)
* and the best pick should be taken based on these calculations.
*
- * Returns a ns estimate for the time this op would take.
+ * Returns a ns estimate for the time this op would take, except if no
+ * frequency limit has been set, in this case we return the number of
+ * cycles nevertheless to allow callers to distinguish which operation
+ * would be the fastest at iso-frequency.
*/
-u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
+u64 spi_mem_calc_op_duration(struct spi_mem *mem, struct spi_mem_op *op)
{
u64 ncycles = 0;
- u32 ns_per_cycles;
+ u64 ps_per_cycles, duration;
+
+ spi_mem_adjust_op_freq(mem, op);
+
+ if (op->max_freq) {
+ ps_per_cycles = 1000000000000ULL;
+ do_div(ps_per_cycles, op->max_freq);
+ } else {
+ /* In this case, the unit is no longer a time unit */
+ ps_per_cycles = 1;
+ }
- ns_per_cycles = 1000000000 / op->max_freq;
ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1);
ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1);
@@ -603,7 +615,12 @@ u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1);
- return ncycles * ns_per_cycles;
+ /* Derive the duration in ps */
+ duration = ncycles * ps_per_cycles;
+ /* Convert into ns */
+ do_div(duration, 1000);
+
+ return duration;
}
EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);