/* * Copyright (c) 2023-2024 Analog Devices, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT adi_max32_flash_controller #include #include #include #include #include "flc.h" struct max32_flash_dev_config { uint32_t flash_base; uint32_t flash_erase_blk_sz; struct flash_parameters parameters; #if CONFIG_FLASH_PAGE_LAYOUT struct flash_pages_layout pages_layouts; #endif /* CONFIG_FLASH_PAGE_LAYOUT */ }; struct max32_flash_dev_data { #ifdef CONFIG_MULTITHREADING struct k_sem sem; #endif }; #ifdef CONFIG_MULTITHREADING static inline void max32_sem_take(const struct device *dev) { struct max32_flash_dev_data *data = dev->data; k_sem_take(&data->sem, K_FOREVER); } static inline void max32_sem_give(const struct device *dev) { struct max32_flash_dev_data *data = dev->data; k_sem_give(&data->sem); } #else #define max32_sem_take(dev) #define max32_sem_give(dev) #endif /* CONFIG_MULTITHREADING */ static int api_read(const struct device *dev, off_t address, void *buffer, size_t length) { const struct max32_flash_dev_config *const cfg = dev->config; address += cfg->flash_base; MXC_FLC_Read(address, buffer, length); return 0; } static int api_write(const struct device *dev, off_t address, const void *buffer, size_t length) { const struct max32_flash_dev_config *const cfg = dev->config; int ret = 0; max32_sem_take(dev); address += cfg->flash_base; ret = MXC_FLC_Write(address, length, (uint32_t *)buffer); max32_sem_give(dev); return ret != 0 ? -EIO : 0; } static int api_erase(const struct device *dev, off_t start, size_t len) { const struct max32_flash_dev_config *const cfg = dev->config; uint32_t page_size = cfg->flash_erase_blk_sz; uint32_t addr = (start + cfg->flash_base); int ret = 0; max32_sem_take(dev); while (len) { ret = MXC_FLC_PageErase(addr); if (ret) { break; } addr += page_size; if (len > page_size) { len -= page_size; } else { len = 0; } } max32_sem_give(dev); return ret != 0 ? -EIO : 0; } #if CONFIG_FLASH_PAGE_LAYOUT static void api_page_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) { const struct max32_flash_dev_config *const cfg = dev->config; *layout = &cfg->pages_layouts; *layout_size = 1; } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ static const struct flash_parameters *api_get_parameters(const struct device *dev) { const struct max32_flash_dev_config *const cfg = dev->config; return &cfg->parameters; } static int flash_max32_init(const struct device *dev) { int ret = MXC_FLC_Init(); #ifdef CONFIG_MULTITHREADING struct max32_flash_dev_data *data = dev->data; /* Mutex for flash controller */ k_sem_init(&data->sem, 1, 1); #endif return ret != 0 ? -EIO : 0; } static DEVICE_API(flash, flash_max32_driver_api) = { .read = api_read, .write = api_write, .erase = api_erase, .get_parameters = api_get_parameters, #ifdef CONFIG_FLASH_PAGE_LAYOUT .page_layout = api_page_layout, #endif }; #if CONFIG_FLASH_PAGE_LAYOUT #define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n) \ .pages_layouts = { \ .pages_count = DT_INST_FOREACH_CHILD(n, GET_FLASH_SIZE) / \ DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE), \ .pages_size = DT_INST_FOREACH_CHILD(n, GET_ERASE_BLOCK_SIZE), \ }, #else #define FLASH_MAX32_CONFIG_PAGE_LAYOUT(n) #endif #define GET_WRITE_BLOCK_SIZE(n) DT_PROP(n, write_block_size) #define GET_ERASE_BLOCK_SIZE(n) DT_PROP(n, erase_block_size) #define GET_FLASH_BASE(n) DT_REG_ADDR(n) #define GET_FLASH_SIZE(n) DT_REG_SIZE(n) #define DEFINE_FLASH_MAX32(_num) \ static const struct max32_flash_dev_config max32_flash_dev_cfg_##_num = { \ .flash_base = DT_INST_FOREACH_CHILD(_num, GET_FLASH_BASE), \ .flash_erase_blk_sz = DT_INST_FOREACH_CHILD(_num, GET_ERASE_BLOCK_SIZE), \ .parameters = \ { \ .write_block_size = \ DT_INST_FOREACH_CHILD(_num, GET_WRITE_BLOCK_SIZE), \ .erase_value = 0xFF, \ }, \ FLASH_MAX32_CONFIG_PAGE_LAYOUT(_num)}; \ static struct max32_flash_dev_data max32_flash_dev_data_##_num; \ DEVICE_DT_INST_DEFINE(_num, flash_max32_init, NULL, &max32_flash_dev_data_##_num, \ &max32_flash_dev_cfg_##_num, POST_KERNEL, \ CONFIG_FLASH_INIT_PRIORITY, &flash_max32_driver_api); DT_INST_FOREACH_STATUS_OKAY(DEFINE_FLASH_MAX32)