[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAPDyKFr+emHfakqJHYjd+17uWPyh8fdVB50CLJLkGz3yJCPO9g@mail.gmail.com>
Date: Mon, 18 Aug 2025 12:55:22 +0200
From: Ulf Hansson <ulf.hansson@...aro.org>
To: Ricky Wu <ricky_wu@...ltek.com>
Cc: linux-kernel@...r.kernel.org, linux-mmc@...r.kernel.org, arnd@...db.de,
gregkh@...uxfoundation.org, chenhuacai@...nel.org, maximlevitsky@...il.com,
kernel test robot <lkp@...el.com>
Subject: Re: [PATCH v2] misc: rtsx: usb card reader: add OCP support
On Tue, 12 Aug 2025 at 05:08, Ricky Wu <ricky_wu@...ltek.com> wrote:
>
> 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.
>
> Reported-by: kernel test robot <lkp@...el.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202508061704.hwI8epAJ-lkp@intel.com/
> Signed-off-by: Ricky Wu <ricky_wu@...ltek.com>
Applied for next and by removing the Reported-by/Closes tags, thanks!
Kind regards
Uffe
> ...
>
> v2: move ocp check in power_on flow
> ---
> drivers/memstick/host/rtsx_usb_ms.c | 5 ++++-
> drivers/misc/cardreader/rtsx_usb.c | 7 ++++++
> drivers/mmc/host/rtsx_usb_sdmmc.c | 33 ++++++++++++++++++++++++++---
> include/linux/rtsx_usb.h | 11 ++++++++++
> 4 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c
> index 3878136227e4..9389e9643c24 100644
> --- a/drivers/memstick/host/rtsx_usb_ms.c
> +++ b/drivers/memstick/host/rtsx_usb_ms.c
> @@ -216,7 +216,10 @@ static int ms_power_off(struct rtsx_usb_ms *host)
>
> rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0);
> rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
> -
> + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
> + POWER_MASK, POWER_OFF);
> + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
> + POWER_MASK | LDO3318_PWR_MASK, POWER_OFF | LDO_SUSPEND);
> err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
> if (err < 0)
> return err;
> diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
> index d007a4455ce5..1830e9ed2521 100644
> --- a/drivers/misc/cardreader/rtsx_usb.c
> +++ b/drivers/misc/cardreader/rtsx_usb.c
> @@ -552,6 +552,10 @@ static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr)
> ret = rtsx_usb_send_cmd(ucr, MODE_C, 100);
> if (ret)
> return ret;
> + /* config OCP */
> + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_DETECT_EN, MS_OCP_DETECT_EN);
> + rtsx_usb_write_register(ucr, OCPPARA1, 0xF0, 0x50);
> + rtsx_usb_write_register(ucr, OCPPARA2, 0x7, 0x3);
>
> /* config non-crystal mode */
> rtsx_usb_read_register(ucr, CFG_MODE, &val);
> @@ -722,6 +726,9 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
> if (val & (SD_CD | MS_CD)) {
> device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
> return -EAGAIN;
> + } else {
> + /* if the card does not exists, clear OCP status */
> + rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR);
> }
> } else {
> /* There is an ongoing operation*/
> diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
> index c5f6b9df066b..e1ed39c657c3 100644
> --- a/drivers/mmc/host/rtsx_usb_sdmmc.c
> +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
> @@ -48,7 +48,7 @@ struct rtsx_usb_sdmmc {
> bool ddr_mode;
>
> unsigned char power_mode;
> -
> + u16 ocp_stat;
> #ifdef RTSX_USB_USE_LEDS_CLASS
> struct led_classdev led;
> char led_name[32];
> @@ -785,6 +785,9 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
>
> mutex_unlock(&ucr->dev_mutex);
>
> + /* get OCP status */
> + host->ocp_stat = (val >> 4) & 0x03;
> +
> /* Treat failed detection as non-exist */
> if (err)
> goto no_card;
> @@ -795,6 +798,11 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
> }
>
> no_card:
> + /* 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;
> return 0;
> }
> @@ -818,7 +826,11 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
> cmd->error = -ENOMEDIUM;
> goto finish_detect_card;
> }
> -
> + /* check OCP stat */
> + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
> + cmd->error = -ENOMEDIUM;
> + goto finish_detect_card;
> + }
> mutex_lock(&ucr->dev_mutex);
>
> mutex_lock(&host->host_mutex);
> @@ -952,6 +964,10 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host)
> struct rtsx_ucr *ucr = host->ucr;
> int err;
>
> + if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
> + dev_dbg(sdmmc_dev(host), "over current\n");
> + return -EIO;
> + }
> dev_dbg(sdmmc_dev(host), "%s\n", __func__);
> rtsx_usb_init_cmd(ucr);
> rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
> @@ -977,9 +993,19 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host)
>
> usleep_range(800, 1000);
>
> + rtsx_usb_init_cmd(ucr);
> + /* WA OCP issue: after OCP, there were problems with reopen card power */
> + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_ON);
> + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, FPDCTL, SSC_POWER_MASK, SSC_POWER_DOWN);
> + err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
> + if (err)
> + return err;
> + msleep(20);
> + rtsx_usb_write_register(ucr, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
> + usleep_range(180, 200);
> rtsx_usb_init_cmd(ucr);
> rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
> - POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON);
> + LDO3318_PWR_MASK, LDO_ON);
> rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
> SD_OUTPUT_EN, SD_OUTPUT_EN);
>
> @@ -1332,6 +1358,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
> mmc->max_req_size = 524288;
>
> host->power_mode = MMC_POWER_OFF;
> + host->ocp_stat = 0;
> }
>
> static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
> diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h
> index f267a06c6b1e..276b509c03e3 100644
> --- a/include/linux/rtsx_usb.h
> +++ b/include/linux/rtsx_usb.h
> @@ -99,6 +99,17 @@ extern int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card);
> #define CD_MASK (SD_CD | MS_CD | XD_CD)
> #define SD_WP 0x08
>
> +/* OCPCTL */
> +#define MS_OCP_DETECT_EN 0x08
> +#define MS_OCP_INT_EN 0x04
> +#define MS_OCP_INT_CLR 0x02
> +#define MS_OCP_CLEAR 0x01
> +
> +/* OCPSTAT */
> +#define MS_OCP_DETECT 0x80
> +#define MS_OCP_NOW 0x02
> +#define MS_OCP_EVER 0x01
> +
> /* reader command field offset & parameters */
> #define READ_REG_CMD 0
> #define WRITE_REG_CMD 1
> --
> 2.25.1
>
Powered by blists - more mailing lists