// SPDX-License-Identifier: GPL-2.0-or-later
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* Author:
* Ricky Wu <ricky_wu@realtek.com>
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/rtsx_pci.h>
#include "rts5264.h"
#include "rtsx_pcr.h"
static u8 rts5264_get_ic_version(struct rtsx_pcr *pcr)
{
u8 val;
rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
return val & 0x0F;
}
static void rts5264_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
{
u8 driving_3v3[4][3] = {
{0x88, 0x88, 0x88},
{0x77, 0x77, 0x77},
{0x99, 0x99, 0x99},
{0x66, 0x66, 0x66},
};
u8 driving_1v8[4][3] = {
{0x99, 0x99, 0x99},
{0x77, 0x77, 0x77},
{0xBB, 0xBB, 0xBB},
{0x65, 0x65, 0x65},
};
u8 (*driving)[3], drive_sel;
if (voltage == OUTPUT_3V3) {
driving = driving_3v3;
drive_sel = pcr->sd30_drive_sel_3v3;
} else {
driving = driving_1v8;
drive_sel = pcr->sd30_drive_sel_1v8;
}
rtsx_pci_write_register(pcr, SD30_CLK_DRIVE_SEL,
0xFF, driving[drive_sel][0]);
rtsx_pci_write_register(pcr, SD30_CMD_DRIVE_SEL,
0xFF, driving[drive_sel][1]);
rtsx_pci_write_register(pcr, SD30_DAT_DRIVE_SEL,
0xFF, driving[drive_sel][2]);
}
static void rts5264_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
{
/* Set relink_time to 0 */
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
RELINK_TIME_MASK, 0);
if (pm_state == HOST_ENTER_S3)
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
if (!runtime) {
rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG1,
CD_RESUME_EN_MASK, 0);
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
} else {
rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
FORCE_PM_CONTROL | FORCE_PM_VALUE, 0);
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01);
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
D3_DELINK_MODE_EN, 0);
rtsx_pci_write_register(pcr, RTS5264_FW_CTL,
RTS5264_INFORM_RTD3_COLD, RTS5264_INFORM_RTD3_COLD);
rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG4,
RTS5264_FORCE_PRSNT_LOW, RTS5264_FORCE_PRSNT_LOW);
}
rtsx_pci_write_register(pcr, RTS5264_REG_FPDCTL,
SSC_POWER_DOWN, SSC_POWER_DOWN);
}
static int rts5264_enable_auto_blink(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
LED_SHINE_MASK, LED_SHINE_EN);
}
static int rts5264_disable_auto_blink(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
LED_SHINE_MASK, LED_SHINE_DISABLE);
}
static int rts5264_turn_on_led(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, GPIO_CTL,
0x02, 0x02);
}
static int rts5264_turn_off_led(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, GPIO_CTL,
0x02, 0x00);
}
/* SD Pull Control Enable:
* SD_DAT[3:0] ==> pull up
* SD_CD ==> pull up
* SD_WP ==> pull up
* SD_CMD ==> pull up
* SD_CLK ==> pull down
*/
static const u32 rts5264_sd_pull_ctl_enable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
0,
};
/* SD Pull Control Disable:
* SD_DAT[3:0] ==> pull down
* SD_CD ==> pull up
* SD_WP ==> pull down
* SD_CMD ==> pull down
* SD_CLK ==> pull down
*/
static const u32 rts5264_sd_pull_ctl_disable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
0,
};
static int rts5264_sd_set_sample_push_timing_sd30(struct rtsx_pcr *pcr)
{
rtsx_pci_write_register(pcr, SD_CFG1, SD_MODE_SELECT_MASK
| SD_ASYNC_FIFO_NOT_RST, SD_30_MODE | SD_ASYNC_FIFO_NOT_RST);
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ,