blob: 9e75f0557a22e468fa0478baa4e328fb3c731a12 [file] [log] [blame]
/*
* Copyright (c) 2023-2024 Analog Devices, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_max32_flash_controller
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/init.h>
#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 const struct flash_driver_api 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)