1 /*
2 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*******************************************************************************
8 * NOTICE
9 * The ll is not public api, don't use in application code.
10 * See readme.md in soc/include/hal/readme.md
11 ******************************************************************************/
12
13 // The Lowlevel layer for SPI Flash
14
15 #pragma once
16
17 #include <stdlib.h>
18 #include <sys/param.h> // For MIN/MAX
19 #include <stdbool.h>
20 #include <string.h>
21
22 #include "soc/spi_periph.h"
23 #include "soc/spi_mem_struct.h"
24 #include "hal/assert.h"
25 #include "hal/spi_types.h"
26 #include "hal/spi_flash_types.h"
27 #include "soc/pcr_struct.h"
28 #include "soc/clk_tree_defs.h"
29 #include "hal/misc.h"
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
36 #define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
37
38 typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
39
40 /*------------------------------------------------------------------------------
41 * Control
42 *----------------------------------------------------------------------------*/
43 /**
44 * Reset peripheral registers before configuration and starting control
45 *
46 * @param dev Beginning address of the peripheral registers.
47 */
spimem_flash_ll_reset(spi_mem_dev_t * dev)48 static inline void spimem_flash_ll_reset(spi_mem_dev_t *dev)
49 {
50 dev->user.val = 0;
51 dev->ctrl.val = 0;
52 }
53
54 /**
55 * Check whether the previous operation is done.
56 *
57 * @param dev Beginning address of the peripheral registers.
58 *
59 * @return true if last command is done, otherwise false.
60 */
spimem_flash_ll_cmd_is_done(const spi_mem_dev_t * dev)61 static inline bool spimem_flash_ll_cmd_is_done(const spi_mem_dev_t *dev)
62 {
63 return (dev->cmd.val == 0);
64 }
65
66 /**
67 * Erase the flash chip.
68 *
69 * @param dev Beginning address of the peripheral registers.
70 */
spimem_flash_ll_erase_chip(spi_mem_dev_t * dev)71 static inline void spimem_flash_ll_erase_chip(spi_mem_dev_t *dev)
72 {
73 dev->cmd.flash_ce = 1;
74 }
75
76 /**
77 * Erase the sector, the address should be set by spimem_flash_ll_set_address.
78 *
79 * @param dev Beginning address of the peripheral registers.
80 */
spimem_flash_ll_erase_sector(spi_mem_dev_t * dev)81 static inline void spimem_flash_ll_erase_sector(spi_mem_dev_t *dev)
82 {
83 dev->ctrl.val = 0;
84 dev->cmd.flash_se = 1;
85 }
86
87 /**
88 * Erase the block, the address should be set by spimem_flash_ll_set_address.
89 *
90 * @param dev Beginning address of the peripheral registers.
91 */
spimem_flash_ll_erase_block(spi_mem_dev_t * dev)92 static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
93 {
94 dev->cmd.flash_be = 1;
95 }
96
97 /**
98 * Suspend erase/program operation.
99 *
100 * @param dev Beginning address of the peripheral registers.
101 */
spimem_flash_ll_suspend(spi_mem_dev_t * dev)102 static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
103 {
104 dev->flash_sus_ctrl.flash_pes = 1;
105 }
106
107 /**
108 * Resume suspended erase/program operation.
109 *
110 * @param dev Beginning address of the peripheral registers.
111 */
spimem_flash_ll_resume(spi_mem_dev_t * dev)112 static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
113 {
114 dev->flash_sus_ctrl.flash_per = 1;
115 }
116
117 /**
118 * Initialize auto suspend mode, and esp32H2 doesn't support disable auto-suspend.
119 *
120 * @param dev Beginning address of the peripheral registers.
121 * @param auto_sus Enable/disable Flash Auto-Suspend.
122 */
spimem_flash_ll_auto_suspend_init(spi_mem_dev_t * dev,bool auto_sus)123 static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
124 {
125 dev->flash_sus_ctrl.flash_pes_en = auto_sus;
126 }
127
128 /**
129 * Initialize auto resume mode
130 *
131 * @param dev Beginning address of the peripheral registers.
132 * @param auto_res Enable/Disable Flash Auto-Resume.
133 *
134 */
spimem_flash_ll_auto_resume_init(spi_mem_dev_t * dev,bool auto_res)135 static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res)
136 {
137 dev->flash_sus_ctrl.pes_per_en = auto_res;
138 }
139
140 /**
141 * Setup the flash suspend command, may vary from chips to chips.
142 *
143 * @param dev Beginning address of the peripheral registers.
144 * @param sus_cmd Flash suspend command.
145 *
146 */
spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t * dev,uint32_t sus_cmd)147 static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd)
148 {
149 HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, flash_pes_command, sus_cmd);
150 }
151
152 /**
153 * Setup the flash resume command, may vary from chips to chips.
154 *
155 * @param dev Beginning address of the peripheral registers.
156 * @param res_cmd Flash resume command.
157 *
158 */
spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t * dev,uint32_t res_cmd)159 static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd)
160 {
161 HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sus_status, flash_per_command, res_cmd);
162 }
163
164 /**
165 * Setup the flash read suspend status command, may vary from chips to chips.
166 *
167 * @param dev Beginning address of the peripheral registers.
168 * @param pesr_cmd Flash read suspend status command.
169 *
170 */
spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t * dev,uint32_t pesr_cmd)171 static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
172 {
173 HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_cmd, wait_pesr_command, pesr_cmd);
174 }
175
176 /**
177 * Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs.
178 *
179 * @param dev Beginning address of the peripheral registers.
180 * @param sus_check_sus_en 1: enable, 0: disable.
181 *
182 */
spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t * dev,bool sus_check_sus_en)183 static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en)
184 {
185 dev->flash_sus_ctrl.sus_timeout_cnt = 5;
186 dev->flash_sus_ctrl.pes_end_en = sus_check_sus_en;
187 }
188
189 /**
190 * Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs.
191 *
192 * @param dev Beginning address of the peripheral registers.
193 * @param sus_check_sus_en 1: enable, 0: disable.
194 *
195 */
spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t * dev,bool res_check_sus_en)196 static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en)
197 {
198 dev->flash_sus_ctrl.sus_timeout_cnt = 5;
199 dev->flash_sus_ctrl.per_end_en = res_check_sus_en;
200 }
201
202 /**
203 * Set 8 bit command to read suspend status
204 *
205 * @param dev Beginning address of the peripheral registers.
206 */
spimem_flash_ll_set_read_sus_status(spi_mem_dev_t * dev,uint32_t sus_conf)207 static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_conf)
208 {
209 dev->flash_sus_ctrl.frd_sus_2b = 0;
210 HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_sus_ctrl, pesr_end_msk, sus_conf);
211 }
212
213 /**
214 * Initialize auto wait idle mode
215 *
216 * @param dev Beginning address of the peripheral registers.
217 * @param auto_waiti Enable/disable auto wait-idle function
218 */
spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t * dev,bool auto_waiti)219 static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
220 {
221 HAL_FORCE_MODIFY_U32_REG_FIELD(dev->flash_waiti_ctrl, waiti_cmd, 0x05);
222 dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti;
223 dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti;
224 }
225
226 /**
227 * Return the suspend status of erase or program operations.
228 *
229 * @param dev Beginning address of the peripheral registers.
230 *
231 * @return true if suspended, otherwise false.
232 */
spimem_flash_ll_sus_status(spi_mem_dev_t * dev)233 static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
234 {
235 return dev->sus_status.flash_sus;
236 }
237
238 /**
239 * Enable/disable write protection for the flash chip.
240 *
241 * @param dev Beginning address of the peripheral registers.
242 * @param wp true to enable the protection, false to disable (write enable).
243 */
spimem_flash_ll_set_write_protect(spi_mem_dev_t * dev,bool wp)244 static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp)
245 {
246 if (wp) {
247 dev->cmd.flash_wrdi = 1;
248 } else {
249 dev->cmd.flash_wren = 1;
250 }
251 }
252
253 /**
254 * Get the read data from the buffer after ``spimem_flash_ll_read`` is done.
255 *
256 * @param dev Beginning address of the peripheral registers.
257 * @param buffer Buffer to hold the output data
258 * @param read_len Length to get out of the buffer
259 */
spimem_flash_ll_get_buffer_data(spi_mem_dev_t * dev,void * buffer,uint32_t read_len)260 static inline void spimem_flash_ll_get_buffer_data(spi_mem_dev_t *dev, void *buffer, uint32_t read_len)
261 {
262 if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) {
263 // If everything is word-aligned, do a faster memcpy
264 memcpy(buffer, (void *)dev->data_buf, read_len);
265 } else {
266 // Otherwise, slow(er) path copies word by word
267 int copy_len = read_len;
268 for (int i = 0; i < (read_len + 3) / 4; i++) {
269 int word_len = MIN(sizeof(uint32_t), copy_len);
270 uint32_t word = dev->data_buf[i];
271 memcpy(buffer, &word, word_len);
272 buffer = (void *)((intptr_t)buffer + word_len);
273 copy_len -= word_len;
274 }
275 }
276 }
277
278 /**
279 * Set the data to be written in the data buffer.
280 *
281 * @param dev Beginning address of the peripheral registers.
282 * @param buffer Buffer holding the data
283 * @param length Length of data in bytes.
284 */
spimem_flash_ll_set_buffer_data(spi_mem_dev_t * dev,const void * buffer,uint32_t length)285 static inline void spimem_flash_ll_set_buffer_data(spi_mem_dev_t *dev, const void *buffer, uint32_t length)
286 {
287 // Load data registers, word at a time
288 int num_words = (length + 3) / 4;
289 for (int i = 0; i < num_words; i++) {
290 uint32_t word = 0;
291 uint32_t word_len = MIN(length, sizeof(word));
292 memcpy(&word, buffer, word_len);
293 dev->data_buf[i] = word;
294 length -= word_len;
295 buffer = (void *)((intptr_t)buffer + word_len);
296 }
297 }
298
299
300 /**
301 * Program a page of the flash chip. Call ``spimem_flash_ll_set_address`` before
302 * this to set the address to program.
303 *
304 * @param dev Beginning address of the peripheral registers.
305 * @param buffer Buffer holding the data to program
306 * @param length Length to program.
307 */
spimem_flash_ll_program_page(spi_mem_dev_t * dev,const void * buffer,uint32_t length)308 static inline void spimem_flash_ll_program_page(spi_mem_dev_t *dev, const void *buffer, uint32_t length)
309 {
310 dev->user.usr_dummy = 0;
311 spimem_flash_ll_set_buffer_data(dev, buffer, length);
312 dev->cmd.flash_pp = 1;
313 }
314
315 /**
316 * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases,
317 * should be configured before this is called.
318 *
319 * @param dev Beginning address of the peripheral registers.
320 */
spimem_flash_ll_user_start(spi_mem_dev_t * dev)321 static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
322 {
323 dev->cmd.usr = 1;
324 }
325
326 /**
327 * Check whether the host is idle to perform new commands.
328 *
329 * @param dev Beginning address of the peripheral registers.
330 *
331 * @return true if the host is idle, otherwise false
332 */
spimem_flash_ll_host_idle(const spi_mem_dev_t * dev)333 static inline bool spimem_flash_ll_host_idle(const spi_mem_dev_t *dev)
334 {
335 return dev->cmd.mst_st == 0;
336 }
337
338 /**
339 * Set phases for user-defined transaction to read
340 *
341 * @param dev Beginning address of the peripheral registers.
342 */
spimem_flash_ll_read_phase(spi_mem_dev_t * dev)343 static inline void spimem_flash_ll_read_phase(spi_mem_dev_t *dev)
344 {
345 typeof (dev->user) user = {
346 .usr_command = 1,
347 .usr_mosi = 0,
348 .usr_miso = 1,
349 .usr_addr = 1,
350 };
351 dev->user = user;
352 }
353 /*------------------------------------------------------------------------------
354 * Configs
355 *----------------------------------------------------------------------------*/
356 /**
357 * Select which pin to use for the flash
358 *
359 * @param dev Beginning address of the peripheral registers.
360 * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins.
361 */
spimem_flash_ll_set_cs_pin(spi_mem_dev_t * dev,int pin)362 static inline void spimem_flash_ll_set_cs_pin(spi_mem_dev_t *dev, int pin)
363 {
364 dev->misc.cs0_dis = (pin == 0) ? 0 : 1;
365 dev->misc.cs1_dis = (pin == 1) ? 0 : 1;
366 }
367
368 /**
369 * Set the read io mode.
370 *
371 * @param dev Beginning address of the peripheral registers.
372 * @param read_mode I/O mode to use in the following transactions.
373 */
spimem_flash_ll_set_read_mode(spi_mem_dev_t * dev,esp_flash_io_mode_t read_mode)374 static inline void spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_io_mode_t read_mode)
375 {
376 typeof (dev->ctrl) ctrl = dev->ctrl;
377 ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M);
378 ctrl.val |= SPI_MEM_FASTRD_MODE_M;
379 switch (read_mode) {
380 case SPI_FLASH_FASTRD:
381 //the default option
382 break;
383 case SPI_FLASH_QIO:
384 ctrl.fread_qio = 1;
385 break;
386 case SPI_FLASH_QOUT:
387 ctrl.fread_quad = 1;
388 break;
389 case SPI_FLASH_DIO:
390 ctrl.fread_dio = 1;
391 break;
392 case SPI_FLASH_DOUT:
393 ctrl.fread_dual = 1;
394 break;
395 case SPI_FLASH_SLOWRD:
396 ctrl.fastrd_mode = 0;
397 break;
398 default:
399 abort();
400 }
401 dev->ctrl = ctrl;
402 }
403
404 __attribute__((always_inline))
spimem_flash_ll_set_clock_source(soc_periph_mspi_clk_src_t clk_src)405 static inline void spimem_flash_ll_set_clock_source(soc_periph_mspi_clk_src_t clk_src)
406 {
407 switch (clk_src) {
408 case MSPI_CLK_SRC_XTAL:
409 PCR.mspi_conf.mspi_clk_sel = 0;
410 break;
411 case MSPI_CLK_SRC_RC_FAST:
412 PCR.mspi_conf.mspi_clk_sel = 1;
413 break;
414 case MSPI_CLK_SRC_PLL_F64M:
415 PCR.mspi_conf.mspi_clk_sel = 2;
416 break;
417 case MSPI_CLK_SRC_PLL_F48M:
418 PCR.mspi_conf.mspi_clk_sel = 3;
419 break;
420 default:
421 HAL_ASSERT(false);
422 }
423 }
424
425 /**
426 * Set clock frequency to work at.
427 *
428 * @param dev Beginning address of the peripheral registers.
429 * @param clock_val pointer to the clock value to set
430 */
spimem_flash_ll_set_clock(spi_mem_dev_t * dev,spimem_flash_ll_clock_reg_t * clock_val)431 static inline void spimem_flash_ll_set_clock(spi_mem_dev_t *dev, spimem_flash_ll_clock_reg_t *clock_val)
432 {
433 dev->clock.val = *clock_val;
434 }
435
436 /**
437 * Set the input length, in bits.
438 *
439 * @param dev Beginning address of the peripheral registers.
440 * @param bitlen Length of input, in bits.
441 */
spimem_flash_ll_set_miso_bitlen(spi_mem_dev_t * dev,uint32_t bitlen)442 static inline void spimem_flash_ll_set_miso_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
443 {
444 dev->user.usr_miso = bitlen > 0;
445 dev->miso_dlen.usr_miso_bit_len = bitlen ? (bitlen - 1) : 0;
446 }
447
448 /**
449 * Set the output length, in bits (not including command, address and dummy
450 * phases)
451 *
452 * @param dev Beginning address of the peripheral registers.
453 * @param bitlen Length of output, in bits.
454 */
spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t * dev,uint32_t bitlen)455 static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
456 {
457 dev->user.usr_mosi = bitlen > 0;
458 dev->mosi_dlen.usr_mosi_bit_len = bitlen ? (bitlen - 1) : 0;
459 }
460
461 /**
462 * Set the command.
463 *
464 * @param dev Beginning address of the peripheral registers.
465 * @param command Command to send
466 * @param bitlen Length of the command
467 */
spimem_flash_ll_set_command(spi_mem_dev_t * dev,uint32_t command,uint32_t bitlen)468 static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen)
469 {
470 dev->user.usr_command = 1;
471 typeof(dev->user2) user2 = {
472 .usr_command_value = command,
473 .usr_command_bitlen = (bitlen - 1),
474 };
475 dev->user2 = user2;
476 }
477
478 /**
479 * Get the address length that is set in register, in bits.
480 *
481 * @param dev Beginning address of the peripheral registers.
482 *
483 */
spimem_flash_ll_get_addr_bitlen(spi_mem_dev_t * dev)484 static inline int spimem_flash_ll_get_addr_bitlen(spi_mem_dev_t *dev)
485 {
486 return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0;
487 }
488
489 /**
490 * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write...
491 *
492 * @param dev Beginning address of the peripheral registers.
493 * @param bitlen Length of the address, in bits
494 */
spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t * dev,uint32_t bitlen)495 static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
496 {
497 dev->user1.usr_addr_bitlen = (bitlen - 1);
498 dev->user.usr_addr = bitlen ? 1 : 0;
499 }
500
501 /**
502 * Set extra address for bits M0-M7 in DIO/QIO mode.
503 *
504 * @param dev Beginning address of the peripheral registers.
505 * @param extra_addr extra address(M0-M7) to send.
506 */
spimem_flash_ll_set_extra_address(spi_mem_dev_t * dev,uint32_t extra_addr)507 static inline void spimem_flash_ll_set_extra_address(spi_mem_dev_t *dev, uint32_t extra_addr)
508 {
509 dev->cache_fctrl.usr_addr_4byte = 0;
510 dev->rd_status.wb_mode = extra_addr;
511 }
512
513 /**
514 * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
515 *
516 * @param dev Beginning address of the peripheral registers.
517 * @param addr Address to send
518 */
spimem_flash_ll_set_address(spi_mem_dev_t * dev,uint32_t addr)519 static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr)
520 {
521 dev->addr = addr;
522 }
523
524 /**
525 * Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
526 *
527 * @param dev Beginning address of the peripheral registers.
528 * @param addr Address to send
529 */
spimem_flash_ll_set_usr_address(spi_mem_dev_t * dev,uint32_t addr,uint32_t bitlen)530 static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
531 {
532 (void)bitlen;
533 spimem_flash_ll_set_address(dev, addr);
534 }
535
536 /**
537 * Set the length of dummy cycles.
538 *
539 * @param dev Beginning address of the peripheral registers.
540 * @param dummy_n Cycles of dummy phases
541 */
spimem_flash_ll_set_dummy(spi_mem_dev_t * dev,uint32_t dummy_n)542 static inline void spimem_flash_ll_set_dummy(spi_mem_dev_t *dev, uint32_t dummy_n)
543 {
544 dev->user.usr_dummy = dummy_n ? 1 : 0;
545 dev->user1.usr_dummy_cyclelen = dummy_n - 1;
546 }
547
548 /**
549 * Set CS hold time.
550 *
551 * @param dev Beginning address of the peripheral registers.
552 * @param hold_n CS hold time config used by the host.
553 */
spimem_flash_ll_set_hold(spi_mem_dev_t * dev,uint32_t hold_n)554 static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
555 {
556 dev->ctrl2.cs_hold_time = hold_n - 1;
557 dev->user.cs_hold = (hold_n > 0? 1: 0);
558 }
559
spimem_flash_ll_set_cs_setup(spi_mem_dev_t * dev,uint32_t cs_setup_time)560 static inline void spimem_flash_ll_set_cs_setup(spi_mem_dev_t *dev, uint32_t cs_setup_time)
561 {
562 dev->user.cs_setup = (cs_setup_time > 0 ? 1 : 0);
563 dev->ctrl2.cs_setup_time = cs_setup_time - 1;
564 }
565
566 /**
567 * Get the spi flash source clock frequency. Used for calculating
568 * the divider parameters.
569 *
570 * @param None
571 *
572 * @return the frequency of spi flash clock source.(MHz)
573 */
spimem_flash_ll_get_source_freq_mhz(void)574 static inline uint8_t spimem_flash_ll_get_source_freq_mhz(void)
575 {
576 uint8_t clock_val = 0;
577 switch (PCR.mspi_conf.mspi_clk_sel) {
578 case 0:
579 clock_val = 32;
580 break;
581 case 1:
582 clock_val = 8;
583 break;
584 case 2:
585 clock_val = 64;
586 break;
587 case 3:
588 clock_val = 32;
589 break;
590 default:
591 HAL_ASSERT(false);
592 }
593 return clock_val;
594 }
595
596 /**
597 * Calculate spi_flash clock frequency division parameters for register.
598 *
599 * @param clkdiv frequency division factor
600 *
601 * @return Register setting for the given clock division factor.
602 */
spimem_flash_ll_calculate_clock_reg(uint8_t clkdiv)603 static inline uint32_t spimem_flash_ll_calculate_clock_reg(uint8_t clkdiv)
604 {
605 uint32_t div_parameter;
606 // See comments of `clock` in `spi_mem_struct.h`
607 if (clkdiv == 1) {
608 div_parameter = (1 << 31);
609 } else {
610 div_parameter = ((clkdiv - 1) | (((clkdiv - 1) / 2 & 0xff) << 8 ) | (((clkdiv - 1) & 0xff) << 16));
611 }
612 return div_parameter;
613 }
614
615 #ifdef __cplusplus
616 }
617 #endif
618