/* * Copyright 2022,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT zephyr_sdhc_spi_slot #include #include #include #include #include #include LOG_MODULE_REGISTER(sdhc_spi, CONFIG_SDHC_LOG_LEVEL); #define MAX_CMD_READ 21 #define SPI_R1B_TIMEOUT_MS 3000 #define SD_SPI_SKIP_RETRIES 1000000 /* The SD protocol requires sending ones while reading but Zephyr * defaults to writing zeros. This block of 512 bytes is used for writing * 0xff while we read data blocks. Should remain const so this buffer is * stored in flash. */ static const uint8_t sdhc_ones[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; BUILD_ASSERT(sizeof(sdhc_ones) == 512, "0xFF array for SDHC must be 512 bytes"); struct sdhc_spi_config { const struct device *spi_dev; const struct gpio_dt_spec pwr_gpio; const uint32_t spi_max_freq; uint32_t power_delay_ms; }; struct sdhc_spi_data { enum sdhc_power power_mode; struct spi_config *spi_cfg; struct spi_config cfg_a; struct spi_config cfg_b; uint8_t scratch[MAX_CMD_READ]; }; /* Receives a block of bytes */ static int sdhc_spi_rx(const struct device *spi_dev, struct spi_config *spi_cfg, uint8_t *buf, int len) { struct spi_buf tx_bufs[] = { { .buf = (uint8_t *)sdhc_ones, .len = len } }; const struct spi_buf_set tx = { .buffers = tx_bufs, .count = 1, }; struct spi_buf rx_bufs[] = { { .buf = buf, .len = len } }; const struct spi_buf_set rx = { .buffers = rx_bufs, .count = 1, }; return spi_transceive(spi_dev, spi_cfg, &tx, &rx); } static int sdhc_spi_init_card(const struct device *dev) { /* SD spec requires at least 74 clocks be send to SD to start it. * for SPI protocol, this will be performed by sending 10 0xff values * to the card (this should result in 80 SCK cycles) */ const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *data = dev->data; struct spi_config *spi_cfg = data->spi_cfg; int ret; if (spi_cfg->frequency == 0) { /* Use default 400KHZ frequency */ spi_cfg->frequency = SDMMC_CLOCK_400KHZ; } /* the initial 74 clocks must be sent while CS is high */ spi_cfg->operation |= SPI_CS_ACTIVE_HIGH; ret = sdhc_spi_rx(config->spi_dev, spi_cfg, data->scratch, 10); if (ret != 0) { spi_release(config->spi_dev, spi_cfg); spi_cfg->operation &= ~SPI_CS_ACTIVE_HIGH; return ret; } /* Release lock on SPI bus */ ret = spi_release(config->spi_dev, spi_cfg); spi_cfg->operation &= ~SPI_CS_ACTIVE_HIGH; return ret; } /* Checks if SPI SD card is sending busy signal */ static int sdhc_spi_card_busy(const struct device *dev) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *data = dev->data; int ret; uint8_t response; ret = sdhc_spi_rx(config->spi_dev, data->spi_cfg, &response, 1); if (ret) { return -EIO; } if (response == 0xFF) { return 0; } else return 1; } /* Waits for SPI SD card to stop sending busy signal */ static int sdhc_spi_wait_unbusy(const struct device *dev, int timeout_ms, int interval_ticks) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *data = dev->data; int ret; uint8_t response; while (timeout_ms > 0) { ret = sdhc_spi_rx(config->spi_dev, data->spi_cfg, &response, 1); if (ret) { return ret; } if (response == 0xFF) { return 0; } k_msleep(k_ticks_to_ms_floor32(interval_ticks)); timeout_ms -= k_ticks_to_ms_floor32(interval_ticks); } return -ETIMEDOUT; } /* Read SD command from SPI response */ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command *cmd, int rx_len) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *dev_data = dev->data; uint8_t *response = dev_data->scratch; uint8_t *end = response + rx_len; int ret, timeout = cmd->timeout_ms; uint8_t value, i; /* First step is finding the first valid byte of the response. * All SPI responses start with R1, which will have MSB of zero. * we know we can ignore the first 7 bytes, which hold the command and * initial "card ready" byte. */ response += 8; while (response < end && ((*response & SD_SPI_START) == SD_SPI_START)) { response++; } if (response == end) { /* Some cards are slow, and need more time to respond. Continue * with single byte reads until the card responds. */ response = dev_data->scratch; end = response + 1; while (timeout > 0) { ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, response, 1); if (ret < 0) { return ret; } if (*response != 0xff) { break; } /* Delay for a bit, and poll the card again */ k_msleep(10); timeout -= 10; } if (*response == 0xff) { return -ETIMEDOUT; } } /* Record R1 response */ cmd->response[0] = *response++; /* Check response for error */ if (cmd->response[0] != 0) { if (cmd->response[0] & (SD_SPI_R1PARAMETER_ERR | SD_SPI_R1ADDRESS_ERR)) { return -EFAULT; /* Bad address */ } else if (cmd->response[0] & (SD_SPI_R1ILLEGAL_CMD_ERR)) { return -EINVAL; /* Invalid command */ } else if (cmd->response[0] & (SD_SPI_R1CMD_CRC_ERR)) { return -EILSEQ; /* Illegal byte sequence */ } else if (cmd->response[0] & (SD_SPI_R1ERASE_SEQ_ERR | SD_SPI_R1ERASE_RESET)) { return -EIO; } /* else IDLE_STATE bit is set, which is not an error, card is just resetting */ } switch ((cmd->response_type & SDHC_SPI_RESPONSE_TYPE_MASK)) { case SD_SPI_RSP_TYPE_R1: /* R1 response - one byte*/ break; case SD_SPI_RSP_TYPE_R1b: /* R1b response - one byte plus busy signal */ /* Read remaining bytes to see if card is still busy. * card will be ready when it stops driving data out * low. */ while (response < end && (*response == 0x0)) { response++; } if (response == end) { value = cmd->timeout_ms; response--; /* Periodically check busy line */ ret = sdhc_spi_wait_unbusy(dev, SPI_R1B_TIMEOUT_MS, 1000); } break; case SD_SPI_RSP_TYPE_R2: case SD_SPI_RSP_TYPE_R5: /* R2/R5 response - R1 response + 1 byte*/ if (response == end) { response = dev_data->scratch; end = response + 1; /* Read the next byte */ ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, response, 1); if (ret) { return ret; } } cmd->response[0] = (*response) << 8; break; case SD_SPI_RSP_TYPE_R3: case SD_SPI_RSP_TYPE_R4: case SD_SPI_RSP_TYPE_R7: /* R3/R4/R7 response - R1 response + 4 bytes */ cmd->response[1] = 0; for (i = 0; i < 4; i++) { cmd->response[1] <<= 8; /* Read bytes of response */ if (response == end) { response = dev_data->scratch; end = response + 1; /* Read the next byte */ ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, response, 1); if (ret) { return ret; } } cmd->response[1] |= *response++; } break; default: /* Other RSP types not supported */ return -ENOTSUP; } return 0; } /* Send SD command using SPI */ static int sdhc_spi_send_cmd(const struct device *dev, struct sdhc_command *cmd, bool data_present) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *dev_data = dev->data; int err; uint8_t *cmd_buf; /* To reduce overhead, we will send entire command in one SPI * transaction. The packet takes the following format: * - all ones byte to ensure card is ready * - opcode byte (which includes start and transmission bits) * - 4 bytes for argument * - crc7 byte (with end bit) * The SD card can take up to 8 bytes worth of SCLK cycles to respond. * therefore, we provide 8 bytes of all ones, to read data from the card. * the maximum spi response length is 5 bytes, so we provide an * additional 5 bytes of data, leaving us with 13 bytes of 0xff. * Finally, we send a padding byte of all 0xff, to ensure that * the card recives at least one 0xff byte before next command. */ /* Note: we can discard CMD data as we send it, * so resuse the TX buf as RX */ struct spi_buf bufs[] = { { .buf = dev_data->scratch, .len = sizeof(dev_data->scratch), }, }; const struct spi_buf_set buf_set = { .buffers = bufs, .count = 1, }; if (data_present) { /* We cannot send extra SCLK cycles with our command, * since we'll miss the data the card responds with. We * send one 0xff byte, six command bytes, two additional 0xff * bytes, since the min value of NCR (see SD SPI timing * diagrams) is one, and we know there will be an R1 response. */ bufs[0].len = SD_SPI_CMD_SIZE + 3; } memset(dev_data->scratch, 0xFF, sizeof(dev_data->scratch)); cmd_buf = dev_data->scratch + 1; /* Command packet holds the following bits: * [47]: start bit, 0b0 * [46]: transmission bit, 0b1 * [45-40]: command index * [39-8]: argument * [7-1]: CRC * [0]: end bit, 0b1 * Note that packets are sent MSB first. */ /* Add start bit, tx bit, and cmd opcode */ cmd_buf[0] = (cmd->opcode & SD_SPI_CMD); cmd_buf[0] = ((cmd_buf[0] | SD_SPI_TX) & ~SD_SPI_START); /* Add argument */ sys_put_be32(cmd->arg, &cmd_buf[1]); /* Add CRC, and set LSB as the end bit */ cmd_buf[SD_SPI_CMD_BODY_SIZE] = crc7_be(0, cmd_buf, SD_SPI_CMD_BODY_SIZE) | 0x1; LOG_DBG("cmd%d arg 0x%x", cmd->opcode, cmd->arg); /* Set data, will lock SPI bus */ err = spi_transceive(config->spi_dev, dev_data->spi_cfg, &buf_set, &buf_set); if (err != 0) { return err; } /* Read command response */ return sdhc_spi_response_get(dev, cmd, bufs[0].len); } /* Skips bytes in SDHC data stream. */ static int sdhc_skip(const struct device *dev, uint8_t skip_val) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *data = dev->data; uint8_t buf; int ret; uint32_t retries = SD_SPI_SKIP_RETRIES; do { ret = sdhc_spi_rx(config->spi_dev, data->spi_cfg, &buf, sizeof(buf)); if (ret) { return ret; } } while (buf == skip_val && retries--); if (retries == 0) { return -ETIMEDOUT; } /* Return first non-skipped value */ return buf; } /* Handles reading data from SD SPI device */ static int sdhc_spi_read_data(const struct device *dev, struct sdhc_data *data) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *dev_data = dev->data; uint8_t *read_location = data->data; uint32_t remaining = data->blocks; int ret; uint8_t crc[SD_SPI_CRC16_SIZE + 1]; /* The SPI API defaults to sending 0x00 when no TX buffer is * provided, so we are limited to 512 byte reads * (unless we increase the size of SDHC buffer) */ const struct spi_buf tx_bufs[] = { { .buf = (uint8_t *)sdhc_ones, .len = data->block_size, }, }; const struct spi_buf_set tx = { .buffers = tx_bufs, .count = 1, }; struct spi_buf rx_bufs[] = { { .buf = read_location, .len = data->block_size, } }; const struct spi_buf_set rx = { .buffers = rx_bufs, .count = 1, }; if (data->block_size > 512) { /* SPI max BLKLEN is 512 */ return -ENOTSUP; } /* Read bytes until data stream starts. SD will send 0xff until * data is available */ ret = sdhc_skip(dev, 0xff); if (ret < 0) { return ret; } /* Check token */ if (ret != SD_SPI_TOKEN_SINGLE) { return -EIO; } /* Read blocks until we are out of data */ while (remaining--) { ret = spi_transceive(config->spi_dev, dev_data->spi_cfg, &tx, &rx); if (ret) { LOG_ERR("Data write failed"); return ret; } /* Read CRC16 plus one end byte */ ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, crc, sizeof(crc)); if (crc16_itu_t(0, read_location, data->block_size) != sys_get_be16(crc)) { /* Bad CRC */ LOG_ERR("Bad data CRC"); return -EILSEQ; } /* Advance read location */ read_location += data->block_size; rx_bufs[0].buf = read_location; if (remaining) { /* Check next data token */ ret = sdhc_skip(dev, 0xff); if (ret != SD_SPI_TOKEN_SINGLE) { LOG_ERR("Bad token"); return -EIO; } } } return ret; } /* Handles writing data to SD SPI device */ static int sdhc_spi_write_data(const struct device *dev, struct sdhc_data *data) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *dev_data = dev->data; int ret; uint8_t token, resp; uint8_t *write_location = data->data, crc[SD_SPI_CRC16_SIZE]; uint32_t remaining = data->blocks; struct spi_buf tx_bufs[] = { { .buf = &token, .len = sizeof(uint8_t), }, { .buf = write_location, .len = data->block_size, }, { .buf = crc, .len = sizeof(crc), }, }; struct spi_buf_set tx = { .buffers = tx_bufs, .count = 3, }; /* Set the token- single block reads use different token * than multibock */ if (remaining > 1) { token = SD_SPI_TOKEN_MULTI_WRITE; } else { token = SD_SPI_TOKEN_SINGLE; } while (remaining--) { /* Build the CRC for this data block */ sys_put_be16(crc16_itu_t(0, write_location, data->block_size), crc); ret = spi_write(config->spi_dev, dev_data->spi_cfg, &tx); if (ret) { return ret; } /* Read back the data response token from the card */ ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, &resp, sizeof(resp)); if (ret) { return ret; } /* Check response token */ if ((resp & 0xF) != SD_SPI_RESPONSE_ACCEPTED) { if ((resp & 0xF) == SD_SPI_RESPONSE_CRC_ERR) { return -EILSEQ; } else if ((resp & 0xF) == SD_SPI_RESPONSE_WRITE_ERR) { return -EIO; } LOG_DBG("Unknown write response token 0x%x", resp); return -EIO; } /* Advance write location */ write_location += data->block_size; tx_bufs[1].buf = write_location; /* Wait for card to stop being busy */ ret = sdhc_spi_wait_unbusy(dev, data->timeout_ms, 0); if (ret) { return ret; } } if (data->blocks > 1) { /* Write stop transfer token to card */ token = SD_SPI_TOKEN_STOP_TRAN; tx.count = 1; ret = spi_write(config->spi_dev, dev_data->spi_cfg, &tx); if (ret) { return ret; } /* Wait for card to stop being busy */ ret = sdhc_spi_wait_unbusy(dev, data->timeout_ms, 0); if (ret) { return ret; } } return 0; } static int sdhc_spi_request(const struct device *dev, struct sdhc_command *cmd, struct sdhc_data *data) { const struct sdhc_spi_config *config = dev->config; struct sdhc_spi_data *dev_data = dev->data; int ret, stop_ret, retries = cmd->retries; const struct sdhc_command stop_cmd = { .opcode = SD_STOP_TRANSMISSION, .arg = 0, .response_type = SD_SPI_RSP_TYPE_R1b, .timeout_ms = 1000, .retries = 1, }; if (data == NULL) { do { ret = sdhc_spi_send_cmd(dev, cmd, false); } while ((ret != 0) && (retries-- > 0)); } else { do { retries--; ret = sdhc_spi_send_cmd(dev, cmd, true); if (ret) { continue; } if ((cmd->opcode == SD_WRITE_SINGLE_BLOCK) || (cmd->opcode == SD_WRITE_MULTIPLE_BLOCK)) { ret = sdhc_spi_write_data(dev, data); } else { ret = sdhc_spi_read_data(dev, data); } if (ret || (cmd->opcode == SD_READ_MULTIPLE_BLOCK)) { int stop_retries = cmd->retries; /* CMD12 is required after multiple read, or * to retry failed transfer */ stop_ret = sdhc_spi_send_cmd(dev, (struct sdhc_command *)&stop_cmd, false); while ((stop_ret != 0) && (stop_retries > 0)) { /* Retry stop command */ ret = stop_ret = sdhc_spi_send_cmd(dev, (struct sdhc_command *)&stop_cmd, false); stop_retries--; } } } while ((ret != 0) && (retries > 0)); } if (ret) { /* Release SPI bus */ spi_release(config->spi_dev, dev_data->spi_cfg); return ret; } /* Release SPI bus */ return spi_release(config->spi_dev, dev_data->spi_cfg); } static int sdhc_spi_set_io(const struct device *dev, struct sdhc_io *ios) { const struct sdhc_spi_config *cfg = dev->config; struct sdhc_spi_data *data = dev->data; if (ios->clock != data->spi_cfg->frequency) { if (ios->clock > cfg->spi_max_freq) { return -ENOTSUP; } /* Because pointer comparision is used, we have to * swap to a new configuration structure to reconfigure SPI. */ if (ios->clock != 0) { if (data->spi_cfg == &data->cfg_a) { data->cfg_a.frequency = ios->clock; memcpy(&data->cfg_b, &data->cfg_a, sizeof(struct spi_config)); data->spi_cfg = &data->cfg_b; } else { data->cfg_b.frequency = ios->clock; memcpy(&data->cfg_a, &data->cfg_b, sizeof(struct spi_config)); data->spi_cfg = &data->cfg_a; } } } if (ios->bus_mode != SDHC_BUSMODE_PUSHPULL) { /* SPI mode supports push pull */ return -ENOTSUP; } if (data->power_mode != ios->power_mode) { if (ios->power_mode == SDHC_POWER_ON) { /* Send 74 clock cycles to start card */ if (sdhc_spi_init_card(dev) != 0) { LOG_ERR("Card SCLK init sequence failed"); return -EIO; } } if (cfg->pwr_gpio.port) { /* If power control GPIO is defined, toggle SD power */ if (ios->power_mode == SDHC_POWER_ON) { if (gpio_pin_set_dt(&cfg->pwr_gpio, 1)) { return -EIO; } } else { if (gpio_pin_set_dt(&cfg->pwr_gpio, 0)) { return -EIO; } } } data->power_mode = ios->power_mode; } if (ios->bus_width != SDHC_BUS_WIDTH1BIT) { /* SPI mode supports 1 bit bus */ return -ENOTSUP; } if (ios->signal_voltage != SD_VOL_3_3_V) { /* SPI mode does not support UHS voltages */ return -ENOTSUP; } return 0; } static int sdhc_spi_get_card_present(const struct device *dev) { /* SPI has no card presence method, assume card is in slot */ return 1; } static int sdhc_spi_get_host_props(const struct device *dev, struct sdhc_host_props *props) { const struct sdhc_spi_config *cfg = dev->config; memset(props, 0, sizeof(struct sdhc_host_props)); props->f_min = SDMMC_CLOCK_400KHZ; props->f_max = cfg->spi_max_freq; props->power_delay = cfg->power_delay_ms; props->host_caps.vol_330_support = true; props->is_spi = true; return 0; } static int sdhc_spi_reset(const struct device *dev) { struct sdhc_spi_data *data = dev->data; /* Reset host I/O */ data->spi_cfg->frequency = SDMMC_CLOCK_400KHZ; return 0; } static int sdhc_spi_init(const struct device *dev) { const struct sdhc_spi_config *cfg = dev->config; struct sdhc_spi_data *data = dev->data; int ret = 0; if (!device_is_ready(cfg->spi_dev)) { return -ENODEV; } if (cfg->pwr_gpio.port) { if (!gpio_is_ready_dt(&cfg->pwr_gpio)) { return -ENODEV; } ret = gpio_pin_configure_dt(&cfg->pwr_gpio, GPIO_OUTPUT_INACTIVE); if (ret != 0) { LOG_ERR("Could not configure power gpio (%d)", ret); return ret; } } data->power_mode = SDHC_POWER_OFF; data->spi_cfg = &data->cfg_a; data->spi_cfg->frequency = 0; return ret; } static const struct sdhc_driver_api sdhc_spi_api = { .request = sdhc_spi_request, .set_io = sdhc_spi_set_io, .get_host_props = sdhc_spi_get_host_props, .get_card_present = sdhc_spi_get_card_present, .reset = sdhc_spi_reset, .card_busy = sdhc_spi_card_busy, }; #define SDHC_SPI_INIT(n) \ const struct sdhc_spi_config sdhc_spi_config_##n = { \ .spi_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \ .pwr_gpio = GPIO_DT_SPEC_INST_GET_OR(n, pwr_gpios, {0}), \ .spi_max_freq = DT_INST_PROP(n, spi_max_frequency), \ .power_delay_ms = DT_INST_PROP(n, power_delay_ms), \ }; \ \ struct sdhc_spi_data sdhc_spi_data_##n = { \ .cfg_a = SPI_CONFIG_DT_INST(n, \ (SPI_LOCK_ON | SPI_HOLD_ON_CS | SPI_WORD_SET(8) \ | (DT_INST_PROP(n, spi_clock_mode_cpol) ? SPI_MODE_CPOL : 0) \ | (DT_INST_PROP(n, spi_clock_mode_cpha) ? SPI_MODE_CPHA : 0) \ ),\ 0), \ }; \ \ DEVICE_DT_INST_DEFINE(n, \ &sdhc_spi_init, \ NULL, \ &sdhc_spi_data_##n, \ &sdhc_spi_config_##n, \ POST_KERNEL, \ CONFIG_SDHC_INIT_PRIORITY, \ &sdhc_spi_api); DT_INST_FOREACH_STATUS_OKAY(SDHC_SPI_INIT)