1 /*
2 * Copyright 2022 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * MMC disk driver using zephyr SD subsystem
9 */
10 #define DT_DRV_COMPAT zephyr_mmc_disk
11
12 #include <zephyr/sd/mmc.h>
13 #include <zephyr/drivers/disk.h>
14
15
16 enum sd_status {
17 SD_UNINIT,
18 SD_ERROR,
19 SD_OK,
20 };
21
22 struct mmc_config {
23 const struct device *host_controller;
24 };
25
26 struct mmc_data {
27 struct sd_card card;
28 enum sd_status status;
29 char *name;
30 };
31
32
disk_mmc_access_init(struct disk_info * disk)33 static int disk_mmc_access_init(struct disk_info *disk)
34 {
35 const struct device *dev = disk->dev;
36 const struct mmc_config *cfg = dev->config;
37 struct mmc_data *data = dev->data;
38 int ret;
39
40 if (data->status == SD_OK) {
41 /* Called twice, don't reinit */
42 return 0;
43 }
44
45 ret = sd_init(cfg->host_controller, &data->card);
46 if (ret) {
47 data->status = SD_ERROR;
48 return ret;
49 }
50 data->status = SD_OK;
51 return 0;
52 }
53
disk_mmc_access_status(struct disk_info * disk)54 static int disk_mmc_access_status(struct disk_info *disk)
55 {
56 const struct device *dev = disk->dev;
57 struct mmc_data *data = dev->data;
58
59 if (data->status == SD_OK) {
60 return DISK_STATUS_OK;
61 } else {
62 return DISK_STATUS_UNINIT;
63 }
64 }
65
disk_mmc_access_read(struct disk_info * disk,uint8_t * buf,uint32_t sector,uint32_t count)66 static int disk_mmc_access_read(struct disk_info *disk, uint8_t *buf,
67 uint32_t sector, uint32_t count)
68 {
69 const struct device *dev = disk->dev;
70 struct mmc_data *data = dev->data;
71
72 return mmc_read_blocks(&data->card, buf, sector, count);
73 }
74
disk_mmc_access_write(struct disk_info * disk,const uint8_t * buf,uint32_t sector,uint32_t count)75 static int disk_mmc_access_write(struct disk_info *disk, const uint8_t *buf,
76 uint32_t sector, uint32_t count)
77 {
78 const struct device *dev = disk->dev;
79 struct mmc_data *data = dev->data;
80
81 return mmc_write_blocks(&data->card, buf, sector, count);
82 }
83
disk_mmc_access_ioctl(struct disk_info * disk,uint8_t cmd,void * buf)84 static int disk_mmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf)
85 {
86 const struct device *dev = disk->dev;
87 struct mmc_data *data = dev->data;
88
89 return mmc_ioctl(&data->card, cmd, buf);
90 }
91
92 static const struct disk_operations mmc_disk_ops = {
93 .init = disk_mmc_access_init,
94 .status = disk_mmc_access_status,
95 .read = disk_mmc_access_read,
96 .write = disk_mmc_access_write,
97 .ioctl = disk_mmc_access_ioctl,
98 };
99
100 static struct disk_info mmc_disk = {
101 .ops = &mmc_disk_ops,
102 };
103
disk_mmc_init(const struct device * dev)104 static int disk_mmc_init(const struct device *dev)
105 {
106 struct mmc_data *data = dev->data;
107
108 data->status = SD_UNINIT;
109 mmc_disk.dev = dev;
110 mmc_disk.name = data->name;
111
112 return disk_access_register(&mmc_disk);
113 }
114
115 #define DISK_ACCESS_MMC_INIT(n) \
116 static const struct mmc_config mmc_config_##n = { \
117 .host_controller = DEVICE_DT_GET(DT_INST_PARENT(n)), \
118 }; \
119 \
120 static struct mmc_data mmc_data_##n = { \
121 .name = CONFIG_MMC_VOLUME_NAME, \
122 }; \
123 \
124 DEVICE_DT_INST_DEFINE(n, \
125 &disk_mmc_init, \
126 NULL, \
127 &mmc_data_##n, \
128 &mmc_config_##n, \
129 POST_KERNEL, \
130 CONFIG_SD_INIT_PRIORITY, \
131 NULL);
132
133 DT_INST_FOREACH_STATUS_OKAY(DISK_ACCESS_MMC_INIT)
134