blob: 559884499b023acd0443899aae5ba2b8d6d33437 [file] [log] [blame]
/*
* Copyright 2022 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/drivers/sdhc.h>
#include <zephyr/device.h>
#include <zephyr/ztest.h>
static const struct device *const sdhc_dev = DEVICE_DT_GET(DT_ALIAS(sdhc0));
static struct sdhc_host_props props;
static struct sdhc_io io;
#define SDHC_FREQUENCY_SLIP 10000000
/* Resets SD host controller, verifies API */
ZTEST(sdhc, test_reset)
{
int ret;
zassert_true(device_is_ready(sdhc_dev), "SDHC device is not ready");
ret = sdhc_hw_reset(sdhc_dev);
zassert_equal(ret, 0, "SDHC HW reset failed");
}
/* Gets host properties, verifies all properties are set */
ZTEST(sdhc, test_host_props)
{
int ret;
/* Set all host properties to 0xFF */
props.f_max = 0xFF;
props.f_min = 0xFF;
props.power_delay = 0xFF;
props.max_current_330 = 0xFF;
props.max_current_300 = 0xFF;
props.max_current_180 = 0xFF;
ret = sdhc_get_host_props(sdhc_dev, &props);
zassert_equal(ret, 0, "SDHC host props api call failed");
zassert_not_equal(props.f_max, 0xFF, "props structure not initialized");
zassert_not_equal(props.f_min, 0xFF, "props structure not initialized");
zassert_not_equal(props.power_delay, 0xFF, "props structure not initialized");
zassert_not_equal(props.max_current_330, 0xFF, "props structure not initialized");
zassert_not_equal(props.max_current_300, 0xFF, "props structure not initialized");
zassert_not_equal(props.max_current_180, 0xFF, "props structure not initialized");
}
/* Verify that driver rejects frequencies outside of claimed range */
ZTEST(sdhc, test_set_io)
{
int ret;
io.clock = props.f_min;
io.bus_mode = SDHC_BUSMODE_PUSHPULL;
io.power_mode = SDHC_POWER_ON;
io.bus_width = SDHC_BUS_WIDTH1BIT;
io.timing = SDHC_TIMING_LEGACY;
io.signal_voltage = SD_VOL_3_3_V;
ret = sdhc_set_io(sdhc_dev, &io);
zassert_equal(ret, 0, "IO configuration failed");
/* Verify that IO configuration fails with high frequency */
/* Since SDHC may select nearby frequency, increase frequency
* by a large margin over the max.
*/
io.clock = props.f_max + SDHC_FREQUENCY_SLIP;
ret = sdhc_set_io(sdhc_dev, &io);
zassert_not_equal(ret, 0, "Invalid io configuration should not succeed");
}
/* Verify that the driver can detect a present SD card */
ZTEST(sdhc, test_card_presence)
{
int ret;
io.clock = props.f_min;
ret = sdhc_set_io(sdhc_dev, &io);
zassert_equal(ret, 0, "Setting io configuration failed");
k_msleep(props.power_delay);
ret = sdhc_card_present(sdhc_dev);
zassert_equal(ret, 1, "Card is not reported as present, is one connected?");
}
/* Verify that the driver can send commands to SD card, by reading interface
* condition. This follows the first part of the SD initialization defined in
* the SD specification.
*/
ZTEST(sdhc, test_card_if_cond)
{
struct sdhc_command cmd;
int ret, resp;
int check_pattern = SD_IF_COND_CHECK;
/* Toggle power to card, to clear state */
io.power_mode = SDHC_POWER_OFF;
ret = sdhc_set_io(sdhc_dev, &io);
zassert_equal(ret, 0, "Setting io configuration failed");
k_msleep(props.power_delay);
io.power_mode = SDHC_POWER_ON;
ret = sdhc_set_io(sdhc_dev, &io);
zassert_equal(ret, 0, "Setting io configuration failed");
k_msleep(props.power_delay);
memset(&cmd, 0, sizeof(struct sdhc_command));
cmd.opcode = SD_GO_IDLE_STATE;
cmd.response_type = (SD_RSP_TYPE_NONE | SD_SPI_RSP_TYPE_R1);
cmd.timeout_ms = 200;
ret = sdhc_request(sdhc_dev, &cmd, NULL);
zassert_equal(ret, 0, "Card reset command failed");
cmd.opcode = SD_SEND_IF_COND;
/* Indicate 3.3V support, plus check pattern */
cmd.arg = SD_IF_COND_VHS_3V3 | check_pattern;
cmd.response_type = (SD_RSP_TYPE_R7 | SD_SPI_RSP_TYPE_R7);
cmd.timeout_ms = 500;
cmd.retries = 3;
ret = sdhc_request(sdhc_dev, &cmd, NULL);
zassert_equal(ret, 0, "Read Interface condition failed");
if (props.is_spi) {
resp = cmd.response[1];
} else {
resp = cmd.response[0];
}
if ((resp & 0xFF) == check_pattern) {
/* Although both responses are valid in SD spec, most
* modern cards are SDHC or better, and should respond as such.
*/
TC_PRINT("Found SDHC/SDXC card\n");
} else if (resp & 0x4) {
/* An illegal command response indicates an SDSC card */
TC_PRINT("Found SDSC card\n");
} else {
zassert_unreachable("Invalid response to SD interface condition");
}
}
ZTEST_SUITE(sdhc, NULL, NULL, NULL, NULL, NULL);