From 49ebf55b0dd4f5ba3d87b44961c448e5ab5541dc Mon Sep 17 00:00:00 2001 From: Aurelien Gonce Date: Mon, 4 Jul 2016 17:48:35 +0200 Subject: [PATCH] mtd: add a low level generic driver for flash file system --- drivers/include/mtd.h | 233 ++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/Makefile | 3 + drivers/mtd/mtd.c | 95 +++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 drivers/include/mtd.h create mode 100644 drivers/mtd/Makefile create mode 100644 drivers/mtd/mtd.c diff --git a/drivers/include/mtd.h b/drivers/include/mtd.h new file mode 100644 index 0000000000..bc32eb280f --- /dev/null +++ b/drivers/include/mtd.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2016 OTA keys S.A. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup mtd Memory Technology Device + * @{ + * @brief Low level Memory Technology Device interface + * + * Generic memory technology device interface + * + * @file + * + * @author Aurelien Gonce + * @author Vincent Dupont + */ + +#ifndef MTD_H +#define MTD_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief MTD power states + */ +enum mtd_power_state { + MTD_POWER_UP, /**< Power up */ + MTD_POWER_DOWN, /**< Power down */ +}; + +/** + * @brief MTD driver interface + * + * This define the functions to access a MTD. + * + * A MTD is composed of pages combined into sectors. A sector is the smallest erasable unit. + * The number of pages in a sector must be constant for the whole MTD. + * + * The erase operation is available only for entire sectors. + */ +typedef struct mtd_desc mtd_desc_t; + +/** + * @brief MTD device descriptor + */ +typedef struct { + const mtd_desc_t *driver; /**< MTD driver */ + uint32_t sector_count; /**< Number of sector in the MTD */ + uint32_t pages_per_sector; /**< Number of pages by sector in the MTD */ + uint32_t page_size; /**< Size of the pages in the MTD */ +} mtd_dev_t; + +/** + * @brief MTD driver interface + * + * This define the functions to access a MTD. + * + * A MTD is composed of pages combined into sectors. A sector is the smallest erasable unit. + * The number of pages in a sector must be constant for the whole MTD. + * + * The erase operation is available only for entire sectors. + */ +struct mtd_desc { + /** + * @brief Initialize Memory Technology Device (MTD) + * + * @param[in] dev Pointer to the selected driver + * + * @returns 0 on success + * @returns < 0 value in error + */ + int (*init)(mtd_dev_t *dev); + + /** + * @brief Read from the Memory Technology Device (MTD) + * + * No alignment is required on @p addr and @p size. + * + * @param[in] dev Pointer to the selected driver + * @param[out] buff Pointer to the data buffer to store read data + * @param[in] addr Starting address + * @param[in] size Number of bytes + * + * @return the number of bytes actually read + * @return < 0 value on error + */ + int (*read)(mtd_dev_t *dev, + void *buff, + uint32_t addr, + uint32_t size); + + /** + * @brief Write to the Memory Technology Device (MTD) + * + * @p addr + @p size must be inside a page boundary. @p addr can be anywhere + * but the buffer cannot overlap two pages. + * + * @param[in] dev Pointer to the selected driver + * @param[in] buff Pointer to the data to be written + * @param[in] addr Starting address + * @param[in] size Number of bytes + * + * @return the number of bytes actually written + * @return < 0 value on error + */ + int (*write)(mtd_dev_t *dev, + const void *buff, + uint32_t addr, + uint32_t size); + + /** + * @brief Erase sector(s) over the Memory Technology Device (MTD) + * + * @p addr must be aligned on a sector boundary. @p size must be a multiple of a sector size. + * + * @param[in] dev Pointer to the selected driver + * @param[in] addr Starting address + * @param[in] size Number of bytes + * + * @return 0 on success + * @return < 0 value on error + */ + int (*erase)(mtd_dev_t *dev, + uint32_t addr, + uint32_t size); + + /** + * @brief Control power of Memory Technology Device (MTD) + * + * @param[in] dev Pointer to the selected driver + * @param[in] power Power state to apply (from @ref mtd_power_state) + * + * @return 0 on success + * @return < 0 value on error + */ + int (*power)(mtd_dev_t *dev, enum mtd_power_state power); +}; + +/** + * @brief mtd_init Initialize a MTD device + * + * @param mtd the device to initialize + * + * @return + */ +int mtd_init(mtd_dev_t *mtd); + +/** + * @brief mtd_read Read data from a MTD device + * + * No alignment is required on @p addr and @p count. + * + * @param mtd the device to read from + * @param[out] dest the buffer to fill in + * @param[in] addr the start address to read from + * @param[in] count the number of bytes to read + * + * @return the number of byte actually read + * @return < 0 if an error occured + * @return -ENODEV if @p mtd is not a valid device + * @return -ENOTSUP if operation is not supported on @p mtd + * @return -EOVERFLOW if @p addr or @p count are not valid, i.e. outside memory + * @return -EIO if I/O error occured + */ +int mtd_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count); + +/** + * @brief mtd_read write data to a MTD device + * + * @p addr + @p count must be inside a page boundary. @p addr can be anywhere + * but the buffer cannot overlap two pages. + * + * @param mtd the device to write to + * @param[in] src the buffer to write + * @param[in] addr the start address to write to + * @param[in] count the number of bytes to write + * + * @return the number of byte actually written + * @return < 0 if an error occured + * @return -ENODEV if @p mtd is not a valid device + * @return -ENOTSUP if operation is not supported on @p mtd + * @return -EOVERFLOW if @p addr or @p count are not valid, i.e. outside memory, + * or overlapping two pages + * @return -EIO if I/O error occured + */ +int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count); + +/** + * @brief mtd_erase Erase sectors of a MTD device + * + * @p addr must be aligned on a sector boundary. @p count must be a multiple of a sector size. + * + * @param mtd the device to erase + * @param[in] addr the address of the first sector to erase + * @param[in] count the number of bytes to erase + * + * @return 0 if erase successful + * @return < 0 if an error occured + * @return -ENODEV if @p mtd is not a valid device + * @return -ENOTSUP if operation is not supported on @p mtd + * @return -EOVERFLOW if @p addr or @p count are not valid, i.e. outside memory + * @return -EIO if I/O error occured + */ +int mtd_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t count); + +/** + * @brief mtd_power Set power mode on a MTD device + * + * @param mtd the device to access + * @param[in] power the power mode to set + * + * @return 0 if power mode successfully set + * @return < 0 if an error occured + * @return -ENODEV if @p mtd is not a valid device + * @return -ENOTSUP if operation or @p power state is not supported on @p mtd + * @return -EIO if I/O error occured + */ +int mtd_power(mtd_dev_t *mtd, enum mtd_power_state power); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* MTD_H */ diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile new file mode 100644 index 0000000000..f31de9a1a2 --- /dev/null +++ b/drivers/mtd/Makefile @@ -0,0 +1,3 @@ +MODULE = mtd + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/mtd/mtd.c b/drivers/mtd/mtd.c new file mode 100644 index 0000000000..53f285382a --- /dev/null +++ b/drivers/mtd/mtd.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 OTA keys S.A. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup mtd + * @{ + * @brief Low level Memory Technology Device interface + * + * Generic memory technology device interface + * + * @file + * + * @author Vincent Dupont + */ + +#include + +#include "mtd.h" + +int mtd_init(mtd_dev_t *mtd) +{ + if (!mtd || !mtd->driver) { + return -ENODEV; + } + + if (mtd->driver->init) { + return mtd->driver->init(mtd); + } + else { + return -ENOTSUP; + } +} + +int mtd_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count) +{ + if (!mtd || !mtd->driver) { + return -ENODEV; + } + + if (mtd->driver->read) { + return mtd->driver->read(mtd, dest, addr, count); + } + else { + return -ENOTSUP; + } +} + +int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count) +{ + if (!mtd || !mtd->driver) { + return -ENODEV; + } + + if (mtd->driver->write) { + return mtd->driver->write(mtd, src, addr, count); + } + else { + return -ENOTSUP; + } +} + +int mtd_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t count) +{ + if (!mtd || !mtd->driver) { + return -ENODEV; + } + + if (mtd->driver->erase) { + return mtd->driver->erase(mtd, addr, count); + } + else { + return -ENOTSUP; + } +} + +int mtd_power(mtd_dev_t *mtd, enum mtd_power_state power) +{ + if (!mtd || !mtd->driver) { + return -ENODEV; + } + + if (mtd->driver->power) { + return mtd->driver->power(mtd, power); + } + else { + return -ENOTSUP; + } +} + +/** @} */