|  | /* | 
|  | * Copyright 2023 Cypress Semiconductor Corporation (an Infineon company) or | 
|  | * an affiliate of Cypress Semiconductor Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #define DT_DRV_COMPAT	  infineon_cat1_flash_controller | 
|  | #define SOC_NV_FLASH_NODE DT_PARENT(DT_INST(0, fixed_partitions)) | 
|  |  | 
|  | #define PAGE_LEN DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) | 
|  |  | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/devicetree.h> | 
|  | #include <zephyr/drivers/flash.h> | 
|  | #include <zephyr/logging/log.h> | 
|  |  | 
|  | #include "cyhal_flash.h" | 
|  |  | 
|  | LOG_MODULE_REGISTER(flash_infineon_cat1, CONFIG_FLASH_LOG_LEVEL); | 
|  |  | 
|  | /* Device config structure */ | 
|  | struct ifx_cat1_flash_config { | 
|  | uint32_t base_addr; | 
|  | uint32_t max_addr; | 
|  | }; | 
|  |  | 
|  | /* Data structure */ | 
|  | struct ifx_cat1_flash_data { | 
|  | cyhal_flash_t flash_obj; | 
|  | struct k_sem sem; | 
|  | }; | 
|  |  | 
|  | static struct flash_parameters ifx_cat1_flash_parameters = { | 
|  | .write_block_size = DT_PROP(SOC_NV_FLASH_NODE, write_block_size), | 
|  | .erase_value = 0x00, | 
|  | }; | 
|  |  | 
|  | static inline void flash_ifx_sem_take(const struct device *dev) | 
|  | { | 
|  | struct ifx_cat1_flash_data *data = dev->data; | 
|  |  | 
|  | k_sem_take(&data->sem, K_FOREVER); | 
|  | } | 
|  |  | 
|  | static inline void flash_ifx_sem_give(const struct device *dev) | 
|  | { | 
|  | struct ifx_cat1_flash_data *data = dev->data; | 
|  |  | 
|  | k_sem_give(&data->sem); | 
|  | } | 
|  |  | 
|  | static int ifx_cat1_flash_read(const struct device *dev, off_t offset, void *data, size_t data_len) | 
|  | { | 
|  | struct ifx_cat1_flash_data *dev_data = dev->data; | 
|  | const struct ifx_cat1_flash_config *dev_config = dev->config; | 
|  | uint32_t read_offset = dev_config->base_addr + offset; | 
|  | cy_rslt_t rslt = CY_RSLT_SUCCESS; | 
|  | int ret = 0; | 
|  |  | 
|  | flash_ifx_sem_take(dev); | 
|  |  | 
|  | rslt = cyhal_flash_read(&dev_data->flash_obj, read_offset, (uint8_t *)data, data_len); | 
|  | if (rslt != CY_RSLT_SUCCESS) { | 
|  | LOG_ERR("Error reading @ 0x%x (Err:0x%x)", read_offset, rslt); | 
|  | ret = -EIO; | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | out: | 
|  | flash_ifx_sem_give(dev); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int ifx_cat1_flash_write(const struct device *dev, off_t offset, const void *data, | 
|  | size_t data_len) | 
|  | { | 
|  | struct ifx_cat1_flash_data *dev_data = dev->data; | 
|  | const struct ifx_cat1_flash_config *dev_config = dev->config; | 
|  | uint32_t write_offset = dev_config->base_addr + (uint32_t)offset; | 
|  | const uint8_t *data_ptr = (const uint8_t *)data; | 
|  | cy_rslt_t rslt = CY_RSLT_SUCCESS; | 
|  | int ret = 0; | 
|  |  | 
|  | if (data_len == 0) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if ((offset < 0) || (data_len % PAGE_LEN != 0) || (offset % PAGE_LEN != 0)) { | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | flash_ifx_sem_take(dev); | 
|  |  | 
|  | while (data_len) { | 
|  | rslt = cyhal_flash_write(&dev_data->flash_obj, write_offset, | 
|  | (const uint32_t *)data_ptr); | 
|  | if (rslt != CY_RSLT_SUCCESS) { | 
|  | LOG_ERR("Error in writing @ 0x%x (Err:0x%x)", write_offset, rslt); | 
|  | ret = -EIO; | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | data_ptr += PAGE_LEN; | 
|  | write_offset += PAGE_LEN; | 
|  | data_len -= PAGE_LEN; | 
|  | } | 
|  |  | 
|  | out: | 
|  | flash_ifx_sem_give(dev); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int ifx_cat1_flash_erase(const struct device *dev, off_t offset, size_t size) | 
|  | { | 
|  | struct ifx_cat1_flash_data *data = dev->data; | 
|  | const struct ifx_cat1_flash_config *config = dev->config; | 
|  | uint32_t erase_offset = config->base_addr + (uint32_t)offset; | 
|  | cy_rslt_t rslt; | 
|  |  | 
|  | if ((offset < 0) || ((offset % PAGE_LEN) != 0)) { | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | if (((erase_offset + size) > config->max_addr) || ((size % PAGE_LEN) != 0)) { | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | while (size) { | 
|  | rslt = cyhal_flash_erase(&data->flash_obj, erase_offset); | 
|  | if (rslt != CY_RSLT_SUCCESS) { | 
|  | LOG_ERR("Error in erasing : 0x%x", rslt); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | size -= PAGE_LEN; | 
|  | erase_offset += PAGE_LEN; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if CONFIG_FLASH_PAGE_LAYOUT | 
|  | static const struct flash_pages_layout ifx_cat1_flash_pages_layout = { | 
|  | .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / PAGE_LEN, | 
|  | .pages_size = PAGE_LEN, | 
|  | }; | 
|  |  | 
|  | static void ifx_cat1_flash_page_layout(const struct device *dev, | 
|  | const struct flash_pages_layout **layout, | 
|  | size_t *layout_size) | 
|  | { | 
|  | *layout = &ifx_cat1_flash_pages_layout; | 
|  |  | 
|  | /* | 
|  | * For flash memories which have uniform page sizes, this routine | 
|  | * returns an array of length 1, which specifies the page size and | 
|  | * number of pages in the memory. | 
|  | */ | 
|  | *layout_size = 1; | 
|  | } | 
|  | #endif /* CONFIG_FLASH_PAGE_LAYOUT */ | 
|  |  | 
|  | static const struct flash_parameters *ifx_cat1_flash_get_parameters(const struct device *dev) | 
|  | { | 
|  | ARG_UNUSED(dev); | 
|  |  | 
|  | return &ifx_cat1_flash_parameters; | 
|  | } | 
|  |  | 
|  | static int ifx_cat1_flash_init(const struct device *dev) | 
|  | { | 
|  | struct ifx_cat1_flash_data *data = dev->data; | 
|  | cy_rslt_t rslt = CY_RSLT_SUCCESS; | 
|  |  | 
|  | rslt = cyhal_flash_init(&data->flash_obj); | 
|  | if (rslt != CY_RSLT_SUCCESS) { | 
|  | LOG_ERR("Failed to init flash hal driver (Err:0x%x)", rslt); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | k_sem_init(&data->sem, 1, 1); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static DEVICE_API(flash, ifx_cat1_flash_driver_api) = { | 
|  | .read = ifx_cat1_flash_read, | 
|  | .write = ifx_cat1_flash_write, | 
|  | .erase = ifx_cat1_flash_erase, | 
|  | .get_parameters = ifx_cat1_flash_get_parameters, | 
|  | #ifdef CONFIG_FLASH_PAGE_LAYOUT | 
|  | .page_layout = ifx_cat1_flash_page_layout, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | static struct ifx_cat1_flash_data flash_data; | 
|  |  | 
|  | static const struct ifx_cat1_flash_config ifx_cat1_flash_config = { | 
|  | .base_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE), | 
|  | .max_addr = DT_REG_ADDR(SOC_NV_FLASH_NODE) + DT_REG_SIZE(SOC_NV_FLASH_NODE)}; | 
|  |  | 
|  | DEVICE_DT_INST_DEFINE(0, ifx_cat1_flash_init, NULL, &flash_data, &ifx_cat1_flash_config, | 
|  | POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, &ifx_cat1_flash_driver_api); |