diff --git a/drivers/disk/CMakeLists.txt b/drivers/disk/CMakeLists.txt index 91d834f863e..20ac00a246a 100644 --- a/drivers/disk/CMakeLists.txt +++ b/drivers/disk/CMakeLists.txt @@ -11,5 +11,6 @@ zephyr_library_sources_ifdef(CONFIG_DISK_DRIVER_RAM ramdisk.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_OVER_SPI sdmmc_spi.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_STM32 sdmmc_stm32.c) zephyr_library_sources_ifdef(CONFIG_SDMMC_USDHC usdhc.c) +zephyr_library_sources_ifdef(CONFIG_SDMMC_SUBSYS sdmmc_subsys.c) endif() diff --git a/drivers/disk/Kconfig.sdmmc b/drivers/disk/Kconfig.sdmmc index 1859e42b715..ec24ea1d70c 100644 --- a/drivers/disk/Kconfig.sdmmc +++ b/drivers/disk/Kconfig.sdmmc @@ -5,6 +5,7 @@ DT_COMPAT_ZEPHYR_MMC_SPI_SLOT := zephyr,mmc-spi-slot DT_COMPAT_NXP_USDHC := nxp,imx-usdhc DT_COMPAT_ST_STM32_SDMMC := st,stm32-sdmmc +DT_COMPAT_ZEPHYR_MMC := zephyr,sdmmc-disk config DISK_DRIVER_SDMMC bool "SDMMC card driver" @@ -33,6 +34,14 @@ config SDMMC_OVER_SPI help File system on a SDHC card accessed over SPI. +config SDMMC_SUBSYS + bool "SDMMC access via SD subsystem" + select SD_STACK + select SDHC + default $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_MMC)) + help + Enable SDMMC access via SD subsystem + config SDMMC_USDHC bool "NXP i.MXRT USDHC driver" depends on (HAS_MCUX_USDHC1 || HAS_MCUX_USDHC2) diff --git a/drivers/disk/sdmmc_subsys.c b/drivers/disk/sdmmc_subsys.c new file mode 100644 index 00000000000..26f0d365b12 --- /dev/null +++ b/drivers/disk/sdmmc_subsys.c @@ -0,0 +1,141 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * SDMMC disk driver using zephyr SD subsystem + */ +#define DT_DRV_COMPAT zephyr_sdmmc_disk + +#include +#include + + +enum sd_status { + SD_UNINIT, + SD_ERROR, + SD_OK, +}; + +struct sdmmc_config { + const struct device *host_controller; +}; + +struct sdmmc_data { + struct sd_card card; + enum sd_status status; + char *name; +}; + + +static int disk_sdmmc_access_init(struct disk_info *disk) +{ + const struct device *dev = disk->dev; + const struct sdmmc_config *cfg = dev->config; + struct sdmmc_data *data = dev->data; + int ret; + + if (data->status == SD_OK) { + /* Called twice, don't reinit */ + return 0; + } + + if (!sd_is_card_present(cfg->host_controller)) { + return DISK_STATUS_NOMEDIA; + } + + ret = sd_init(cfg->host_controller, &data->card); + if (ret) { + data->status = SD_ERROR; + return ret; + } + data->status = SD_OK; + return 0; +} + +static int disk_sdmmc_access_status(struct disk_info *disk) +{ + const struct device *dev = disk->dev; + const struct sdmmc_config *cfg = dev->config; + struct sdmmc_data *data = dev->data; + + if (!sd_is_card_present(cfg->host_controller)) { + return DISK_STATUS_NOMEDIA; + } + if (data->status == SD_OK) { + return DISK_STATUS_OK; + } else { + return DISK_STATUS_UNINIT; + } +} + +static int disk_sdmmc_access_read(struct disk_info *disk, uint8_t *buf, + uint32_t sector, uint32_t count) +{ + const struct device *dev = disk->dev; + struct sdmmc_data *data = dev->data; + + return sdmmc_read_blocks(&data->card, buf, sector, count); +} + +static int disk_sdmmc_access_write(struct disk_info *disk, const uint8_t *buf, + uint32_t sector, uint32_t count) +{ + const struct device *dev = disk->dev; + struct sdmmc_data *data = dev->data; + + return sdmmc_write_blocks(&data->card, buf, sector, count); +} + +static int disk_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf) +{ + const struct device *dev = disk->dev; + struct sdmmc_data *data = dev->data; + + return sdmmc_ioctl(&data->card, cmd, buf); +} + +static const struct disk_operations sdmmc_disk_ops = { + .init = disk_sdmmc_access_init, + .status = disk_sdmmc_access_status, + .read = disk_sdmmc_access_read, + .write = disk_sdmmc_access_write, + .ioctl = disk_sdmmc_access_ioctl, +}; + +static struct disk_info sdmmc_disk = { + .ops = &sdmmc_disk_ops, +}; + +static int disk_sdmmc_init(const struct device *dev) +{ + struct sdmmc_data *data = dev->data; + + data->status = SD_UNINIT; + sdmmc_disk.dev = dev; + sdmmc_disk.name = data->name; + + return disk_access_register(&sdmmc_disk); +} + +#define DISK_ACCESS_SDMMC_INIT(n) \ + static const struct sdmmc_config sdmmc_config_##n = { \ + .host_controller = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + }; \ + \ + static struct sdmmc_data sdmmc_data_##n = { \ + .name = CONFIG_SDMMC_VOLUME_NAME, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + &disk_sdmmc_init, \ + NULL, \ + &sdmmc_data_##n, \ + &sdmmc_config_##n, \ + POST_KERNEL, \ + CONFIG_SDMMC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(DISK_ACCESS_SDMMC_INIT)