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