1 /*
2 * Copyright 2022 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * SDMMC disk driver using zephyr SD subsystem
9 */
10 #define DT_DRV_COMPAT zephyr_sdmmc_disk
11
12 #include <zephyr/sd/sdmmc.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 sdmmc_config {
23 const struct device *host_controller;
24 const char *name;
25 };
26
27 struct sdmmc_data {
28 struct sd_card card;
29 enum sd_status status;
30 struct disk_info disk_info;
31 };
32
33
disk_sdmmc_access_init(struct disk_info * disk)34 static int disk_sdmmc_access_init(struct disk_info *disk)
35 {
36 const struct device *dev = disk->dev;
37 const struct sdmmc_config *cfg = dev->config;
38 struct sdmmc_data *data = dev->data;
39 int ret;
40
41 if (!sd_is_card_present(cfg->host_controller)) {
42 return DISK_STATUS_NOMEDIA;
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_sdmmc_access_status(struct disk_info * disk)54 static int disk_sdmmc_access_status(struct disk_info *disk)
55 {
56 const struct device *dev = disk->dev;
57 const struct sdmmc_config *cfg = dev->config;
58 struct sdmmc_data *data = dev->data;
59
60 if (!sd_is_card_present(cfg->host_controller)) {
61 return DISK_STATUS_NOMEDIA;
62 }
63 if (data->status == SD_OK) {
64 return DISK_STATUS_OK;
65 } else {
66 return DISK_STATUS_UNINIT;
67 }
68 }
69
disk_sdmmc_access_read(struct disk_info * disk,uint8_t * buf,uint32_t sector,uint32_t count)70 static int disk_sdmmc_access_read(struct disk_info *disk, uint8_t *buf,
71 uint32_t sector, uint32_t count)
72 {
73 const struct device *dev = disk->dev;
74 struct sdmmc_data *data = dev->data;
75
76 return sdmmc_read_blocks(&data->card, buf, sector, count);
77 }
78
disk_sdmmc_access_write(struct disk_info * disk,const uint8_t * buf,uint32_t sector,uint32_t count)79 static int disk_sdmmc_access_write(struct disk_info *disk, const uint8_t *buf,
80 uint32_t sector, uint32_t count)
81 {
82 const struct device *dev = disk->dev;
83 struct sdmmc_data *data = dev->data;
84
85 return sdmmc_write_blocks(&data->card, buf, sector, count);
86 }
87
disk_sdmmc_access_erase(struct disk_info * disk,uint32_t sector,uint32_t count)88 static int disk_sdmmc_access_erase(struct disk_info *disk, uint32_t sector, uint32_t count)
89 {
90 const struct device *dev = disk->dev;
91 struct sdmmc_data *data = dev->data;
92
93 return sdmmc_erase_blocks(&data->card, sector, count);
94 }
95
disk_sdmmc_access_ioctl(struct disk_info * disk,uint8_t cmd,void * buf)96 static int disk_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf)
97 {
98 const struct device *dev = disk->dev;
99 struct sdmmc_data *data = dev->data;
100
101 switch (cmd) {
102 case DISK_IOCTL_CTRL_INIT:
103 return disk_sdmmc_access_init(disk);
104 case DISK_IOCTL_CTRL_DEINIT:
105 /* Card will be uninitialized after DEINIT */
106 data->status = SD_UNINIT;
107 return sdmmc_ioctl(&data->card, DISK_IOCTL_CTRL_DEINIT, NULL);
108 default:
109 return sdmmc_ioctl(&data->card, cmd, buf);
110 }
111
112 return 0;
113 }
114
115 static const struct disk_operations sdmmc_disk_ops = {
116 .init = disk_sdmmc_access_init,
117 .status = disk_sdmmc_access_status,
118 .read = disk_sdmmc_access_read,
119 .write = disk_sdmmc_access_write,
120 .erase = disk_sdmmc_access_erase,
121 .ioctl = disk_sdmmc_access_ioctl,
122 };
123
disk_sdmmc_init(const struct device * dev)124 static int disk_sdmmc_init(const struct device *dev)
125 {
126 const struct sdmmc_config *config = dev->config;
127 struct sdmmc_data *data = dev->data;
128
129 data->status = SD_UNINIT;
130 data->disk_info.name = config->name;
131 data->disk_info.ops = &sdmmc_disk_ops;
132 data->disk_info.dev = dev;
133
134 return disk_access_register(&data->disk_info);
135 }
136
137 #define DISK_ACCESS_SDMMC_INIT(n) \
138 static const struct sdmmc_config sdmmc_config_##n = { \
139 .host_controller = DEVICE_DT_GET(DT_INST_PARENT(n)), \
140 .name = DT_INST_PROP(n, disk_name), \
141 }; \
142 \
143 static struct sdmmc_data sdmmc_data_##n; \
144 \
145 DEVICE_DT_INST_DEFINE(n, \
146 &disk_sdmmc_init, \
147 NULL, \
148 &sdmmc_data_##n, \
149 &sdmmc_config_##n, \
150 POST_KERNEL, \
151 CONFIG_SD_INIT_PRIORITY, \
152 NULL);
153
154 DT_INST_FOREACH_STATUS_OKAY(DISK_ACCESS_SDMMC_INIT)
155