diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 63af95cedd8..eb626f2868a 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -62,6 +62,7 @@ add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock) add_subdirectory_ifdef(CONFIG_PWM pwm) add_subdirectory_ifdef(CONFIG_REGULATOR regulator) add_subdirectory_ifdef(CONFIG_RESET reset) +add_subdirectory_ifdef(CONFIG_RETAINED_MEM retained_mem) add_subdirectory_ifdef(CONFIG_SDHC sdhc) add_subdirectory_ifdef(CONFIG_SENSOR sensor) add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) diff --git a/drivers/Kconfig b/drivers/Kconfig index d4259816ade..e462c28a440 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -63,6 +63,7 @@ source "drivers/ptp_clock/Kconfig" source "drivers/pwm/Kconfig" source "drivers/regulator/Kconfig" source "drivers/reset/Kconfig" +source "drivers/retained_mem/Kconfig" source "drivers/sdhc/Kconfig" source "drivers/sensor/Kconfig" source "drivers/serial/Kconfig" diff --git a/drivers/retained_mem/CMakeLists.txt b/drivers/retained_mem/CMakeLists.txt new file mode 100644 index 00000000000..28a0cecce8a --- /dev/null +++ b/drivers/retained_mem/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() diff --git a/drivers/retained_mem/Kconfig b/drivers/retained_mem/Kconfig new file mode 100644 index 00000000000..1b76aeed48e --- /dev/null +++ b/drivers/retained_mem/Kconfig @@ -0,0 +1,22 @@ +# Copyright (c) Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menuconfig RETAINED_MEM + bool "Retained memory support" + help + Enables support for drivers that can retain their data whilst the + device is powered (may be lost in low power states). + +if RETAINED_MEM + +config RETAINED_MEM_INIT_PRIORITY + int "Retained memory devices init priority" + default 40 + help + Retained memory devices initialization priority, + +module = RETAINED_MEM +module-str = retained_mem +source "subsys/logging/Kconfig.template.log_config" + +endif # RETAINED_MEM diff --git a/drivers/retained_mem/retained_mem_handlers.c b/drivers/retained_mem/retained_mem_handlers.c new file mode 100644 index 00000000000..265ae7b15fd --- /dev/null +++ b/drivers/retained_mem/retained_mem_handlers.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static inline ssize_t z_vrfy_retained_mem_size(const struct device *dev) +{ + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + return z_impl_retained_mem_size(dev); +} +#include + +static inline int z_vrfy_retained_mem_read(const struct device *dev, off_t offset, + uint8_t *buffer, size_t size) +{ + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buffer, size)); + return z_impl_retained_mem_read(dev, offset, buffer, size); +} +#include + +static inline int z_vrfy_retained_mem_write(const struct device *dev, off_t offset, + const uint8_t *buffer, size_t size) +{ + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + Z_OOPS(Z_SYSCALL_MEMORY_READ(buffer, size)); + return z_impl_retained_mem_write(dev, offset, buffer, size); +} +#include + +static inline int z_vrfy_retained_mem_clear(const struct device *dev) +{ + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_RETAINED_MEM)); + return z_impl_retained_mem_clear(dev); +} +#include diff --git a/include/zephyr/drivers/retained_mem.h b/include/zephyr/drivers/retained_mem.h new file mode 100644 index 00000000000..18bfffed099 --- /dev/null +++ b/include/zephyr/drivers/retained_mem.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for retained memory drivers + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_RETAINED_MEM_ +#define ZEPHYR_INCLUDE_DRIVERS_RETAINED_MEM_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +BUILD_ASSERT(!(sizeof(off_t) > sizeof(size_t)), + "Size of off_t must be equal or less than size of size_t"); + +/** + * @brief Retained memory driver interface + * @defgroup retained_mem_interface Retained memory driver interface + * @ingroup io_interfaces + * @{ + */ + +/** + * @typedef retained_mem_size_api + * @brief Callback API to get size of retained memory area. + * See retained_mem_size() for argument description. + */ +typedef ssize_t (*retained_mem_size_api)(const struct device *dev); + +/** + * @typedef retained_mem_read_api + * @brief Callback API to read from retained memory area. + * See retained_mem_read() for argument description. + */ +typedef int (*retained_mem_read_api)(const struct device *dev, off_t offset, uint8_t *buffer, + size_t size); + +/** + * @typedef retained_mem_write_api + * @brief Callback API to write to retained memory area. + * See retained_mem_write() for argument description. + */ +typedef int (*retained_mem_write_api)(const struct device *dev, off_t offset, + const uint8_t *buffer, size_t size); + +/** + * @typedef retained_mem_clear_api + * @brief Callback API to clear retained memory area (reset all data to 0x00). + * See retained_mem_clear() for argument description. + */ +typedef int (*retained_mem_clear_api)(const struct device *dev); + +/** + * @brief Retained memory driver API + * API which can be used by a device to store data in a retained memory area. Retained memory is + * memory that is retained while the device is powered but is lost when power to the device is + * lost (note that low power modes in some devices may clear the data also). This may be in a + * non-initialised RAM region, or in specific registers, but is not reset when a different + * application begins execution or the device is rebooted (without power loss). It must support + * byte-level reading and writing without a need to erase data before writing. + * + * Note that drivers must implement all functions, none of the functions are optional. + */ +struct retained_mem_driver_api { + retained_mem_size_api size; + retained_mem_read_api read; + retained_mem_write_api write; + retained_mem_clear_api clear; +}; + +/** + * @brief Returns the size of the retained memory area. + * + * @param dev Retained memory device to use. + * + * @retval Positive value indicating size in bytes on success, else negative errno + * code. + */ +__syscall ssize_t retained_mem_size(const struct device *dev); + +static inline ssize_t z_impl_retained_mem_size(const struct device *dev) +{ + struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api; + + return api->size(dev); +} + +/** + * @brief Reads data from the Retained memory area. + * + * @param dev Retained memory device to use. + * @param offset Offset to read data from. + * @param buffer Buffer to store read data in. + * @param size Size of data to read. + * + * @retval 0 on success else negative errno code. + */ +__syscall int retained_mem_read(const struct device *dev, off_t offset, uint8_t *buffer, + size_t size); + +static inline int z_impl_retained_mem_read(const struct device *dev, off_t offset, + uint8_t *buffer, size_t size) +{ + struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api; + size_t area_size; + + /* Validate user-supplied parameters */ + if (size == 0) { + return 0; + } + + area_size = api->size(dev); + + if (offset < 0 || size > area_size || (area_size - size) < (size_t)offset) { + return -EINVAL; + } + + return api->read(dev, offset, buffer, size); +} + +/** + * @brief Writes data to the Retained memory area - underlying data does not need to + * be cleared prior to writing. + * + * @param dev Retained memory device to use. + * @param offset Offset to write data to. + * @param buffer Data to write. + * @param size Size of data to be written. + * + * @retval 0 on success else negative errno code. + */ +__syscall int retained_mem_write(const struct device *dev, off_t offset, const uint8_t *buffer, + size_t size); + +static inline int z_impl_retained_mem_write(const struct device *dev, off_t offset, + const uint8_t *buffer, size_t size) +{ + struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api; + size_t area_size; + + /* Validate user-supplied parameters */ + if (size == 0) { + return 0; + } + + area_size = api->size(dev); + + if (offset < 0 || size > area_size || (area_size - size) < (size_t)offset) { + return -EINVAL; + } + + return api->write(dev, offset, buffer, size); +} + +/** + * @brief Clears data in the retained memory area by setting it to 0x00. + * + * @param dev Retained memory device to use. + * + * @retval 0 on success else negative errno code. + */ +__syscall int retained_mem_clear(const struct device *dev); + +static inline int z_impl_retained_mem_clear(const struct device *dev) +{ + struct retained_mem_driver_api *api = (struct retained_mem_driver_api *)dev->api; + + return api->clear(dev); +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_RETAINED_MEM_ */