Closed
Description
Describe problem solved by the proposed feature
在新的主线上已经支持 switch_uhs_voltage
ops,但是目前看上去他更像操作 signal voltage switch 的子集,如果让驱动 ops 实现改进如下是否更好:
struct rt_mmcsd_host_ops
{
void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
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);
/* 设置 uhs 模式或者其他场景可能会用到 */
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);
};
参考实现:
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;
}
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)
{
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);
}
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;
}
在原先的 mmcsd_power_up
阶段中,还需要对电压做初始化,从高调到低:
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");
}
}
static void mmcsd_power_up(struct rt_mmcsd_host *host)
{
[...]
host->io_cfg.power_mode = MMCSD_POWER_UP;
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.
*/
rt_thread_mdelay(10);
[...]
}
主要目的还是为了统一一个电压切换接口并且传递更多参数。
Describe your preferred solution
No response
Describe possible alternatives
No response
Metadata
Metadata
Assignees
Labels
No labels