mmc: rtsx_usb_sdmmc: qualify card-detect on tray readers
Subsystems (2)
cover mmc: rtsx_usb_sdmmc: qualify card-detect on tray readers
Hi Uffe, USB/cardreader folks,
Uffe suggested sending this as an RFC and adding the USB/cardreader side, because this may need input on where the media qualification should live.
I previously sent an RFC for the USB/cardreader runtime-PM side of this problem. That did not get USB/cardreader-side guidance on the detect layering question; the only substantive feedback was that the MMC child should already own runtime PM for a real inserted card. I have since retested that, and it is correct: with real media inserted, rtsx_usb_sdmmc holds runtime_usage=1 and the USB parent remains active through runtime_active_kids=1.
The remaining failure is narrower: empty tray only. Raw SD_CD remains asserted, the MMC core repeatedly probes non-existent media, and the runtime-PM hierarchy does not settle.
This is an RFC for the Realtek RTS5129 tray-reader false-detect issue.
Short version: on these machines, raw SD_CD is not a reliable "card is present" signal. It is asserted when the tray is inserted, even if the tray contains no SD card.
That means the current driver reports card-present to the MMC core for an empty tray. The MMC core then does what it should do: it tries to initialize a card. The commands time out, no mmcblk device is created, but because SD_CD remains asserted the detect path is entered again. In practice this keeps rtsx_usb_sdmmc runtime-active and prevents the USB parent from autosuspending.
I retested this on an RTS5129 reader:
- tray removed: no mmcblk device, rtsx_usb_sdmmc suspends, USB parent suspends
- empty tray inserted: no mmcblk device, repeated CMD0/CMD8/CMD55/CMD1 probe loop, rtsx_usb_sdmmc remains active, USB parent remains active
- tray + SD card: mmcblk0 appears and reads correctly; the MMC child holds runtime PM as expected
The old Realtek rts5139 staging driver did not treat raw tray/CD state as sufficient. It qualified insertion by checking whether media actually responded before reporting a card present. That approach works on this hardware, and avoids papering over the issue in runtime PM.
I know the previous version put the validation directly in ->get_cd(), and the objection was that MMC command probing does not belong there. I'm not trying to ignore that feedback. The question for this RFC is the layering:
- if the only exposed hardware bit is "tray inserted", not "card present", where should the Realtek-specific media qualification live?
- is an rts5139-style qualification acceptable in rtsx_usb_sdmmc if it is kept out of the generic MMC core?
- or should the USB/cardreader parent expose a qualified media-present state to the SD/MMC child?
This is intentionally copied to linux-usb and the char/misc/cardreader maintainers, not just linux-mmc, because one possible answer is that the USB/cardreader parent should expose a qualified media-present state rather than having rtsx_usb_sdmmc compensate for raw SD_CD.
Patch 2 keeps the validation path in a known initial electrical state by starting SD power-up at 3.3V, matching the old Realtek rts5139 driver. It is included because the validation sequence must not inherit a previous 1.8V state.
I have deliberately left the SDR/UHS rate patches out of this RFC. They are separate capability work and just make this harder to review. This series is only about making tray card-detect correct and stopping the empty-tray detect loop.
Thanks,
Sean
Sean Rhodes (2):
mmc: rtsx_usb_sdmmc: avoid false card-detect on tray readers
mmc: rtsx_usb_sdmmc: start card power-up at 3.3V
drivers/mmc/host/rtsx_usb_sdmmc.c | 161 ++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 8 deletions(-)
RFC PATCH 1/2 mmc: rtsx_usb_sdmmc: avoid false card-detect on tray readers
Some Realtek USB SD readers with a tray can assert SD_CD even when no card is present. This can make the MMC core believe a card exists, and may trigger unnecessary initialization and suspend failures.
Debounce the CD signal and validate a newly detected card by probing for a response (CMD0 + CMD8/CMD55/CMD1) before reporting it present. Also treat SD_INT as a removal indication even if SD_CD stays asserted.
Tested on a Realtek RTS5129 USB reader (0bda:0129):
- Tray inserted, no card: no mmc device created (hot-plug and cold boot)
- Tray + SDXC card: hot-plug and cold boot detect mmcblk0
--- drivers/mmc/host/rtsx_usb_sdmmc.c | 156 ++++++++++++++++++++++++++++-- 1 file changed, 148 insertions(+), 8 deletions(-)
drivers/mmc/host/rtsx_usb_sdmmc.c +148 -8
@@ -19,6 +19,7 @@#include <linux/scatterlist.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/jiffies.h> #include <linux/rtsx_usb.h> #include <linux/unaligned.h>
@@ -30,6 +31,9 @@#define RTSX_USB_USE_LEDS_CLASS #endif +#define RTSX_USB_SD_CD_DEBOUNCE_CNT 2 +#define RTSX_USB_SD_INSERT_RETRY_MS 1000 +struct rtsx_usb_sdmmc {struct platform_device *pdev;struct rtsx_ucr *ucr;
@@ -46,6 +50,8 @@ struct rtsx_usb_sdmmc {bool card_exist;bool initial_mode;bool ddr_mode; +u8 cd_debounce; +unsigned long next_insert_check;unsigned char power_mode;u16 ocp_stat;
@@ -72,6 +78,13 @@ static inline void sd_clear_error(struct rtsx_usb_sdmmc *host)rtsx_usb_clear_fsm_err (ucr); } +static int sd_set_bus_width (struct rtsx_usb_sdmmc *host, +unsigned char bus_width); +static int sd_set_timing (struct rtsx_usb_sdmmc *host, +unsigned char timing,bool *ddr_mode); +static int sd_power_on (struct rtsx_usb_sdmmc *host); +static int sd_power_off (struct rtsx_usb_sdmmc *host); +#ifdef DEBUG static void sd_print_debug_regs (struct rtsx_usb_sdmmc *host) {
@@ -768,12 +781,94 @@ static int sdmmc_get_ro(struct mmc_host *mmc)return 0 ; } +static bool sdmmc_validate_insert_locked (struct rtsx_usb_sdmmc *host) +{ +struct rtsx_ucr *ucr = host->ucr; +struct mmc_command cmd = { }; +int err =0 ; +bool probe_powered = false; +bool ddr_mode = false; + +/* +* Some readers with a tray assert the mechanical SD_CD pin even when no +* card is present. Only report a card present when it responds to a +* minimal reset/probe sequence, similar to the old rts5139 behavior. +* +* Must be called with ucr->dev_mutex held. +*/ +if (host->power_mode ==MMC_POWER_OFF ) { + err =sd_power_on (host); +if (err) +return false; + probe_powered = true; + +/* Issue clock signals to card for at least 74 clocks. */ +rtsx_usb_write_register (ucr,SD_BUS_STAT , +SD_CLK_TOGGLE_EN ,SD_CLK_TOGGLE_EN ); +usleep_range (200 ,400 ); +rtsx_usb_write_register (ucr,SD_BUS_STAT ,SD_CLK_TOGGLE_EN ,0 ); + } + +/* +* Ensure the interface is in a safe, legacy / initial-clock mode before +* probing for a response. The MMC core may not have configured ios yet. +*/ + err =sd_set_bus_width (host,MMC_BUS_WIDTH_1 ); +if (err) + goto out; + + err =sd_set_timing (host,MMC_TIMING_LEGACY , &ddr_mode); +if (err) + goto out; + + ucr->cur_clk =0 ; + err =rtsx_usb_switch_clock (ucr,400000 ,SSC_DEPTH_512K , + true, true, false); +if (err) + goto out; + + cmd.opcode =MMC_GO_IDLE_STATE ; + cmd.arg =0 ; + cmd.flags =MMC_RSP_NONE |MMC_CMD_BC ; +sd_send_cmd_get_rsp (host, &cmd); + +/* SD v2.0+: CMD8 */ + cmd.opcode =SD_SEND_IF_COND ; + cmd.arg =0x1aa ; + cmd.flags =MMC_RSP_R7 |MMC_CMD_BCR ; +sd_send_cmd_get_rsp (host, &cmd); +if (!cmd.error) + goto out; + +/* SD v1.x: CMD55 */ + cmd.opcode =MMC_APP_CMD ; + cmd.arg =0 ; + cmd.flags =MMC_RSP_R1 |MMC_CMD_AC ; +sd_send_cmd_get_rsp (host, &cmd); +if (!cmd.error) + goto out; + +/* MMC: CMD1 */ + cmd.opcode =MMC_SEND_OP_COND ; + cmd.arg =0 ; + cmd.flags =MMC_RSP_R3 |MMC_CMD_BCR ; +sd_send_cmd_get_rsp (host, &cmd); + +out: +if (probe_powered) +sd_power_off (host); +return !err && !cmd.error; +} +static int sdmmc_get_cd (struct mmc_host *mmc) {struct rtsx_usb_sdmmc *host =mmc_priv (mmc);struct rtsx_ucr *ucr = host->ucr;int err;u16 val; +u8 pend; +bool sd_int = false; +bool cd_raw = false;if (host->host_removal)return -ENOMEDIUM ;
@@ -782,28 +877,71 @@ static int sdmmc_get_cd(struct mmc_host *mmc)/* Check SD card detect */ err =rtsx_usb_get_card_status (ucr, &val); - -mutex_unlock (&ucr->dev_mutex); - -/* Treat failed detection as non-exist */ if (err) - goto no_card; + goto no_card_unlock;/* get OCP status */ host->ocp_stat = (val >>4 ) &0x03 ; -if (val &SD_CD ) { - host->card_exist = true; + cd_raw = !!(val &SD_CD ); + +/* Use SD_INT as a reliable removal indication on some tray readers. */ + err =rtsx_usb_read_register (ucr,CARD_INT_PEND , &pend); +if (!err) { + sd_int = !!(pend &SD_INT ); +if (sd_int) +rtsx_usb_write_register (ucr,CARD_INT_PEND , +SD_INT ,SD_INT ); + } + +if (!cd_raw) { + host->cd_debounce =0 ; + host->next_insert_check =0 ; + goto no_card_unlock; + } + +/* +* rts5139-style: when a card is already known present, treat SD_INT as +* a removal event even if SD_CD stays high (e.g. tray-based readers). +*/ +if (host->card_exist) { +if (sd_int) { + host->cd_debounce =0 ; + host->next_insert_check =0 ; + goto no_card_unlock; + } +mutex_unlock (&ucr->dev_mutex);return 1 ; } -no_card: +/* Debounce mechanical CD before probing for a response. */ +if (host->cd_debounce <RTSX_USB_SD_CD_DEBOUNCE_CNT ) { + host->cd_debounce++; + goto no_card_unlock; + } + +/* Avoid pounding the bus with probes if CD is stuck asserted. */ +if (time_before (jiffies, host->next_insert_check)) + goto no_card_unlock; + +if (!sdmmc_validate_insert_locked (host)) { + host->next_insert_check = jiffies + +msecs_to_jiffies (RTSX_USB_SD_INSERT_RETRY_MS ); + goto no_card_unlock; + } + + host->card_exist = true; +mutex_unlock (&ucr->dev_mutex); +return 1 ; + +no_card_unlock:/* clear OCP status */ if (host->ocp_stat & (MS_OCP_NOW |MS_OCP_EVER )) {rtsx_usb_write_register (ucr,OCPCTL ,MS_OCP_CLEAR ,MS_OCP_CLEAR ); host->ocp_stat =0 ; } host->card_exist = false; +mutex_unlock (&ucr->dev_mutex);return 0 ; }
@@ -1359,6 +1497,8 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) host->power_mode =MMC_POWER_OFF ; host->ocp_stat =0 ; + host->cd_debounce =0 ; + host->next_insert_check =0 ; }static int rtsx_usb_sdmmc_drv_probe (struct platform_device *pdev)
RFC PATCH 2/2 mmc: rtsx_usb_sdmmc: start card power-up at 3.3V
In reply to Sean RhodesSome tray-based readers keep SD_CD asserted even without a card. The rtsx_usb_sdmmc driver now validates insertion with a minimal probe sequence. That probe must start with the SD pads in 3.3V mode.
Like the old rts5139 driver (sd_init_power()), force the SD pads to 3.3V and tune the SD18 regulator to 3.3V before powering up the card. This avoids spurious probe timeouts when the reader is left in 1.8V from a previous UHS session.
Tested: Realtek RTS5129 (0bda:0129) + tray + Lexar 2TB SDXC
Tested: cold boot detects mmcblk0 (2026-02-24)
Tested: hotplug insert enumerates mmcblk0 (2026-02-23)
--- drivers/mmc/host/rtsx_usb_sdmmc.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/mmc/host/rtsx_usb_sdmmc.c +5 -0
@@ -1108,6 +1108,11 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host) }dev_dbg (sdmmc_dev (host),"%s\n" , __func__);rtsx_usb_init_cmd (ucr); +/* Start SD init at 3.3V, like the old rts5139 driver. */ +rtsx_usb_add_cmd (ucr,WRITE_REG_CMD ,SD_PAD_CTL , +SD_IO_USING_1V8 ,SD_IO_USING_3V3 ); +rtsx_usb_add_cmd (ucr,WRITE_REG_CMD ,LDO_POWER_CFG , +TUNE_SD18_MASK ,TUNE_SD18_3V3 );rtsx_usb_add_cmd (ucr,WRITE_REG_CMD ,CARD_SELECT ,0x07 ,SD_MOD_SEL );rtsx_usb_add_cmd (ucr,WRITE_REG_CMD ,CARD_SHARE_MODE ,CARD_SHARE_MASK ,CARD_SHARE_SD );
Quoted 45 lines · Sean Rhodes
Hi Uffe, USB/cardreader folks,
Uffe suggested sending this as an RFC and adding the USB/cardreader side, because this may need input on where the media qualification should live.
I previously sent an RFC for the USB/cardreader runtime-PM side of this problem. That did not get USB/cardreader-side guidance on the detect layering question; the only substantive feedback was that the MMC child should already own runtime PM for a real inserted card. I have since retested that, and it is correct: with real media inserted,
rtsx_usb_sdmmcholds runtime_usage=1 and the USB parent remains active through runtime_active_kids=1.The remaining failure is narrower: empty tray only. Raw
SD_CDremains asserted, the MMC core repeatedly probes non-existent media, and the runtime-PM hierarchy does not settle.This is an RFC for the Realtek RTS5129 tray-reader false-detect issue.
Short version: on these machines, raw
SD_CDis not a reliable "card is present" signal. It is asserted when the tray is inserted, even if the tray contains no SD card.That means the current driver reports card-present to the MMC core for an empty tray. The MMC core then does what it should do: it tries to initialize a card. The commands time out, no mmcblk device is created, but because
SD_CDremains asserted the detect path is entered again. In practice this keepsrtsx_usb_sdmmcruntime-active and prevents the USB parent from autosuspending.I retested this on an RTS5129 reader:
- tray removed: no mmcblk device,
rtsx_usb_sdmmcsuspends, USB parent suspends
- empty tray inserted: no mmcblk device, repeated CMD0/CMD8/CMD55/CMD1 probe loop,rtsx_usb_sdmmcremains active, USB parent remains active
- tray + SD card: mmcblk0 appears and reads correctly; the MMC child holds runtime PM as expectedThe old Realtek rts5139 staging driver did not treat raw tray/CD state as sufficient. It qualified insertion by checking whether media actually responded before reporting a card present. That approach works on this hardware, and avoids papering over the issue in runtime PM.
Quoted 6 lines
I know the previous version put the validation directly in ->get_cd(), and the objection was that MMC command probing does not belong there. I'm not trying to ignore that feedback. The question for this RFC is the layering:
- if the only exposed hardware bit is "tray inserted", not "card present", where should the Realtek-specific media qualification live?
It depends on what the media qualification must consist of.
Quoted 2 lines
- is an rts5139-style qualification acceptable in
rtsx_usb_sdmmcif it is kept out of the generic MMC core?
We can certainly add some specific hacks to the rtsx_usb_sdmmc for this, but I think we should be able to do it without having to build/send all the corresponding mmc commands directly in the driver. In principle we should be able to rely on the mmc_rescan() work to do this for us, in one way or the other.
A part that is still a bit unclear to me, is how we should handle the card detect when the tray is/gets inserted. Is it possible to insert/remove a card to the tray when the tray is already inserted - or does the tray need to be removed (and inserted again) to allow this?
Quoted 2 lines
- or should the USB/cardreader parent expose a qualified media-present state to the SD/MMC child?
Is there a way for the USB card reader driver to figure out if there is a "card present"?
I thought all it could do was to signal whether the tray is inserted or not? No?
Quoted 19 lines
This is intentionally copied to linux-usb and the char/misc/cardreader maintainers, not just linux-mmc, because one possible answer is that the USB/cardreader parent should expose a qualified media-present state rather than having
rtsx_usb_sdmmccompensate for rawSD_CD.Patch 2 keeps the validation path in a known initial electrical state by starting SD power-up at 3.3V, matching the old Realtek rts5139 driver. It is included because the validation sequence must not inherit a previous 1.8V state.
I have deliberately left the SDR/UHS rate patches out of this RFC. They are separate capability work and just make this harder to review. This series is only about making tray card-detect correct and stopping the empty-tray detect loop.
Thanks,
Sean
Quoted 6 lines
Sean Rhodes (2):
mmc:rtsx_usb_sdmmc: avoid false card-detect on tray readers
mmc:rtsx_usb_sdmmc: start card power-up at 3.3Vdrivers/mmc/host/rtsx_usb_sdmmc.c | 161 ++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 8 deletions(-)
Kind regards
Uffe