Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: rtsx: usb card reader: add OCP support

This patch adds support for Over Current Protection (OCP) to the Realtek
USB card reader driver.

The OCP mechanism protects the hardware by detecting and handling current
overload conditions.
This implementation includes:

- Register configurations to enable OCP monitoring.
- Handling of OCP interrupt events and associated error reporting.
- Card power management changes in response to OCP triggers.

This enhancement improves the robustness of the driver when operating in
environments where electrical anomalies may occur, particularly with SD
and MS card interfaces.

Signed-off-by: Ricky Wu <ricky_wu@realtek.com>
Link: https://lore.kernel.org/r/20250812030811.2426112-1-ricky_wu@realtek.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Ricky Wu and committed by
Ulf Hansson
d2e6fb2c b65e630a

+52 -4
+4 -1
drivers/memstick/host/rtsx_usb_ms.c
··· 216 216 217 217 rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); 218 218 rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); 219 - 219 + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, 220 + POWER_MASK, POWER_OFF); 221 + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, 222 + POWER_MASK | LDO3318_PWR_MASK, POWER_OFF | LDO_SUSPEND); 220 223 err = rtsx_usb_send_cmd(ucr, MODE_C, 100); 221 224 if (err < 0) 222 225 return err;
+7
drivers/misc/cardreader/rtsx_usb.c
··· 552 552 ret = rtsx_usb_send_cmd(ucr, MODE_C, 100); 553 553 if (ret) 554 554 return ret; 555 + /* config OCP */ 556 + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_DETECT_EN, MS_OCP_DETECT_EN); 557 + rtsx_usb_write_register(ucr, OCPPARA1, 0xF0, 0x50); 558 + rtsx_usb_write_register(ucr, OCPPARA2, 0x7, 0x3); 555 559 556 560 /* config non-crystal mode */ 557 561 rtsx_usb_read_register(ucr, CFG_MODE, &val); ··· 726 722 if (val & (SD_CD | MS_CD)) { 727 723 device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child); 728 724 return -EAGAIN; 725 + } else { 726 + /* if the card does not exists, clear OCP status */ 727 + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR); 729 728 } 730 729 } else { 731 730 /* There is an ongoing operation*/
+30 -3
drivers/mmc/host/rtsx_usb_sdmmc.c
··· 48 48 bool ddr_mode; 49 49 50 50 unsigned char power_mode; 51 - 51 + u16 ocp_stat; 52 52 #ifdef RTSX_USB_USE_LEDS_CLASS 53 53 struct led_classdev led; 54 54 char led_name[32]; ··· 785 785 786 786 mutex_unlock(&ucr->dev_mutex); 787 787 788 + /* get OCP status */ 789 + host->ocp_stat = (val >> 4) & 0x03; 790 + 788 791 /* Treat failed detection as non-exist */ 789 792 if (err) 790 793 goto no_card; ··· 798 795 } 799 796 800 797 no_card: 798 + /* clear OCP status */ 799 + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) { 800 + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR); 801 + host->ocp_stat = 0; 802 + } 801 803 host->card_exist = false; 802 804 return 0; 803 805 } ··· 826 818 cmd->error = -ENOMEDIUM; 827 819 goto finish_detect_card; 828 820 } 829 - 821 + /* check OCP stat */ 822 + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) { 823 + cmd->error = -ENOMEDIUM; 824 + goto finish_detect_card; 825 + } 830 826 mutex_lock(&ucr->dev_mutex); 831 827 832 828 mutex_lock(&host->host_mutex); ··· 964 952 struct rtsx_ucr *ucr = host->ucr; 965 953 int err; 966 954 955 + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) { 956 + dev_dbg(sdmmc_dev(host), "over current\n"); 957 + return -EIO; 958 + } 967 959 dev_dbg(sdmmc_dev(host), "%s\n", __func__); 968 960 rtsx_usb_init_cmd(ucr); 969 961 rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); ··· 994 978 usleep_range(800, 1000); 995 979 996 980 rtsx_usb_init_cmd(ucr); 981 + /* WA OCP issue: after OCP, there were problems with reopen card power */ 982 + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_ON); 983 + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, FPDCTL, SSC_POWER_MASK, SSC_POWER_DOWN); 984 + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); 985 + if (err) 986 + return err; 987 + msleep(20); 988 + rtsx_usb_write_register(ucr, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON); 989 + usleep_range(180, 200); 990 + rtsx_usb_init_cmd(ucr); 997 991 rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, 998 - POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON); 992 + LDO3318_PWR_MASK, LDO_ON); 999 993 rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, 1000 994 SD_OUTPUT_EN, SD_OUTPUT_EN); 1001 995 ··· 1358 1332 mmc->max_req_size = 524288; 1359 1333 1360 1334 host->power_mode = MMC_POWER_OFF; 1335 + host->ocp_stat = 0; 1361 1336 } 1362 1337 1363 1338 static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
+11
include/linux/rtsx_usb.h
··· 99 99 #define CD_MASK (SD_CD | MS_CD | XD_CD) 100 100 #define SD_WP 0x08 101 101 102 + /* OCPCTL */ 103 + #define MS_OCP_DETECT_EN 0x08 104 + #define MS_OCP_INT_EN 0x04 105 + #define MS_OCP_INT_CLR 0x02 106 + #define MS_OCP_CLEAR 0x01 107 + 108 + /* OCPSTAT */ 109 + #define MS_OCP_DETECT 0x80 110 + #define MS_OCP_NOW 0x02 111 + #define MS_OCP_EVER 0x01 112 + 102 113 /* reader command field offset & parameters */ 103 114 #define READ_REG_CMD 0 104 115 #define WRITE_REG_CMD 1