From f18b8cf1078c1c8f0af076007932dccd6e91b1cb Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Mon, 2 Dec 2024 10:46:53 +0800 Subject: [PATCH] [DM/SDIO] Support DM mode 1. Support features read by DM. 2. Support regulator API in drivers. 3. Support send tuning option CMD. 4. Replace `switch_uhs_voltage` by `signal_voltage_switch`. Link: https://github.com/RT-Thread/rt-thread/issues/9732 Signed-off-by: GuEe-GUI <2991707448@qq.com> --- .../drivers/include/drivers/dev_mmcsd_core.h | 6 + .../drivers/include/drivers/mmcsd_host.h | 23 +- components/drivers/sdio/SConscript | 6 + components/drivers/sdio/dev_mmcsd_core.c | 288 ++++++++++++++++++ components/drivers/sdio/dev_regulator.c | 262 ++++++++++++++++ components/drivers/sdio/dev_sd.c | 33 +- components/drivers/sdio/dev_sdio_dm.c | 135 ++++++++ components/drivers/sdio/dev_sdio_dm.h | 39 +++ 8 files changed, 761 insertions(+), 31 deletions(-) create mode 100644 components/drivers/sdio/dev_regulator.c create mode 100644 components/drivers/sdio/dev_sdio_dm.c create mode 100644 components/drivers/sdio/dev_sdio_dm.h diff --git a/components/drivers/include/drivers/dev_mmcsd_core.h b/components/drivers/include/drivers/dev_mmcsd_core.h index c86e9dde4815..a541bc2e2d1a 100644 --- a/components/drivers/include/drivers/dev_mmcsd_core.h +++ b/components/drivers/include/drivers/dev_mmcsd_core.h @@ -242,6 +242,12 @@ void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width); void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing); void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card); rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr); +rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage); +void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host); +rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host); +rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr); +rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error); +rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode); void mmcsd_change(struct rt_mmcsd_host *host); void mmcsd_detect(void *param); void mmcsd_host_init(struct rt_mmcsd_host *host); diff --git a/components/drivers/include/drivers/mmcsd_host.h b/components/drivers/include/drivers/mmcsd_host.h index 5632ee107537..41caf49365c1 100644 --- a/components/drivers/include/drivers/mmcsd_host.h +++ b/components/drivers/include/drivers/mmcsd_host.h @@ -88,9 +88,23 @@ struct rt_mmcsd_host_ops rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host); void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en); rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode); - rt_int32_t (*switch_uhs_voltage)(struct rt_mmcsd_host *host); + rt_bool_t (*card_busy)(struct rt_mmcsd_host *host); + rt_err_t (*signal_voltage_switch)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg); }; +#ifdef RT_USING_REGULATOR +struct rt_regulator; + +struct rt_mmcsd_supply +{ + rt_bool_t vqmmc_enabled; + rt_bool_t regulator_enabled; + + struct rt_regulator *vmmc; /* Card power supply */ + struct rt_regulator *vqmmc; /* Optional Vccq supply */ +}; +#endif /* RT_USING_REGULATOR */ + struct rt_mmcsd_host { char name[RT_NAME_MAX]; @@ -158,6 +172,13 @@ struct rt_mmcsd_host struct rt_semaphore *sdio_irq_sem; struct rt_thread *sdio_irq_thread; +#ifdef RT_USING_REGULATOR + struct rt_mmcsd_supply supply; +#endif +#ifdef RT_USING_OFW + void *ofw_node; +#endif + void *private_data; }; #ifdef __cplusplus diff --git a/components/drivers/sdio/SConscript b/components/drivers/sdio/SConscript index 04061a9e02a0..23e4386ac510 100644 --- a/components/drivers/sdio/SConscript +++ b/components/drivers/sdio/SConscript @@ -13,6 +13,12 @@ dev_mmc.c # The set of source files associated with this SConscript file. path = [cwd + '/../include'] +if GetDepend(['RT_USING_DM']): + src += ['dev_sdio_dm.c'] + + if GetDepend(['RT_USING_REGULATOR']): + src += ['dev_regulator.c'] + group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SDIO'], CPPPATH = path) Return('group') diff --git a/components/drivers/sdio/dev_mmcsd_core.c b/components/drivers/sdio/dev_mmcsd_core.c index 33072c10dd8c..9d513f8596d3 100644 --- a/components/drivers/sdio/dev_mmcsd_core.c +++ b/components/drivers/sdio/dev_mmcsd_core.c @@ -549,6 +549,281 @@ rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr) return ocr; } +rt_err_t mmcsd_set_signal_voltage(struct rt_mmcsd_host *host, unsigned char signal_voltage) +{ + rt_err_t err = RT_EOK; + unsigned char old_signal_voltage = host->io_cfg.signal_voltage; + + host->io_cfg.signal_voltage = signal_voltage; + if (host->ops->signal_voltage_switch) + { + err = host->ops->signal_voltage_switch(host, &host->io_cfg); + } + + if (err) + { + host->io_cfg.signal_voltage = old_signal_voltage; + } + + return err; +} + +void mmcsd_set_initial_signal_voltage(struct rt_mmcsd_host *host) +{ + /* 3.3V -> 1.8v -> 1.2v */ + if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_330)) + { + LOG_D("Initial signal voltage of %sv", "3.3"); + } + else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180)) + { + LOG_D("Initial signal voltage of %sv", "1.8"); + } + else if (!mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_120)) + { + LOG_D("Initial signal voltage of %sv", "1.2"); + } +} + +rt_err_t mmcsd_host_set_uhs_voltage(struct rt_mmcsd_host *host) +{ + rt_uint32_t old_clock = host->io_cfg.clock; + + host->io_cfg.clock = 0; + mmcsd_set_iocfg(host); + + if (mmcsd_set_signal_voltage(host, MMCSD_SIGNAL_VOLTAGE_180)) + { + return -RT_ERROR; + } + + /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ + rt_thread_mdelay(10); + + host->io_cfg.clock = old_clock; + mmcsd_set_iocfg(host); + + return RT_EOK; +} + +static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr); + +rt_err_t mmcsd_set_uhs_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr) +{ + rt_err_t err = RT_EOK; + struct rt_mmcsd_cmd cmd; + + if (!host->ops->signal_voltage_switch) + { + return -RT_EINVAL; + } + + if (!host->ops->card_busy) + { + LOG_W("%s: Cannot verify signal voltage switch", host->name); + } + + rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); + + cmd.cmd_code = VOLTAGE_SWITCH; + cmd.arg = 0; + cmd.flags = RESP_R1 | CMD_AC; + + err = mmcsd_send_cmd(host, &cmd, 0); + if (err) + { + goto power_cycle; + } + + if (!controller_is_spi(host) && (cmd.resp[0] & R1_ERROR)) + { + return -RT_EIO; + } + + /* + * The card should drive cmd and dat[0:3] low immediately + * after the response of cmd11, but wait 1 ms to be sure + */ + rt_thread_mdelay(1); + if (host->ops->card_busy && !host->ops->card_busy(host)) + { + err = -RT_ERROR; + goto power_cycle; + } + + if (mmcsd_host_set_uhs_voltage(host)) + { + /* + * Voltages may not have been switched, but we've already + * sent CMD11, so a power cycle is required anyway + */ + err = -RT_ERROR; + goto power_cycle; + } + + /* Wait for at least 1 ms according to spec */ + rt_thread_mdelay(1); + + /* + * Failure to switch is indicated by the card holding + * dat[0:3] low + */ + if (host->ops->card_busy && host->ops->card_busy(host)) + { + err = -RT_ERROR; + } + +power_cycle: + if (err) + { + LOG_D("%s: Signal voltage switch failed, power cycling card", host->name); + mmcsd_power_cycle(host, ocr); + } + + return err; +} + +static const rt_uint8_t tuning_blk_pattern_4bit[] = +{ + 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, + 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, + 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, + 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, + 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, + 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, + 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, + 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, +}; + +static const rt_uint8_t tuning_blk_pattern_8bit[] = +{ + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + +rt_err_t mmcsd_send_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode, rt_err_t *cmd_error) +{ + rt_err_t err = RT_EOK; + int size; + rt_uint8_t *data_buf; + const rt_uint8_t *tuning_block_pattern; + struct rt_mmcsd_req req = {}; + struct rt_mmcsd_cmd cmd = {}; + struct rt_mmcsd_data data = {}; + struct rt_mmcsd_io_cfg *io_cfg = &host->io_cfg; + + if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8) + { + tuning_block_pattern = tuning_blk_pattern_8bit; + size = sizeof(tuning_blk_pattern_8bit); + } + else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4) + { + tuning_block_pattern = tuning_blk_pattern_4bit; + size = sizeof(tuning_blk_pattern_4bit); + } + else + { + return -RT_EINVAL; + } + + data_buf = rt_malloc(size); + if (!data_buf) + { + return -RT_ENOMEM; + } + + rt_memset(data_buf, 0, size); + rt_memset(&req, 0, sizeof(struct rt_mmcsd_req)); + rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); + rt_memset(&data, 0, sizeof(struct rt_mmcsd_data)); + + req.cmd = &cmd; + req.data = &data; + + cmd.cmd_code = opcode; + cmd.flags = RESP_R1 | CMD_ADTC; + + data.blksize = size; + data.blks = 1; + data.flags = DATA_DIR_READ; + + /* + * According to the tuning specs, Tuning process + * is normally shorter 40 executions of CMD19, + * and timeout value should be shorter than 150 ms + */ + data.timeout_ns = 150 * 1000000; + + mmcsd_send_request(host, &req); + + if (cmd_error) + { + *cmd_error = cmd.err; + } + + if (cmd.err) + { + err = cmd.err; + goto out_free; + } + + if (data.err) + { + err = data.err; + goto out_free; + } + + if (rt_memcmp(data_buf, tuning_block_pattern, size)) + { + err = -RT_EIO; + } + +out_free: + rt_free(data_buf); + + return err; +} + +rt_err_t mmcsd_send_abort_tuning(struct rt_mmcsd_host *host, rt_uint32_t opcode) +{ + struct rt_mmcsd_cmd cmd = {}; + + /* + * eMMC specification specifies that CMD12 can be used to stop a tuning + * command, but SD specification does not, so do nothing unless it is eMMC. + */ + if (opcode != SEND_TUNING_BLOCK_HS200) + { + return 0; + } + + cmd.cmd_code = STOP_TRANSMISSION; + cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC; + + /* + * For drivers that override R1 to R1b, set an arbitrary timeout based + * on the tuning timeout i.e. 150ms. + */ + cmd.busy_timeout = 150; + + return mmcsd_send_cmd(host, &cmd, 0); +} + static void mmcsd_power_up(struct rt_mmcsd_host *host) { int bit = __rt_fls(host->valid_ocr) - 1; @@ -568,6 +843,8 @@ static void mmcsd_power_up(struct rt_mmcsd_host *host) host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1; mmcsd_set_iocfg(host); + mmcsd_set_initial_signal_voltage(host); + /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. @@ -599,6 +876,17 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host) mmcsd_set_iocfg(host); } +static void mmcsd_power_cycle(struct rt_mmcsd_host *host, rt_uint32_t ocr) +{ + mmcsd_power_off(host); + + /* Wait at least 1 ms according to SD spec */ + rt_thread_mdelay(1); + + mmcsd_power_up(host); + mmcsd_select_voltage(host, ocr); +} + int mmcsd_wait_cd_changed(rt_int32_t timeout) { struct rt_mmcsd_host *host; diff --git a/components/drivers/sdio/dev_regulator.c b/components/drivers/sdio/dev_regulator.c new file mode 100644 index 000000000000..74b5d2c5aaf2 --- /dev/null +++ b/components/drivers/sdio/dev_regulator.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include "dev_sdio_dm.h" + +#define DBG_TAG "SDIO" +#ifdef RT_SDIO_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_INFO +#endif /* RT_SDIO_DEBUG */ +#include + +static rt_err_t ocrbitnum_to_vdd(int vdd_bit, int *min_uvolt, int *max_uvolt) +{ + int tmp; + + if (!vdd_bit) + { + return -RT_EINVAL; + } + + tmp = vdd_bit - rt_ilog2(VDD_165_195); + + if (tmp == 0) + { + *min_uvolt = 1650 * 1000; + *max_uvolt = 1950 * 1000; + } + else + { + *min_uvolt = 1900 * 1000 + tmp * 100 * 1000; + *max_uvolt = *min_uvolt + 100 * 1000; + } + + return 0; +} + +rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host, + struct rt_regulator *supply, rt_uint16_t vdd_bit) +{ + rt_err_t err = RT_EOK; + + if (!host) + { + return -RT_EINVAL; + } + + if (rt_is_err_or_null(supply)) + { + return RT_EOK; + } + + if (vdd_bit) + { + int min_uvolt, max_uvolt; + + ocrbitnum_to_vdd(vdd_bit, &min_uvolt, &max_uvolt); + + err = rt_regulator_set_voltage(supply, min_uvolt, max_uvolt); + + if (!err && host->supply.regulator_enabled) + { + err = rt_regulator_enable(supply); + + if (!err) + { + host->supply.regulator_enabled = RT_TRUE; + } + } + } + else if (host->supply.regulator_enabled) + { + err = rt_regulator_disable(supply); + + if (!err) + { + host->supply.regulator_enabled = RT_FALSE; + } + } + + if (err) + { + LOG_E("Set regulator OCR %d error = %s", vdd_bit, rt_strerror(err)); + } + + return err; +} + +static int regulator_set_voltage_if_supported(struct rt_regulator *regulator, + int min_uvolt, int target_uvolt, int max_uvolt) +{ + if (!rt_regulator_is_supported_voltage(regulator, min_uvolt, max_uvolt)) + { + return -RT_EINVAL; + } + + if (rt_regulator_get_voltage(regulator) == target_uvolt) + { + return RT_EOK; + } + + return rt_regulator_set_voltage_triplet(regulator, min_uvolt, target_uvolt, + max_uvolt); +} + +rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *ios) +{ + rt_err_t err; + int uvolt, min_uvolt, max_uvolt; + + if (rt_is_err_or_null(host->supply.vqmmc)) + { + return -RT_EINVAL; + } + + switch (ios->signal_voltage) + { + case MMCSD_SIGNAL_VOLTAGE_120: + return regulator_set_voltage_if_supported(host->supply.vqmmc, + 1100000, 1200000, 1300000); + + case MMCSD_SIGNAL_VOLTAGE_180: + return regulator_set_voltage_if_supported(host->supply.vqmmc, + 1700000, 1800000, 1950000); + + case MMCSD_SIGNAL_VOLTAGE_330: + err = ocrbitnum_to_vdd(host->io_cfg.vdd, &uvolt, &max_uvolt); + + if (err) + { + return err; + } + + min_uvolt = rt_max(uvolt - 300000, 2700000); + max_uvolt = rt_min(max_uvolt + 200000, 3600000); + + err = regulator_set_voltage_if_supported(host->supply.vqmmc, + min_uvolt, uvolt, max_uvolt); + if (err >= 0) + { + return err; + } + + return regulator_set_voltage_if_supported(host->supply.vqmmc, + 2700000, uvolt, 3600000); + + default: + return -RT_EINVAL; + } +} + +rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host) +{ + rt_err_t err; + + if (!dev || !host) + { + return -RT_EINVAL; + } + + host->supply.vmmc = rt_regulator_get(dev, "vmmc"); + host->supply.vqmmc = rt_regulator_get(dev, "vqmmc"); + + if (!rt_is_err(host->supply.vmmc)) + { + if (!host->supply.vmmc) + { + LOG_D("No vmmc regulator found"); + } + } + else + { + err = rt_ptr_err(host->supply.vmmc); + goto _fail; + } + + if (!rt_is_err(host->supply.vqmmc)) + { + if (host->supply.vqmmc) + { + LOG_D("No vqmmc regulator found"); + } + } + else + { + err = rt_ptr_err(host->supply.vqmmc); + goto _fail; + } + + return RT_EOK; + +_fail: + if (!rt_is_err_or_null(host->supply.vmmc)) + { + rt_regulator_put(host->supply.vmmc); + host->supply.vmmc = RT_NULL; + } + + if (!rt_is_err_or_null(host->supply.vqmmc)) + { + rt_regulator_put(host->supply.vqmmc); + host->supply.vqmmc = RT_NULL; + } + + return err; +} + +rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host) +{ + struct rt_mmcsd_supply *supply; + + if (!host) + { + return -RT_EINVAL; + } + + supply = &host->supply; + + if (!rt_is_err_or_null(supply->vqmmc) && !supply->vqmmc_enabled) + { + rt_err_t err = rt_regulator_enable(supply->vqmmc); + + if (err) + { + LOG_E("Enabling vqmmc regulator failed error = %s", rt_strerror(err)); + } + else + { + supply->vqmmc_enabled = RT_TRUE; + } + } + + return RT_EOK; +} + +void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host) +{ + struct rt_mmcsd_supply *supply; + + if (!host) + { + return; + } + + supply = &host->supply; + + if (!rt_is_err_or_null(supply->vqmmc) && supply->vqmmc_enabled) + { + rt_regulator_disable(supply->vqmmc); + + supply->vqmmc_enabled = RT_FALSE; + } +} diff --git a/components/drivers/sdio/dev_sd.c b/components/drivers/sdio/dev_sd.c index 22725dbe1d92..58702b903849 100644 --- a/components/drivers/sdio/dev_sd.c +++ b/components/drivers/sdio/dev_sd.c @@ -629,37 +629,13 @@ static rt_err_t mmcsd_read_sd_status(struct rt_mmcsd_card *card, rt_uint32_t *sd return 0; } -static rt_err_t sd_switch_voltage(struct rt_mmcsd_host *host) -{ - rt_err_t err; - struct rt_mmcsd_cmd cmd = { 0 }; - - cmd.cmd_code = VOLTAGE_SWITCH; - cmd.arg = 0; - cmd.flags = RESP_R1 | CMD_AC; - - err = mmcsd_send_cmd(host, &cmd, 0); - if (err) - return err; - - return RT_EOK; -} - -static rt_err_t sd_switch_uhs_voltage(struct rt_mmcsd_host *host) -{ - if (host->ops->switch_uhs_voltage != RT_NULL) - { - return host->ops->switch_uhs_voltage(host); - } - return -ENOSYS; -} - static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host, rt_uint32_t ocr) { struct rt_mmcsd_card *card; rt_int32_t err; rt_uint32_t resp[4]; + rt_uint32_t pocr = ocr; rt_uint32_t max_data_rate; mmcsd_go_idle(host); @@ -675,7 +651,7 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host, ocr |= 1 << 30; /* Switch to UHS voltage if both Host and the Card support this feature */ - if (((host->valid_ocr & VDD_165_195) != 0) && (host->ops->switch_uhs_voltage != RT_NULL)) + if (((host->valid_ocr & VDD_165_195) != 0) && (host->ops->signal_voltage_switch != RT_NULL)) { ocr |= OCR_S18R; } @@ -687,10 +663,7 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host, if (ocr & OCR_S18R) { ocr = VDD_165_195; - err = sd_switch_voltage(host); - if (err) - goto err2; - err = sd_switch_uhs_voltage(host); + err = mmcsd_set_uhs_voltage(host, pocr); if (err) goto err2; } diff --git a/components/drivers/sdio/dev_sdio_dm.c b/components/drivers/sdio/dev_sdio_dm.c new file mode 100644 index 000000000000..1c9b1944e7c1 --- /dev/null +++ b/components/drivers/sdio/dev_sdio_dm.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include +#include "sdio_dm.h" + +#define DBG_TAG "SDIO" +#ifdef RT_SDIO_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_INFO +#endif /* RT_SDIO_DEBUG */ +#include + +int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname) +{ + int id = -1, res; + static int uid_min = -1; + static volatile rt_atomic_t uid = 0; + + RT_ASSERT(host != RT_NULL); + +#ifdef RT_USING_OFW + if (host->ofw_node) + { + id = rt_ofw_get_alias_id(host->ofw_node, "mmc"); + + if (uid_min < 0) + { + uid_min = rt_ofw_get_alias_last_id("mmc"); + uid_min = uid_min < 0 ? 0 : (uid_min + 1); + + rt_atomic_store(&uid, uid_min); + } + } +#endif /* RT_USING_OFW */ + + if (id < 0) + { + id = (int)rt_atomic_add(&uid, 1); + } + + res = rt_snprintf(host->name, RT_NAME_MAX, "sd%u", id); + + if (out_devname) + { + rt_strncpy(out_devname, host->name, RT_NAME_MAX); + } + + return res; +} + +#ifdef RT_USING_OFW +rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host) +{ + rt_uint32_t bus_width = 1; + + if (!dev_np) + { + return -RT_EINVAL; + } + + host->ofw_node = host->ofw_node ? : dev_np; + + host->flags = MMCSD_MUTBLKWRITE; + rt_ofw_prop_read_u32(dev_np, "bus-width", &bus_width); + + switch (bus_width) + { + case 0x8: + host->flags |= MMCSD_BUSWIDTH_8; + break; + + case 0x4: + host->flags |= MMCSD_BUSWIDTH_4; + break; + + case 0x1: + break; + + default: + LOG_E("Invalid \"bus-width\" value %d", bus_width); + return -RT_EIO; + } + + rt_ofw_prop_read_u32(dev_np, "max-frequency", &host->freq_max); + + if (rt_ofw_prop_read_bool(dev_np, "non-removable")) + { + host->flags |= MMCSD_SUP_NONREMOVABLE; + } + + if (rt_ofw_prop_read_bool(dev_np, "cap-sdio-irq")) + { + host->flags |= MMCSD_SUP_SDIO_IRQ; + } + + if (rt_ofw_prop_read_bool(dev_np, "cap-sd-highspeed") || + rt_ofw_prop_read_bool(dev_np, "cap-mmc-highspeed")) + { + host->flags |= MMCSD_SUP_HIGHSPEED; + } + + if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-3_3v")) + { + host->flags |= MMCSD_SUP_DDR_3V3; + } + if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-1_8v")) + { + host->flags |= MMCSD_SUP_DDR_1V8; + } + if (rt_ofw_prop_read_bool(dev_np, "mmc-ddr-1_2v")) + { + host->flags |= MMCSD_SUP_DDR_1V2; + } + + if (rt_ofw_prop_read_bool(dev_np, "mmc-hs200-1_2v")) + { + host->flags |= MMCSD_SUP_HS200_1V2; + } + if (rt_ofw_prop_read_bool(dev_np, "mmc-hs200-1_8v")) + { + host->flags |= MMCSD_SUP_HS200_1V8; + } + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/sdio/dev_sdio_dm.h b/components/drivers/sdio/dev_sdio_dm.h new file mode 100644 index 000000000000..675ff3d442cf --- /dev/null +++ b/components/drivers/sdio/dev_sdio_dm.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#ifndef __DEV_SDIO_DM_H__ +#define __DEV_SDIO_DM_H__ + +#include +#include +#include + +int sdio_host_set_name(struct rt_mmcsd_host *host, char *out_devname); + +#ifdef RT_USING_REGULATOR +rt_err_t sdio_regulator_set_ocr(struct rt_mmcsd_host *host, + struct rt_regulator *supply, rt_uint16_t vdd_bit); +rt_err_t sdio_regulator_set_vqmmc(struct rt_mmcsd_host *host, + struct rt_mmcsd_io_cfg *ios); +rt_err_t sdio_regulator_get_supply(struct rt_device *dev, struct rt_mmcsd_host *host); +rt_err_t sdio_regulator_enable_vqmmc(struct rt_mmcsd_host *host); +void sdio_regulator_disable_vqmmc(struct rt_mmcsd_host *host); +#endif /* RT_USING_REGULATOR */ + +#ifdef RT_USING_OFW +rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host); +#else +rt_inline rt_err_t sdio_ofw_parse(struct rt_ofw_node *dev_np, struct rt_mmcsd_host *host) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +#endif /* __DEV_SDIO_DM_H__ */