From 57f35bbf5af5831e0d266923dc335cce4ec3b7be Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 15 Nov 2021 11:45:02 -0600 Subject: [PATCH] drivers: USDHC: Enable detection using DAT3 pulldown Enable USDHC host to detect inserted SD card via DAT3 line pulldown. Signed-off-by: Daniel DeGrasse --- drivers/disk/Kconfig.sdmmc | 4 +++ drivers/disk/Kconfig.usdhc | 18 ++++++++++ drivers/disk/usdhc.c | 53 +++++++++++++++++++++++++++-- dts/bindings/mmc/nxp,imx-usdhc.yaml | 8 +++++ soc/arm/nxp_imx/rt/soc.h | 6 ++++ soc/arm/nxp_imx/rt/soc_rt10xx.c | 19 +++++++++++ soc/arm/nxp_imx/rt/soc_rt11xx.c | 19 +++++++++++ 7 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 drivers/disk/Kconfig.usdhc diff --git a/drivers/disk/Kconfig.sdmmc b/drivers/disk/Kconfig.sdmmc index 7344fb1251a..3d929e63aec 100644 --- a/drivers/disk/Kconfig.sdmmc +++ b/drivers/disk/Kconfig.sdmmc @@ -41,6 +41,10 @@ config SDMMC_USDHC File system on a SDHC card accessed over NXP USDHC. +if SDMMC_USDHC +source "drivers/disk/Kconfig.usdhc" +endif + config SDMMC_STM32 bool "STM32 SDMMC driver" depends on HAS_STM32CUBE diff --git a/drivers/disk/Kconfig.usdhc b/drivers/disk/Kconfig.usdhc new file mode 100644 index 00000000000..bbaede52ff2 --- /dev/null +++ b/drivers/disk/Kconfig.usdhc @@ -0,0 +1,18 @@ +# Copyright (c) 2021 NXP +# SPDX-License-Identifier: Apache-2.0 + +# USDHC peripheral require the SD card to power cycle after DAT3 is +# pulled low +config SDMMC_USDHC_DAT3_PWR_TOGGLE + bool + help + USDHC peripheral requires the SD card power to be cycled after DAT3 is + pulled high, before the USDHC peripheral can detect the SD card via DAT3 + pull + +config SDMMC_USDHC_DAT3_PWR_DELAY + int + default 0 + help + Period in milliseconds to delay between powering off the SD card and + applying power again, whenever the SD card power will be cycled. diff --git a/drivers/disk/usdhc.c b/drivers/disk/usdhc.c index a071ddce837..e966d19cc94 100644 --- a/drivers/disk/usdhc.c +++ b/drivers/disk/usdhc.c @@ -388,6 +388,8 @@ struct usdhc_config { uint8_t detect_pin; gpio_dt_flags_t detect_flags; + bool detect_dat3; + bool no_1_8_v; uint32_t data_timeout; @@ -515,6 +517,9 @@ enum usdhc_xfer_data_type { #define CARD_BUS_STRENGTH_6 (6U) #define CARD_BUS_STRENGTH_7 (7U) +#define USDHC_DAT3_PULL_DOWN 0U /*!< Data 3 pull down */ +#define USDHC_DAT3_PULL_UP 1U /*!< Data 3 pull up */ + enum usdhc_adma_flag { USDHC_ADMA_SINGLE_FLAG = 0U, USDHC_ADMA_MUTI_FLAG = 1U, @@ -2604,6 +2609,33 @@ APP_SEND_OP_COND_AGAIN: static K_MUTEX_DEFINE(z_usdhc_init_lock); + +static int usdhc_dat3_pull(bool pullup, struct usdhc_priv *priv) +{ + int ret = 0U; + + /* Call board specific function to pull down DAT3 */ + imxrt_usdhc_dat3_pull(pullup); +#ifdef CONFIG_SDMMC_USDHC_DAT3_PWR_TOGGLE + if (!pullup) { + /* Power off the card to clear DAT3 legacy status */ + if (priv->pwr_gpio) { + ret = gpio_pin_set(priv->pwr_gpio, priv->config->pwr_pin, 0); + if (ret) { + return ret; + } + /* Delay for card power off to complete */ + usdhc_millsec_delay(CONFIG_SDMMC_USDHC_DAT3_PWR_DELAY); + ret = gpio_pin_set(priv->pwr_gpio, priv->config->pwr_pin, 1); + if (ret) { + return ret; + } + } + } +#endif + return ret; +} + static int usdhc_board_access_init(struct usdhc_priv *priv) { const struct usdhc_config *config = priv->config; @@ -2626,6 +2658,11 @@ static int usdhc_board_access_init(struct usdhc_priv *priv) } } + if (config->detect_dat3) { + priv->detect_type = SD_DETECT_HOST_DATA3; + } + + if (priv->pwr_gpio) { ret = gpio_pin_configure(priv->pwr_gpio, config->pwr_pin, @@ -2643,10 +2680,21 @@ static int usdhc_board_access_init(struct usdhc_priv *priv) if (!priv->detect_gpio) { LOG_INF("USDHC detection other than GPIO"); - /* DATA3 does not monitor card insertion */ - base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; + if (config->detect_dat3) { + base->PROT_CTRL |= USDHC_PROT_CTRL_D3CD_MASK; + /* Pull down DAT3 */ + usdhc_dat3_pull(USDHC_DAT3_PULL_DOWN, priv); + } else { + /* DATA3 does not monitor card insertion */ + base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; + } if ((base->PRES_STATE & USDHC_PRES_STATE_CINST_MASK) != 0) { priv->inserted = true; + if (config->detect_dat3) { + usdhc_dat3_pull(USDHC_DAT3_PULL_UP, priv); + /* Disable DAT3 detect function */ + base->PROT_CTRL &= ~USDHC_PROT_CTRL_D3CD_MASK; + } } else { priv->inserted = false; return -ENODEV; @@ -2853,6 +2901,7 @@ static int disk_usdhc_init(const struct device *dev) DISK_ACCESS_USDHC_INIT_PWR(n) \ DISK_ACCESS_USDHC_INIT_CD(n) \ .no_1_8_v = DT_INST_PROP(n, no_1_8_v), \ + .detect_dat3 = DT_INST_PROP(n, detect_dat3), \ .data_timeout = USDHC_DATA_TIMEOUT, \ .endian = USDHC_LITTLE_ENDIAN, \ .read_watermark = USDHC_READ_WATERMARK_LEVEL, \ diff --git a/dts/bindings/mmc/nxp,imx-usdhc.yaml b/dts/bindings/mmc/nxp,imx-usdhc.yaml index 8f42c3f2e53..9bc1a0f14d2 100644 --- a/dts/bindings/mmc/nxp,imx-usdhc.yaml +++ b/dts/bindings/mmc/nxp,imx-usdhc.yaml @@ -36,5 +36,13 @@ properties: When the external SD card circuit does not support 1.8V, add this property to disable 1.8v card voltage of SD card controller. + detect-dat3: + type: boolean + required: false + description: | + Enable the host to detect an SD card via the DAT3 line of the SD card + connection. Requires the board to define a function to pull DAT3 low or + high using pullup/pulldown resistors. + label: required: true diff --git a/soc/arm/nxp_imx/rt/soc.h b/soc/arm/nxp_imx/rt/soc.h index 826def7bce5..c3d45030636 100644 --- a/soc/arm/nxp_imx/rt/soc.h +++ b/soc/arm/nxp_imx/rt/soc.h @@ -32,6 +32,12 @@ void imxrt_usdhc_pinmux(uint16_t nusdhc, void imxrt_usdhc_pinmux_cb_register(usdhc_pin_cfg_cb cb); +typedef void (*usdhc_dat3_cfg_cb)(bool pullup); + +void imxrt_usdhc_dat3_cb_register(usdhc_dat3_cfg_cb cb); + +void imxrt_usdhc_dat3_pull(bool pullup); + #endif #ifdef __cplusplus diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index 3a0d972b4b4..56f1f67fe65 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -261,6 +261,25 @@ void imxrt_usdhc_pinmux(uint16_t nusdhc, bool init, g_usdhc_pin_cfg_cb(nusdhc, init, speed, strength); } + +/* Usdhc driver needs to reconfigure the dat3 line to a pullup in order to + * detect an SD card on the bus. Expose a callback to do that here. The board + * must register this callback in its init function. + */ +static usdhc_dat3_cfg_cb g_usdhc_dat3_cfg_cb; + +void imxrt_usdhc_dat3_cb_register(usdhc_dat3_cfg_cb cb) +{ + g_usdhc_dat3_cfg_cb = cb; +} + +void imxrt_usdhc_dat3_pull(bool pullup) +{ + if (g_usdhc_dat3_cfg_cb) { + g_usdhc_dat3_cfg_cb(pullup); + } +} + #endif /** diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index 13b2ad6542a..899f6776930 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -426,6 +426,25 @@ void imxrt_usdhc_pinmux(uint16_t nusdhc, bool init, g_usdhc_pin_cfg_cb(nusdhc, init, speed, strength); } + +/* Usdhc driver needs to reconfigure the dat3 line to a pullup in order to + * detect an SD card on the bus. Expose a callback to do that here. The board + * must register this callback in its init function. + */ +static usdhc_dat3_cfg_cb g_usdhc_dat3_cfg_cb; + +void imxrt_usdhc_dat3_cb_register(usdhc_dat3_cfg_cb cb) +{ + g_usdhc_dat3_cfg_cb = cb; +} + +void imxrt_usdhc_dat3_pull(bool pullup) +{ + if (g_usdhc_dat3_cfg_cb) { + g_usdhc_dat3_cfg_cb(pullup); + } +} + #endif /**