diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 1d6fe1ecc3c..562d69203c5 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -36,3 +36,4 @@ zephyr_include_directories_ifdef( ) zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_JESD216 jesd216.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 7aab2abf43e..3c84fc12dbd 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -17,6 +17,12 @@ config FLASH_HAS_PAGE_LAYOUT This option is enabled when the SoC flash driver supports retrieving the layout of flash memory pages. +config FLASH_JESD216 + bool + help + Selected by drivers that support JESD216-compatible flash + devices to enable building a common support module. + menuconfig FLASH bool "Flash hardware support" help diff --git a/drivers/flash/jesd216.c b/drivers/flash/jesd216.c new file mode 100644 index 00000000000..b3e2c928a79 --- /dev/null +++ b/drivers/flash/jesd216.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2020 Peter Bigot Consulting, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include +#include "jesd216.h" +#include "spi_nor.h" + +static bool extract_instr(uint16_t packed, + struct jesd216_instr *res) +{ + bool rv = (res != NULL); + + if (rv) { + res->instr = packed >> 8; + res->mode_clocks = (packed >> 5) & 0x07; + res->wait_states = packed & 0x1F; + } + return rv; +} + +int jesd216_bfp_read_support(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + enum jesd216_mode_type mode, + struct jesd216_instr *res) +{ + int rv = -ENOTSUP; + + switch (mode) { + case JESD216_MODE_044: + if ((php->len_dw >= 15) + && (sys_le32_to_cpu(bfp->dw10[5]) & BIT(9))) { + rv = 0; + } + break; + case JESD216_MODE_088: + if ((php->len_dw >= 19) + && (sys_le32_to_cpu(bfp->dw10[9]) & BIT(9))) { + rv = 0; + } + break; + case JESD216_MODE_111: + rv = 0; + break; + case JESD216_MODE_112: + if (sys_le32_to_cpu(bfp->dw1) & BIT(16)) { + uint32_t dw4 = sys_le32_to_cpu(bfp->dw4); + + rv = extract_instr(dw4 >> 0, res); + } + break; + case JESD216_MODE_114: + if (sys_le32_to_cpu(bfp->dw1) & BIT(22)) { + uint32_t dw3 = sys_le32_to_cpu(bfp->dw3); + + rv = extract_instr(dw3 >> 16, res); + } + break; + case JESD216_MODE_118: + if (php->len_dw >= 17) { + uint32_t dw17 = sys_le32_to_cpu(bfp->dw10[7]); + + if ((dw17 >> 24) != 0) { + rv = extract_instr(dw17 >> 16, res); + } + } + break; + case JESD216_MODE_122: + if (sys_le32_to_cpu(bfp->dw1) & BIT(20)) { + uint32_t dw4 = sys_le32_to_cpu(bfp->dw4); + + rv = extract_instr(dw4 >> 16, res); + } + break; + case JESD216_MODE_144: + if (sys_le32_to_cpu(bfp->dw1) & BIT(21)) { + uint32_t dw3 = sys_le32_to_cpu(bfp->dw3); + + rv = extract_instr(dw3 >> 0, res); + } + break; + case JESD216_MODE_188: + if (php->len_dw >= 17) { + uint32_t dw17 = sys_le32_to_cpu(bfp->dw10[7]); + + if ((uint8_t)(dw17 >> 8) != 0) { + rv = extract_instr(dw17 >> 0, res); + } + } + break; + case JESD216_MODE_222: + if (sys_le32_to_cpu(bfp->dw5) & BIT(0)) { + uint32_t dw6 = sys_le32_to_cpu(bfp->dw6); + + rv = extract_instr(dw6 >> 16, res); + } + break; + case JESD216_MODE_444: + if (sys_le32_to_cpu(bfp->dw5) & BIT(4)) { + uint32_t dw7 = sys_le32_to_cpu(bfp->dw7); + + rv = extract_instr(dw7 >> 16, res); + } + break; + /* Not clear how to detect these; they are identified only by + * enable/disable sequences. + */ + case JESD216_MODE_44D4D: + case JESD216_MODE_888: + case JESD216_MODE_8D8D8D: + break; + default: + rv = -EINVAL; + } + + return rv; +} + +int jesd216_bfp_erase(const struct jesd216_bfp *bfp, + uint8_t idx, + struct jesd216_erase_type *etp) +{ + __ASSERT_NO_MSG((idx > 0) && (idx <= JESD216_NUM_ERASE_TYPES)); + + /* Types 1 and 2 are in dw8, types 3 and 4 in dw9 */ + const uint32_t *dwp = &bfp->dw8 + (idx - 1U) / 2U; + uint32_t dw = sys_le32_to_cpu(*dwp); + + /* Type 2(4) is in the upper half of the value. */ + if ((idx & 0x01) == 0x00) { + dw >>= 16; + } + + /* Extract the exponent and command */ + uint8_t exp = (uint8_t)dw; + uint8_t cmd = (uint8_t)(dw >> 8); + + if (exp == 0) { + return -EINVAL; + } + etp->cmd = cmd; + etp->exp = exp; + return 0; +} + +int jesd216_bfp_erase_type_times(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + uint8_t idx, + uint32_t *typ_ms) +{ + __ASSERT_NO_MSG((idx > 0) && (idx <= JESD216_NUM_ERASE_TYPES)); + + /* DW10 introduced in JESD216A */ + if (php->len_dw < 10) { + return -ENOTSUP; + } + + uint32_t dw10 = sys_le32_to_cpu(bfp->dw10[0]); + + /* Each 7-bit erase time entry has a 5-bit count in the lower + * bits, and a 2-bit unit in the upper bits. The actual count + * is the field content plus one. + * + * The entries start with ET1 at bit 4. The low four bits + * encode a value that is offset and scaled to produce a + * multipler to convert from typical time to maximum time. + */ + unsigned int count = 1 + ((dw10 >> (4 + (idx - 1) * 7)) & 0x1F); + unsigned int units = ((dw10 >> (4 + 5 + (idx - 1) * 7)) & 0x03); + unsigned int max_factor = 2 * (1 + (dw10 & 0x0F)); + + switch (units) { + case 0x00: /* 1 ms */ + *typ_ms = count; + break; + case 0x01: /* 16 ms */ + *typ_ms = count * 16; + break; + case 0x02: /* 128 ms */ + *typ_ms = count * 128; + break; + case 0x03: /* 1 s */ + *typ_ms = count * MSEC_PER_SEC; + break; + } + + return max_factor; +} + +int jesd216_bfp_decode_dw11(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + struct jesd216_bfp_dw11 *res) +{ + /* DW11 introduced in JESD216A */ + if (php->len_dw < 11) { + return -ENOTSUP; + } + + uint32_t dw11 = sys_le32_to_cpu(bfp->dw10[1]); + uint32_t value = 1 + ((dw11 >> 24) & 0x1F); + + switch ((dw11 >> 29) & 0x03) { + case 0x00: /* 16 ms */ + value *= 16; + break; + case 0x01: + value *= 256; + break; + case 0x02: + value *= 4 * MSEC_PER_SEC; + break; + case 0x03: + value *= 64 * MSEC_PER_SEC; + break; + } + res->chip_erase_ms = value; + + value = 1 + ((dw11 >> 19) & 0x0F); + if (dw11 & BIT(23)) { + value *= 8; + } + res->byte_prog_addl_us = value; + + value = 1 + ((dw11 >> 14) & 0x0F); + if (dw11 & BIT(18)) { + value *= 8; + } + res->byte_prog_first_us = value; + + value = 1 + ((dw11 >> 8) & 0x01F); + if (dw11 & BIT(13)) { + value *= 64; + } else { + value *= 8; + } + res->page_prog_us = value; + + res->page_size = BIT((dw11 >> 4) & 0x0F); + res->typ_max_factor = 2 * (1 + (dw11 & 0x0F)); + + return 0; +} + +int jesd216_bfp_decode_dw14(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + struct jesd216_bfp_dw14 *res) +{ + /* DW14 introduced in JESD216A */ + if (php->len_dw < 14) { + return -ENOTSUP; + } + + uint32_t dw14 = sys_le32_to_cpu(bfp->dw10[4]); + + if (dw14 & BIT(31)) { + return -ENOTSUP; + } + + res->enter_dpd_instr = (dw14 >> 23) & 0xFF; + res->exit_dpd_instr = (dw14 >> 15) & 0xFF; + + uint32_t value = 1 + ((dw14 >> 8) & 0x1F); + + switch ((dw14 >> 13) & 0x03) { + case 0x00: /* 128 ns */ + value *= 128; + break; + case 0x01: /* 1 us */ + value *= NSEC_PER_USEC; + break; + case 0x02: /* 8 us */ + value *= 8 * NSEC_PER_USEC; + break; + case 0x03: /* 64 us */ + value *= 64 * NSEC_PER_USEC; + break; + } + + res->exit_delay_ns = value; + + res->poll_options = (dw14 >> 2) & 0x3F; + + return 0; +} diff --git a/drivers/flash/jesd216.h b/drivers/flash/jesd216.h new file mode 100644 index 00000000000..ad9888a8e50 --- /dev/null +++ b/drivers/flash/jesd216.h @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2020 Peter Bigot Consulting, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FLASH_JESD216_H_ +#define ZEPHYR_DRIVERS_FLASH_JESD216_H_ + +#include +#include +#include +#include + +/* Following are structures and constants supporting the JEDEC Serial + * Flash Discoverable Parameters standard, JESD216 and its successors, + * available at + * https://www.jedec.org/standards-documents/docs/jesd216b + */ + +#define JESD216_CMD_READ_SFDP 0x5A +#define JESD216_CMD_BURST_SFDP 0x5B + +/* Layout of a JESD216 parameter header. */ +struct jesd216_param_header { + uint8_t id_lsb; /* ID LSB */ + uint8_t rev_minor; /* Minor revision number */ + uint8_t rev_major; /* Major revision number */ + uint8_t len_dw; /* Length of table in 32-bit DWORDs */ + uint8_t ptp[3]; /* Address of table in SFDP space (LSB@0) */ + uint8_t id_msb; /* ID MSB */ +} __packed; + +/* Get the number of bytes required for the parameter table. */ +static inline uint32_t jesd216_param_len(const struct jesd216_param_header *hp) +{ + return sizeof(uint32_t) * hp->len_dw; +} + +/* Get the ID that identifies the content of the parameter table. */ +static inline uint16_t jesd216_param_id(const struct jesd216_param_header *hp) +{ + return ((uint16_t)hp->id_msb << 8) | hp->id_lsb; +} + +/* Get the address within the SFDP where the data for the table is + * stored. + */ +static inline uint32_t jesd216_param_addr(const struct jesd216_param_header *hp) +{ + return ((hp->ptp[2] << 16) + | (hp->ptp[1] << 8) + | (hp->ptp[0] << 0)); +} + +/* Layout of the Serial Flash Discoverable Parameters header. */ +struct jesd216_sfdp_header { + uint32_t magic; /* "SFDP" in little endian */ + uint8_t rev_minor; /* Minor revision number */ + uint8_t rev_major; /* Major revision number */ + uint8_t nph; /* Number of parameter headers */ + uint8_t access; /* Access protocol */ + struct jesd216_param_header phdr[]; /* Headers */ +} __packed; + +/* SFDP access protocol for backwards compatibility with JESD216B. */ +#define JESD216_SFDP_AP_LEGACY 0xFF + +/* The expected value from the jesd216_sfdp::magic field in host byte + * order. + */ +#define JESD216_SFDP_MAGIC 0x50444653 + +/* All JESD216 data is read from the device in little-endian byte + * order. For JEDEC parameter tables defined through JESD216D-01 the + * parameters are defined by 32-bit words that may need to be + * byte-swapped to extract their information. + * + * A 16-bit ID from the parameter header is used to identify the + * content of each table. The first parameter table in the SFDP + * hierarchy must be a Basic Flash Parameter table (ID 0xFF00). + */ + +/* JESD216D-01 section 6.4: Basic Flash Parameter */ +#define JESD216_SFDP_PARAM_ID_BFP 0xFF00 +/* JESD216D-01 section 6.5: Sector Map Parameter */ +#define JESD216_SFDP_PARAM_ID_SECTOR_MAP 0xFF81 +/* JESD216D-01 section 6.6: 4-Byte Address Instruction Parameter */ +#define JESD216_SFDP_PARAM_ID_4B_ADDR_INSTR 0xFF84 +/* JESD216D-01 section 6.7: xSPI (Profile 1.0) Parameter */ +#define JESD216_SFDP_PARAM_ID_XSPI_PROFILE_1V0 0xFF05 +/* JESD216D-01 section 6.8: xSPI (Profile 2.0) Parameter */ +#define JESD216_SFDP_PARAM_ID_XSPI_PROFILE_2V0 0xFF06 + +/* Macro to define the number of bytes required for the SFDP pheader + * and @p nph parameter headers. + * + * @param nph the number of parameter headers to be read. 1 is + * sufficient for basic functionality. + * + * @return required buffer size in bytes. + */ +#define JESD216_SFDP_SIZE(nph) (sizeof(struct jesd216_sfdp_header) \ + + ((nph) * sizeof(struct jesd216_param_header))) + +/** Extract the magic number from the SFDP structure in host byte order. + * + * If this compares equal to JESD216_SFDP_MAGIC then the SFDP header + * may have been read correctly. + */ +static inline uint32_t jesd216_sfdp_magic(const struct jesd216_sfdp_header *hp) +{ + return sys_le32_to_cpu(hp->magic); +} + +/* Layout of the Basic Flash Parameters table. + * + * SFDP through JESD216B supported 9 DWORD values. JESD216C extended + * this to 17, and JESD216D to 20. + * + * All values are expected to be stored as little-endian and must be + * converted to host byte order to extract the bit fields defined in + * the standard. Rather than pre-define layouts to access to all + * potential fields this header provides functions for specific fields + * known to be important, such as density and erase command support. + */ +struct jesd216_bfp { + uint32_t dw1; + uint32_t dw2; + uint32_t dw3; + uint32_t dw4; + uint32_t dw5; + uint32_t dw6; + uint32_t dw7; + uint32_t dw8; + uint32_t dw9; + uint32_t dw10[]; +} __packed; + +/* Provide a few word-specific flags and bitfield ranges for values + * that an application or driver might expect to want to extract. + * + * See the JESD216 specification for the interpretation of these + * bitfields. + */ +#define JESD216_SFDP_BFP_DW1_DTRCLK_FLG BIT(19) +#define JESD216_SFDP_BFP_DW1_ADDRBYTES_MASK (BIT(17) | BIT(18)) +#define JESD216_SFDP_BFP_DW1_ADDRBYTES_SHFT 17 +#define JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B 0 +#define JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_3B4B 1 +#define JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_4B 2 +#define JESD216_SFDP_BFP_DW1_4KERASEINSTR_SHFT 8 +#define JESD216_SFDP_BFP_DW1_4KERASEINSTR_MASK (0xFF << JESD216_SFDP_BFP_DW1_4KERASEINSTR_SHFT) +#define JESD216_SFDP_BFP_DW1_WEISWVSR_FLG BIT(4) +#define JESD216_SFDP_BFP_DW1_VSRBP_FLG BIT(3) +#define JESD216_SFDP_BFP_DW1_WRTGRAN_FLG BIT(2) +#define JESD216_SFDP_BFP_DW1_BSERSZ_SHFT 0 +#define JESD216_SFDP_BFP_DW1_BSERSZ_MASK (0x03 << JESD216_SFDP_BFP_DW1_BSERSZ_SHFT) +#define JESD216_SFDP_BFP_DW1_BSERSZ_VAL_4KSUP 0x01 +#define JESD216_SFDP_BFP_DW1_BSERSZ_VAL_4KNOTSUP 0x03 + +#define JESD216_SFDP_BFP_DW12_SUSPRESSUP_FLG BIT(31) + +/* Data can be extracted from the BFP words using these APIs: + * + * * DW1 (capabilities) use DW1 bitfield macros above or + * jesd216_read_support(). + * * DW2 (density) use jesd216_bfp_density(). + * * DW3-DW7 (instr) use jesd216_bfp_read_support(). + * * DW8-DW9 (erase types) use jesd216_bfp_erase(). + * + * JESD216A (16 DW) + * + * * DW10 (erase times) use jesd216_bfp_erase_type_times(). + * * DW11 (other times) use jesd216_bfp_decode_dw11(). + * * DW12-13 (suspend/resume) no API except + * JESD216_SFDP_BFP_DW12_SUSPRESSUP_FLG. + * * DW14 (deep power down) use jesd216_bfp_decode_dw14(). + * * DW15-16 no API except jesd216_bfp_read_support(). + * + * JESD216C (20 DW) + * * DW17-20 (quad/oct support) no API except jesd216_bfp_read_support(). + */ + +/* Extract the density of the chip in bits from BFP DW2. */ +static inline uint64_t jesd216_bfp_density(const struct jesd216_bfp *hp) +{ + uint32_t dw = sys_le32_to_cpu(hp->dw2); + + if (dw & BIT(31)) { + return BIT64(dw & BIT_MASK(31)); + } + return 1U + (uint64_t)dw; +} + +/* Protocol mode enumeration types. + * + * Modes are identified by fields representing the number of I/O + * signals and the data rate in the transfer. The I/O width may be 1, + * 2, 4, or 8 I/O signals. The data rate may be single or double. + * SDR is assumed; DDR is indicated by a D following the I/O width. + * + * A transfer has three phases, and width/rate is specified for each + * in turn: + * * Transfer of the command + * * Transfer of the command modifier (e.g. address) + * * Transfer of the data. + * + * Modes explicitly mentioned in JESD216 or JESD251 are given + * enumeration values below, which can be used to extract information + * about instruction support. + */ +enum jesd216_mode_type { + JESD216_MODE_044, /* implied instruction, execute in place */ + JESD216_MODE_088, + JESD216_MODE_111, + JESD216_MODE_112, + JESD216_MODE_114, + JESD216_MODE_118, + JESD216_MODE_122, + JESD216_MODE_144, + JESD216_MODE_188, + JESD216_MODE_222, + JESD216_MODE_444, + JESD216_MODE_44D4D, + JESD216_MODE_888, + JESD216_MODE_8D8D8D, + JESD216_MODE_LIMIT, +}; + +/* Command to use for fast read operations in a specified protocol + * mode. + */ +struct jesd216_instr { + uint8_t instr; + uint8_t mode_clocks; + uint8_t wait_states; +}; + +/* Determine whether a particular operational mode is supported for + * read, and possibly what command may be used. + * + * @note For @p mode JESD216_MODE_111 this function will return zero + * to indicate that standard read (instruction 03h) is supported, but + * without providing information on how. SFDP does not provide an + * indication of support for 1-1-1 Fast Read (0Bh). + * + * @param php pointer to the BFP header. + * + * @param bfp pointer to the BFP table. + * + * @param mode the desired protocol mode. + * + * @param res where to store instruction information. Pass a null + * pointer to test for support without retrieving instruction + * information. + * + * @retval positive if instruction is supported and *res has been set. + * + * @retval 0 if instruction is supported but *res has not been set + * (e.g. no instruction needed, or instruction cannot be read from + * BFP). + * + * @retval -ENOTSUP if instruction is not supported. + */ +int jesd216_bfp_read_support(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + enum jesd216_mode_type mode, + struct jesd216_instr *res); + +/* Description of a supported erase operation. */ +struct jesd216_erase_type { + /* The command opcode used for an erase operation. */ + uint8_t cmd; + + /* The value N when the erase operation erases a 2^N byte + * region. + */ + uint8_t exp; +}; + +/* The number of erase types defined in a JESD216 Basic Flash + * Parameter table. + */ +#define JESD216_NUM_ERASE_TYPES 4 + +/* Extract a supported erase size and command from BFP DW8 or DW9. + * + * @param bfp pointer to the parameter table. + * + * @param idx the erase type index, from 1 through 4. Only index 1 is + * guaranteed to be present. + * + * @param etp where to store the command and size used for the erase. + * + * @retval 0 if the erase type index provided usable information. + * @retval -EINVAL if the erase type index is undefined. + */ +int jesd216_bfp_erase(const struct jesd216_bfp *bfp, + uint8_t idx, + struct jesd216_erase_type *etp); + +/* Extract typical and maximum erase times from DW10. + * + * @param php pointer to the BFP header. + * + * @param bfp pointer to the BFP table. + * + * @param idx the erase type index, from 1 through 4. For meaningful + * results the index should be one for which jesd216_bfp_erase() + * returns success. + * + * @param typ_ms where to store the typical erase time (in + * milliseconds) for the specified erase type. + * + * @retval -ENOTSUP if the erase type index is undefined. + * @retval positive is a multiplier that converts typical erase times + * to maximum erase times. + */ +int jesd216_bfp_erase_type_times(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + uint8_t idx, + uint32_t *typ_ms); + +/* Get the page size from the Basic Flash Parameters. + * + * @param php pointer to the BFP header. + * + * @param bfp pointer to the BFP table. + * + * @return the page size in bytes from the parameters if supported, + * otherwise 256. + */ +static inline uint32_t jesd216_bfp_page_size(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp) +{ + /* Page size introduced in JESD216A */ + if (php->len_dw < 11) { + return 256; + } + + uint32_t dw11 = sys_le32_to_cpu(bfp->dw10[1]); + uint8_t exp = (dw11 >> 4) & 0x0F; + + return BIT(exp); +} + +/* Decoded data from JESD216 DW11. */ +struct jesd216_bfp_dw11 { + /* Typical time for chip (die) erase, in milliseconds */ + uint16_t chip_erase_ms; + + /* Typical time for first byte program, in microseconds */ + uint16_t byte_prog_first_us; + + /* Typical time per byte for byte program after first, in + * microseconds + */ + uint16_t byte_prog_addl_us; + + /* Typical time for page program, in microseconds */ + uint16_t page_prog_us; + + /* Multiplier to get maximum time from typical times. */ + uint16_t typ_max_factor; + + /* Number of bytes in a page. */ + uint16_t page_size; +}; + +/* Get data from BFP DW11. + * + * @param php pointer to the BFP header. + * + * @param bfp pointer to the BFP table. + * + * @param res pointer to where to store the decoded data. + * + * @retval -ENOTSUP if this information is not available from this BFP table. + * @retval 0 on successful storage into @c *res. + */ +int jesd216_bfp_decode_dw11(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + struct jesd216_bfp_dw11 *res); + +/* Decode data from JESD216 DW14 */ +struct jesd216_bfp_dw14 { + /* Instruct used to enter deep power-down */ + uint8_t enter_dpd_instr; + + /* Instruct used to exit deep power-down */ + uint8_t exit_dpd_instr; + + /* Bits defining ways busy status may be polled. */ + uint8_t poll_options; + + /* Time after issuing exit instruction until device is ready + * to accept a command, in nanoseconds. + */ + uint32_t exit_delay_ns; +}; + +/* Get data from BFP DW14. + * + * @param php pointer to the BFP header. + * + * @param bfp pointer to the BFP table. + * + * @param res pointer to where to store the decoded data. + * + * @retval -ENOTSUP if this information is not available from this BFP table. + * @retval 0 on successful storage into @c *res. + */ +int jesd216_bfp_decode_dw14(const struct jesd216_param_header *php, + const struct jesd216_bfp *bfp, + struct jesd216_bfp_dw14 *res); + +#endif /* ZEPHYR_DRIVERS_FLASH_JESD216_H_ */