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 };
25
26 struct sdmmc_data {
27 struct sd_card card;
28 enum sd_status status;
29 struct disk_info *disk_info;
30 };
31
32
disk_sdmmc_access_init(struct disk_info * disk)33 static int disk_sdmmc_access_init(struct disk_info *disk)
34 {
35 const struct device *dev = disk->dev;
36 const struct sdmmc_config *cfg = dev->config;
37 struct sdmmc_data *data = dev->data;
38 int ret;
39
40 if (!sd_is_card_present(cfg->host_controller)) {
41 return DISK_STATUS_NOMEDIA;
42 }
43
44 ret = sd_init(cfg->host_controller, &data->card);
45 if (ret) {
46 data->status = SD_ERROR;
47 return ret;
48 }
49 data->status = SD_OK;
50 return 0;
51 }
52
disk_sdmmc_access_status(struct disk_info * disk)53 static int disk_sdmmc_access_status(struct disk_info *disk)
54 {
55 const struct device *dev = disk->dev;
56 const struct sdmmc_config *cfg = dev->config;
57 struct sdmmc_data *data = dev->data;
58
59 if (!sd_is_card_present(cfg->host_controller)) {
60 return DISK_STATUS_NOMEDIA;
61 }
62 if (data->status == SD_OK) {
63 return DISK_STATUS_OK;
64 } else {
65 return DISK_STATUS_UNINIT;
66 }
67 }
68
disk_sdmmc_access_read(struct disk_info * disk,uint8_t * buf,uint32_t sector,uint32_t count)69 static int disk_sdmmc_access_read(struct disk_info *disk, uint8_t *buf,
70 uint32_t sector, uint32_t count)
71 {
72 const struct device *dev = disk->dev;
73 struct sdmmc_data *data = dev->data;
74
75 return sdmmc_read_blocks(&data->card, buf, sector, count);
76 }
77
disk_sdmmc_access_write(struct disk_info * disk,const uint8_t * buf,uint32_t sector,uint32_t count)78 static int disk_sdmmc_access_write(struct disk_info *disk, const uint8_t *buf,
79 uint32_t sector, uint32_t count)
80 {
81 const struct device *dev = disk->dev;
82 struct sdmmc_data *data = dev->data;
83
84 return sdmmc_write_blocks(&data->card, buf, sector, count);
85 }
86
disk_sdmmc_access_ioctl(struct disk_info * disk,uint8_t cmd,void * buf)87 static int disk_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf)
88 {
89 const struct device *dev = disk->dev;
90 struct sdmmc_data *data = dev->data;
91
92 switch (cmd) {
93 case DISK_IOCTL_CTRL_INIT:
94 return disk_sdmmc_access_init(disk);
95 case DISK_IOCTL_CTRL_DEINIT:
96 /* Card will be uninitialized after DEINIT */
97 data->status = SD_UNINIT;
98 return sdmmc_ioctl(&data->card, DISK_IOCTL_CTRL_DEINIT, NULL);
99 default:
100 return sdmmc_ioctl(&data->card, cmd, buf);
101 }
102
103 return 0;
104 }
105
106 static const struct disk_operations sdmmc_disk_ops = {
107 .init = disk_sdmmc_access_init,
108 .status = disk_sdmmc_access_status,
109 .read = disk_sdmmc_access_read,
110 .write = disk_sdmmc_access_write,
111 .ioctl = disk_sdmmc_access_ioctl,
112 };
113
disk_sdmmc_init(const struct device * dev)114 static int disk_sdmmc_init(const struct device *dev)
115 {
116 struct sdmmc_data *data = dev->data;
117
118 data->status = SD_UNINIT;
119
120 return disk_access_register(data->disk_info);
121 }
122
123 #define DISK_ACCESS_SDMMC_INIT(n) \
124 static const struct sdmmc_config sdmmc_config_##n = { \
125 .host_controller = DEVICE_DT_GET(DT_INST_PARENT(n)), \
126 }; \
127 \
128 static struct disk_info sdmmc_disk_##n = { \
129 .name = DT_INST_PROP(n, disk_name), \
130 .ops = &sdmmc_disk_ops, \
131 .dev = DEVICE_DT_INST_GET(n), \
132 }; \
133 \
134 static struct sdmmc_data sdmmc_data_##n = { \
135 .disk_info = &sdmmc_disk_##n, \
136 }; \
137 \
138 DEVICE_DT_INST_DEFINE(n, \
139 &disk_sdmmc_init, \
140 NULL, \
141 &sdmmc_data_##n, \
142 &sdmmc_config_##n, \
143 POST_KERNEL, \
144 CONFIG_SD_INIT_PRIORITY, \
145 NULL);
146
147 DT_INST_FOREACH_STATUS_OKAY(DISK_ACCESS_SDMMC_INIT)
148