1 /*
2 * Copyright (c) 2024 Analog Devices, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT adi_max32_sdhc
8
9 #include <errno.h>
10 #include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
11 #include <zephyr/drivers/sdhc.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/sys/util_macro.h>
14 #include <wrap_max32_sdhc.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/kernel.h>
17
18 LOG_MODULE_REGISTER(sdhc_max32, CONFIG_SDHC_LOG_LEVEL);
19
20 static int cmd_opcode_converter(int opcode, unsigned int *cmd);
21 static int convert_freq_to_divider(int freq);
22
23 /* **** Definitions ****
24 * todo: added from sdhc_resp_regs.h cmd51 is mandatory and is missing in msdk.
25 * SDHC commands and associated cmd register bits which inform hardware to wait for response, etc.
26 */
27 #define MXC_SDHC_LIB_CMD0 0x0000
28 #define MXC_SDHC_LIB_CMD1 0x0102
29 #define MXC_SDHC_LIB_CMD2 0x0209
30 #define MXC_SDHC_LIB_CMD3 0x031A
31 #define MXC_SDHC_LIB_CMD4 0x0400
32 #define MXC_SDHC_LIB_CMD5 0x051A
33 #define MXC_SDHC_LIB_CMD6 0x060A
34 #define MXC_SDHC_LIB_CMD7 0x071B
35 #define MXC_SDHC_LIB_CMD8 0x081A
36 #define MXC_SDHC_LIB_CMD9 0x0901
37 #define MXC_SDHC_LIB_CMD10 0x0A01
38 #define MXC_SDHC_LIB_CMD11 0x0B1A
39 #define MXC_SDHC_LIB_CMD12 0x0C1B
40 #define MXC_SDHC_LIB_CMD13 0x0D1A
41 #define MXC_SDHC_LIB_CMD16 0x101A
42 #define MXC_SDHC_LIB_CMD17 0x113A
43 #define MXC_SDHC_LIB_CMD18 0x123A
44 #define MXC_SDHC_LIB_CMD23 0x171A
45 #define MXC_SDHC_LIB_CMD24 0x183E
46 #define MXC_SDHC_LIB_CMD25 0x193E
47 #define MXC_SDHC_LIB_CMD55 0x371A
48
49 /* Application commands (SD Card) which are prefixed by CMD55 */
50 #define MXC_SDHC_LIB_ACMD6 0x061B
51 #define MXC_SDHC_LIB_ACMD41 0x2902
52 #define MXC_SDHC_LIB_ACMD51 0x331B
53
54 /* todo: GCR dependent division might be 4 as well. if set to = 1 sdhcfrq. add support in msdk */
55 #define SDHC_CLOCK (ADI_MAX32_CLK_IPO_FREQ / 2)
56
57 #define SDHC_SDHC_MAX_DIV_VAL 0x3FF
58 #define SDHC_SDHC_PCLK_DIV 2
59
60 /* todo: cmd.arg = SD_IF_COND_VHS_3V3 | check_pattern;
61 * todo: zephyr always configures response types. msdk needs to support this as well.
62 * todo: add host io support
63 */
64
65 struct sdhc_max32_data {
66 struct sdhc_host_props props;
67 };
68
69 /* SDHC configuration. */
70 struct sdhc_max32_config {
71 void (*irq_func)(void);
72 const struct pinctrl_dev_config *pcfg;
73 unsigned int power_delay_ms;
74 unsigned int bus_volt;
75 const struct device *clock;
76 struct max32_perclk perclk;
77 };
78
sdhc_max32_init_props(const struct device * dev)79 static void sdhc_max32_init_props(const struct device *dev)
80 {
81 struct sdhc_max32_data *sdhc_data = dev->data;
82 const struct sdhc_max32_config *sdhc_config = dev->config;
83
84 memset(sdhc_data, 0, sizeof(struct sdhc_max32_data));
85
86 sdhc_data->props.f_min = SDHC_CLOCK / (SDHC_SDHC_PCLK_DIV * SDHC_SDHC_MAX_DIV_VAL);
87 sdhc_data->props.f_max = SDHC_CLOCK;
88 sdhc_data->props.is_spi = 0;
89 sdhc_data->props.max_current_180 = 0;
90 sdhc_data->props.max_current_300 = 0;
91 sdhc_data->props.max_current_330 = 0;
92 sdhc_data->props.host_caps.timeout_clk_freq = 0x01;
93 sdhc_data->props.host_caps.timeout_clk_unit = 1;
94 sdhc_data->props.host_caps.sd_base_clk = 0x00;
95 sdhc_data->props.host_caps.max_blk_len = 0b10;
96 sdhc_data->props.host_caps.bus_8_bit_support = false;
97 sdhc_data->props.host_caps.bus_4_bit_support = false;
98 sdhc_data->props.host_caps.adma_2_support = true;
99 sdhc_data->props.host_caps.high_spd_support = true;
100 sdhc_data->props.host_caps.sdma_support = true;
101 sdhc_data->props.host_caps.suspend_res_support = true;
102 sdhc_data->props.host_caps.vol_330_support = true;
103 sdhc_data->props.host_caps.vol_300_support = false;
104 sdhc_data->props.host_caps.vol_180_support = false;
105 sdhc_data->props.host_caps.address_64_bit_support_v4 = false;
106 sdhc_data->props.host_caps.address_64_bit_support_v3 = false;
107 sdhc_data->props.host_caps.sdio_async_interrupt_support = true;
108 sdhc_data->props.host_caps.slot_type = 00;
109 sdhc_data->props.host_caps.sdr50_support = true;
110 sdhc_data->props.host_caps.sdr104_support = true;
111 sdhc_data->props.host_caps.ddr50_support = true;
112 sdhc_data->props.host_caps.uhs_2_support = false;
113 sdhc_data->props.host_caps.drv_type_a_support = true;
114 sdhc_data->props.host_caps.drv_type_c_support = true;
115 sdhc_data->props.host_caps.drv_type_d_support = true;
116 sdhc_data->props.host_caps.retune_timer_count = 0;
117 sdhc_data->props.host_caps.sdr50_needs_tuning = 0;
118 sdhc_data->props.host_caps.retuning_mode = 0;
119 sdhc_data->props.host_caps.clk_multiplier = 0;
120 sdhc_data->props.host_caps.adma3_support = false;
121 sdhc_data->props.host_caps.vdd2_180_support = false;
122 sdhc_data->props.host_caps.hs200_support = false;
123 sdhc_data->props.host_caps.hs400_support = false;
124 sdhc_data->props.power_delay = sdhc_config->power_delay_ms;
125 }
126
sdhc_max32_init(const struct device * dev)127 static int sdhc_max32_init(const struct device *dev)
128 {
129 const struct sdhc_max32_config *sdhc_config = dev->config;
130 int ret = 0;
131 mxc_sdhc_cfg_t cfg;
132
133 ret = pinctrl_apply_state(sdhc_config->pcfg, PINCTRL_STATE_DEFAULT);
134 if (ret < 0) {
135 LOG_ERR("Pinctrl apply error:%d", ret);
136 return ret;
137 }
138
139 ret = clock_control_on(sdhc_config->clock, (clock_control_subsys_t)&sdhc_config->perclk);
140 if (ret) {
141 LOG_ERR("Clock control on error:%d", ret);
142 return ret;
143 }
144
145 cfg.bus_voltage = MXC_SDHC_Bus_Voltage_3_3;
146 cfg.block_gap = 0;
147 /* Maximum divide ratio, frequency must be 100 - 400 kHz during Card Identification"*/
148 cfg.clk_div = SDHC_SDHC_MAX_DIV_VAL;
149
150 ret = MXC_SDHC_Init(&cfg);
151 if (ret != E_NO_ERROR) {
152 LOG_ERR("MXC_SDHC_Init error:%d", ret);
153 return ret;
154 }
155
156 /* note: init delay, without it applications fail. 5ms found empirically.
157 * todo: investigate why fails, see if it can be removed via polling a register bit etc.
158 */
159 k_sleep(K_MSEC(5));
160
161 sdhc_max32_init_props(dev);
162
163 return 0;
164 }
165
sdhc_max32_card_busy(const struct device * dev)166 static int sdhc_max32_card_busy(const struct device *dev)
167 {
168 int ret = 0;
169
170 ret = MXC_SDHC_Card_Busy();
171
172 return ret;
173 }
174
sdhc_max32_reset(const struct device * dev)175 static int sdhc_max32_reset(const struct device *dev)
176 {
177 MXC_SDHC_Reset();
178
179 return 0;
180 }
181
sdhc_max32_request(const struct device * dev,struct sdhc_command * cmd,struct sdhc_data * data)182 static int sdhc_max32_request(const struct device *dev, struct sdhc_command *cmd,
183 struct sdhc_data *data)
184 {
185 int ret = 0;
186 unsigned int mxc_cmd = 0;
187 mxc_sdhc_cmd_cfg_t sd_cmd_cfg;
188 bool card_size_workaround = false;
189
190 if (data) {
191 sd_cmd_cfg.sdma = (unsigned int)data->data;
192 sd_cmd_cfg.block_size = data->block_size;
193 sd_cmd_cfg.block_count = data->blocks;
194 }
195
196 sd_cmd_cfg.arg_1 = cmd->arg;
197 sd_cmd_cfg.dma = true; /* todo: add config depending on config_dma etc. */
198
199 switch (cmd->opcode) {
200 case SD_READ_SINGLE_BLOCK:
201 case SD_READ_MULTIPLE_BLOCK:
202 sd_cmd_cfg.direction = MXC_SDHC_DIRECTION_READ;
203 sd_cmd_cfg.arg_1 = data->block_addr;
204 break;
205 case SD_WRITE_SINGLE_BLOCK:
206 case SD_WRITE_MULTIPLE_BLOCK:
207 sd_cmd_cfg.direction = MXC_SDHC_DIRECTION_WRITE;
208 sd_cmd_cfg.arg_1 = data->block_addr;
209 break;
210 case SD_SEND_CSD:
211 card_size_workaround = true;
212 default:
213 sd_cmd_cfg.direction = MXC_SDHC_DIRECTION_CFG;
214 break;
215 }
216
217 ret = cmd_opcode_converter(cmd->opcode, &mxc_cmd);
218 if (ret) {
219 return ret;
220 }
221 sd_cmd_cfg.command = mxc_cmd;
222 sd_cmd_cfg.host_control_1 = MXC_SDHC_Get_Host_Cn_1();
223 sd_cmd_cfg.callback = NULL;
224
225 /*
226 * todo: this was also needed, otherwise applications failed randomly. it would be good to
227 * remove this with a better solution in future.
228 */
229 k_sleep(K_MSEC(1));
230 ret = MXC_SDHC_SendCommand(&sd_cmd_cfg);
231 if (ret) {
232 LOG_ERR("MXC_SDHC_SendCommand error:%d, SD opcode: %d", ret, cmd->opcode);
233 return ret;
234 }
235
236 MXC_SDHC_Get_Response128((char *)(cmd->response));
237
238 if (card_size_workaround) {
239 /*
240 * this workaround is required for only CMD9. This fixes size problem. Otherwise
241 * it doesn't give the correct device size information.
242 */
243 cmd->response[1] <<= 8;
244 cmd->response[3] <<= 8;
245 }
246
247 return 0;
248 }
249
sdhc_max32_get_card_present(const struct device * dev)250 static int sdhc_max32_get_card_present(const struct device *dev)
251 {
252 return MXC_SDHC_Card_Inserted();
253 }
254
sdhc_max32_get_host_props(const struct device * dev,struct sdhc_host_props * props)255 static int sdhc_max32_get_host_props(const struct device *dev, struct sdhc_host_props *props)
256 {
257 struct sdhc_max32_data *sdhc_data = dev->data;
258
259 memcpy(props, &sdhc_data->props, sizeof(struct sdhc_host_props));
260
261 return 0;
262 }
263
sdhc_max32_set_io(const struct device * dev,struct sdhc_io * ios)264 static int sdhc_max32_set_io(const struct device *dev, struct sdhc_io *ios)
265 {
266 struct sdhc_max32_data *data = dev->data;
267 struct sdhc_host_props *props = &data->props;
268 enum sdhc_clock_speed speed = ios->clock;
269 unsigned int clk_div = 0;
270
271 if (speed) {
272 if (speed < props->f_min || speed > props->f_max) {
273 LOG_ERR("Speed range error %d", speed);
274 return -ENOTSUP;
275 }
276 clk_div = convert_freq_to_divider(speed);
277 MXC_SDHC_Set_Clock_Config(clk_div);
278 }
279
280 if (ios->power_mode == SDHC_POWER_OFF) {
281 MXC_SDHC_PowerDown();
282 } else {
283 MXC_SDHC_PowerUp();
284 }
285
286 return 0;
287 }
288
289 static DEVICE_API(sdhc, sdhc_max32_driver_api) = {
290 .reset = sdhc_max32_reset,
291 .request = sdhc_max32_request,
292 .set_io = sdhc_max32_set_io,
293 .get_card_present = sdhc_max32_get_card_present,
294 .card_busy = sdhc_max32_card_busy,
295 .get_host_props = sdhc_max32_get_host_props,
296 .enable_interrupt = NULL,
297 .disable_interrupt = NULL,
298 .execute_tuning = NULL,
299 };
300
cmd_opcode_converter(int opcode,unsigned int * cmd)301 static int cmd_opcode_converter(int opcode, unsigned int *cmd)
302 {
303 switch (opcode) {
304 case SD_GO_IDLE_STATE:
305 *cmd = MXC_SDHC_LIB_CMD0;
306 break;
307 case MMC_SEND_OP_COND:
308 *cmd = MXC_SDHC_LIB_CMD1;
309 break;
310 case SD_ALL_SEND_CID:
311 *cmd = MXC_SDHC_LIB_CMD2;
312 break;
313 case SD_SEND_RELATIVE_ADDR:
314 *cmd = MXC_SDHC_LIB_CMD3;
315 break;
316 case SDIO_SEND_OP_COND:
317 *cmd = MXC_SDHC_LIB_CMD5;
318 break;
319 case SD_SWITCH:
320 *cmd = MXC_SDHC_LIB_CMD6;
321 break;
322 case SD_SELECT_CARD:
323 *cmd = MXC_SDHC_LIB_CMD7;
324 break;
325 case SD_SEND_IF_COND:
326 *cmd = MXC_SDHC_LIB_CMD8;
327 break;
328 case SD_SEND_CSD:
329 *cmd = MXC_SDHC_LIB_CMD9;
330 break;
331 case SD_SEND_CID:
332 *cmd = MXC_SDHC_LIB_CMD10;
333 break;
334 case SD_VOL_SWITCH:
335 *cmd = MXC_SDHC_LIB_CMD11;
336 break;
337 case SD_STOP_TRANSMISSION:
338 *cmd = MXC_SDHC_LIB_CMD12;
339 break;
340 case SD_SEND_STATUS:
341 *cmd = MXC_SDHC_LIB_CMD13;
342 break;
343 case SD_SET_BLOCK_SIZE:
344 *cmd = MXC_SDHC_LIB_CMD16;
345 break;
346 case SD_READ_SINGLE_BLOCK:
347 *cmd = MXC_SDHC_LIB_CMD17;
348 break;
349 case SD_READ_MULTIPLE_BLOCK:
350 *cmd = MXC_SDHC_LIB_CMD18;
351 break;
352 case SD_SET_BLOCK_COUNT:
353 *cmd = MXC_SDHC_LIB_CMD23;
354 break;
355 case SD_WRITE_SINGLE_BLOCK:
356 *cmd = MXC_SDHC_LIB_CMD24;
357 break;
358 case SD_WRITE_MULTIPLE_BLOCK:
359 *cmd = MXC_SDHC_LIB_CMD25;
360 break;
361 case SD_APP_CMD:
362 *cmd = MXC_SDHC_LIB_CMD55;
363 break;
364 case SD_APP_SEND_OP_COND:
365 *cmd = MXC_SDHC_LIB_ACMD41;
366 break;
367 case SD_APP_SEND_SCR:
368 *cmd = MXC_SDHC_LIB_ACMD51;
369 break;
370 /* todo: below are not defined in msdk, support might be added later */
371 case SD_ERASE_BLOCK_START:
372 case SD_ERASE_BLOCK_END:
373 case SD_ERASE_BLOCK_OPERATION:
374 case SDIO_RW_DIRECT:
375 case SD_SEND_TUNING_BLOCK:
376 case SD_GO_INACTIVE_STATE:
377 case SDIO_RW_EXTENDED:
378 default:
379 LOG_ERR("Opcode convert error %d", opcode);
380 return -EINVAL;
381 }
382
383 return 0;
384 }
385
convert_freq_to_divider(int freq)386 static int convert_freq_to_divider(int freq)
387 {
388 if (!freq) {
389 return 0;
390 }
391
392 int divider = 0;
393 /* note: this causes a bit different speed than exact number. */
394 divider = SDHC_CLOCK / (2 * freq);
395
396 return divider;
397 }
398
399 #define DEFINE_SDHC_MAX32(_num) \
400 PINCTRL_DT_INST_DEFINE(_num); \
401 static struct sdhc_max32_data sdhc_max32_data_##_num; \
402 static const struct sdhc_max32_config sdhc_max32_config_##_num = { \
403 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(_num), \
404 .power_delay_ms = DT_INST_PROP(_num, power_delay_ms), \
405 .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(_num)), \
406 .perclk.bus = DT_INST_CLOCKS_CELL(_num, offset), \
407 .perclk.bit = DT_INST_CLOCKS_CELL(_num, bit), \
408 }; \
409 DEVICE_DT_INST_DEFINE(_num, sdhc_max32_init, NULL, &sdhc_max32_data_##_num, \
410 &sdhc_max32_config_##_num, POST_KERNEL, 2, &sdhc_max32_driver_api);
411
412 DT_INST_FOREACH_STATUS_OKAY(DEFINE_SDHC_MAX32)
413