// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/kernel.h>
#include "rtsx.h"
#include "sd.h"
#include "xd.h"
#include "ms.h"
void do_remaining_work(struct rtsx_chip *chip)
{
struct sd_info *sd_card = &chip->sd_card;
#ifdef XD_DELAY_WRITE
struct xd_info *xd_card = &chip->xd_card;
#endif
struct ms_info *ms_card = &chip->ms_card;
if (chip->card_ready & SD_CARD) {
if (sd_card->seq_mode) {
rtsx_set_stat(chip, RTSX_STAT_RUN);
sd_card->cleanup_counter++;
} else {
sd_card->cleanup_counter = 0;
}
}
#ifdef XD_DELAY_WRITE
if (chip->card_ready & XD_CARD) {
if (xd_card->delay_write.delay_write_flag) {
rtsx_set_stat(chip, RTSX_STAT_RUN);
xd_card->cleanup_counter++;
} else {
xd_card->cleanup_counter = 0;
}
}
#endif
if (chip->card_ready & MS_CARD) {
if (CHK_MSPRO(ms_card)) {
if (ms_card->seq_mode) {
rtsx_set_stat(chip, RTSX_STAT_RUN);
ms_card->cleanup_counter++;
} else {
ms_card->cleanup_counter = 0;
}
} else {
#ifdef MS_DELAY_WRITE
if (ms_card->delay_write.delay_write_flag) {
rtsx_set_stat(chip, RTSX_STAT_RUN);
ms_card->cleanup_counter++;
} else {
ms_card->cleanup_counter = 0;
}
#endif
}
}
if (sd_card->cleanup_counter > POLLING_WAIT_CNT)
sd_cleanup_work(chip);
if (xd_card->cleanup_counter > POLLING_WAIT_CNT)
xd_cleanup_work(chip);
if (ms_card->cleanup_counter > POLLING_WAIT_CNT)
ms_cleanup_work(chip);
}
void try_to_switch_sdio_ctrl(struct rtsx_chip *chip)
{
u8 reg1 = 0, reg2 = 0;
rtsx_read_register(chip, 0xFF34, ®1);
rtsx_read_register(chip, 0xFF38, ®2);
dev_dbg(rtsx_dev(chip), "reg 0xFF34: 0x%x, reg 0xFF38: 0x%x\n",
reg1, reg2);
if ((reg1 & 0xC0) && (reg2 & 0xC0)) {
chip->sd_int = 1;
rtsx_write_register(chip, SDIO_CTRL, 0xFF,
SDIO_BUS_CTRL | SDIO_CD_CTRL);
rtsx_write_register(chip, PWR_GATE_CTRL,
LDO3318_PWR_MASK, LDO_ON);
}
}
#ifdef SUPPORT_SDIO_ASPM
void dynamic_configure_sdio_aspm(struct rtsx_chip *chip)
{
u8 buf[12], reg;
int i;
for (i = 0; i < 12; i++)
rtsx_read_register(chip, 0xFF08 + i, &buf[i]);
rtsx_read_register(chip, 0xFF25, ®);
if ((memcmp(buf, chip->sdio_raw_data, 12) != 0) || (reg & 0x03)) {
chip->sdio_counter = 0;
chip->sdio_idle = 0;
} else {
if (!chip->sdio_idle) {
chip->sdio_counter++;
if (chip->sdio_counter >= SDIO_IDLE_COUNT) {
chip->sdio_counter = 0;
chip->sdio_idle = 1;
}
}
}
memcpy(chip->sdio_raw_data, buf, 12);
if (chip->sdio_idle) {
if (!chip->sdio_aspm) {
dev_dbg(rtsx_dev(chip), "SDIO enter ASPM!\n");
rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC,
0x30 | (chip->aspm_level[1] << 2));
chip->sdio_aspm = 1;
}
} else {
if (chip->sdio_aspm) {
dev_dbg(rtsx_dev(chip), "SDIO exit ASPM!\n");
rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC, 0x30);
chip->sdio_aspm = 0;
}
}
}
#endif
void