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 	char *name;
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 (data->status == SD_OK) {
41 		/* Called twice, don't reinit */
42 		return 0;
43 	}
44 
45 	if (!sd_is_card_present(cfg->host_controller)) {
46 		return DISK_STATUS_NOMEDIA;
47 	}
48 
49 	ret = sd_init(cfg->host_controller, &data->card);
50 	if (ret) {
51 		data->status = SD_ERROR;
52 		return ret;
53 	}
54 	data->status = SD_OK;
55 	return 0;
56 }
57 
disk_sdmmc_access_status(struct disk_info * disk)58 static int disk_sdmmc_access_status(struct disk_info *disk)
59 {
60 	const struct device *dev = disk->dev;
61 	const struct sdmmc_config *cfg = dev->config;
62 	struct sdmmc_data *data = dev->data;
63 
64 	if (!sd_is_card_present(cfg->host_controller)) {
65 		return DISK_STATUS_NOMEDIA;
66 	}
67 	if (data->status == SD_OK) {
68 		return DISK_STATUS_OK;
69 	} else {
70 		return DISK_STATUS_UNINIT;
71 	}
72 }
73 
disk_sdmmc_access_read(struct disk_info * disk,uint8_t * buf,uint32_t sector,uint32_t count)74 static int disk_sdmmc_access_read(struct disk_info *disk, uint8_t *buf,
75 				 uint32_t sector, uint32_t count)
76 {
77 	const struct device *dev = disk->dev;
78 	struct sdmmc_data *data = dev->data;
79 
80 	return sdmmc_read_blocks(&data->card, buf, sector, count);
81 }
82 
disk_sdmmc_access_write(struct disk_info * disk,const uint8_t * buf,uint32_t sector,uint32_t count)83 static int disk_sdmmc_access_write(struct disk_info *disk, const uint8_t *buf,
84 				 uint32_t sector, uint32_t count)
85 {
86 	const struct device *dev = disk->dev;
87 	struct sdmmc_data *data = dev->data;
88 
89 	return sdmmc_write_blocks(&data->card, buf, sector, count);
90 }
91 
disk_sdmmc_access_ioctl(struct disk_info * disk,uint8_t cmd,void * buf)92 static int disk_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf)
93 {
94 	const struct device *dev = disk->dev;
95 	struct sdmmc_data *data = dev->data;
96 
97 	return sdmmc_ioctl(&data->card, cmd, buf);
98 }
99 
100 static const struct disk_operations sdmmc_disk_ops = {
101 	.init = disk_sdmmc_access_init,
102 	.status = disk_sdmmc_access_status,
103 	.read = disk_sdmmc_access_read,
104 	.write = disk_sdmmc_access_write,
105 	.ioctl = disk_sdmmc_access_ioctl,
106 };
107 
108 static struct disk_info sdmmc_disk = {
109 	.ops = &sdmmc_disk_ops,
110 };
111 
disk_sdmmc_init(const struct device * dev)112 static int disk_sdmmc_init(const struct device *dev)
113 {
114 	struct sdmmc_data *data = dev->data;
115 
116 	data->status = SD_UNINIT;
117 	sdmmc_disk.dev = dev;
118 	sdmmc_disk.name = data->name;
119 
120 	return disk_access_register(&sdmmc_disk);
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 sdmmc_data sdmmc_data_##n = {				\
129 		.name = CONFIG_SDMMC_VOLUME_NAME,				\
130 	};									\
131 										\
132 	DEVICE_DT_INST_DEFINE(n,						\
133 			&disk_sdmmc_init,					\
134 			NULL,							\
135 			&sdmmc_data_##n,					\
136 			&sdmmc_config_##n,					\
137 			POST_KERNEL,						\
138 			CONFIG_SD_INIT_PRIORITY,				\
139 			NULL);
140 
141 DT_INST_FOREACH_STATUS_OKAY(DISK_ACCESS_SDMMC_INIT)
142