162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* Realtek PCI-Express Memstick Card Interface driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author:
762306a36Sopenharmony_ci *   Wei WANG <wei_wang@realsil.com.cn>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/highmem.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/memstick.h>
1562306a36Sopenharmony_ci#include <linux/rtsx_pci.h>
1662306a36Sopenharmony_ci#include <asm/unaligned.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct realtek_pci_ms {
1962306a36Sopenharmony_ci	struct platform_device	*pdev;
2062306a36Sopenharmony_ci	struct rtsx_pcr		*pcr;
2162306a36Sopenharmony_ci	struct memstick_host	*msh;
2262306a36Sopenharmony_ci	struct memstick_request	*req;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	struct mutex		host_mutex;
2562306a36Sopenharmony_ci	struct work_struct	handle_req;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	u8			ssc_depth;
2862306a36Sopenharmony_ci	unsigned int		clock;
2962306a36Sopenharmony_ci	unsigned char           ifmode;
3062306a36Sopenharmony_ci	bool			eject;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic inline struct device *ms_dev(struct realtek_pci_ms *host)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	return &(host->pdev->dev);
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic inline void ms_clear_error(struct realtek_pci_ms *host)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	rtsx_pci_write_register(host->pcr, CARD_STOP,
4162306a36Sopenharmony_ci			MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#ifdef DEBUG
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic void ms_print_debug_regs(struct realtek_pci_ms *host)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
4962306a36Sopenharmony_ci	u16 i;
5062306a36Sopenharmony_ci	u8 *ptr;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* Print MS host internal registers */
5362306a36Sopenharmony_ci	rtsx_pci_init_cmd(pcr);
5462306a36Sopenharmony_ci	for (i = 0xFD40; i <= 0xFD44; i++)
5562306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
5662306a36Sopenharmony_ci	for (i = 0xFD52; i <= 0xFD69; i++)
5762306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
5862306a36Sopenharmony_ci	rtsx_pci_send_cmd(pcr, 100);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	ptr = rtsx_pci_get_cmd_data(pcr);
6162306a36Sopenharmony_ci	for (i = 0xFD40; i <= 0xFD44; i++)
6262306a36Sopenharmony_ci		dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
6362306a36Sopenharmony_ci	for (i = 0xFD52; i <= 0xFD69; i++)
6462306a36Sopenharmony_ci		dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#else
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define ms_print_debug_regs(host)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int ms_power_on(struct realtek_pci_ms *host)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
7662306a36Sopenharmony_ci	int err;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	rtsx_pci_init_cmd(pcr);
7962306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL);
8062306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE,
8162306a36Sopenharmony_ci			CARD_SHARE_MASK, CARD_SHARE_48_MS);
8262306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN,
8362306a36Sopenharmony_ci			MS_CLK_EN, MS_CLK_EN);
8462306a36Sopenharmony_ci	err = rtsx_pci_send_cmd(pcr, 100);
8562306a36Sopenharmony_ci	if (err < 0)
8662306a36Sopenharmony_ci		return err;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_MS_CARD);
8962306a36Sopenharmony_ci	if (err < 0)
9062306a36Sopenharmony_ci		return err;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	err = rtsx_pci_card_power_on(pcr, RTSX_MS_CARD);
9362306a36Sopenharmony_ci	if (err < 0)
9462306a36Sopenharmony_ci		return err;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* Wait ms power stable */
9762306a36Sopenharmony_ci	msleep(150);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	err = rtsx_pci_write_register(pcr, CARD_OE,
10062306a36Sopenharmony_ci			MS_OUTPUT_EN, MS_OUTPUT_EN);
10162306a36Sopenharmony_ci	if (err < 0)
10262306a36Sopenharmony_ci		return err;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int ms_power_off(struct realtek_pci_ms *host)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
11062306a36Sopenharmony_ci	int err;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	rtsx_pci_init_cmd(pcr);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0);
11562306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	err = rtsx_pci_send_cmd(pcr, 100);
11862306a36Sopenharmony_ci	if (err < 0)
11962306a36Sopenharmony_ci		return err;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	err = rtsx_pci_card_power_off(pcr, RTSX_MS_CARD);
12262306a36Sopenharmony_ci	if (err < 0)
12362306a36Sopenharmony_ci		return err;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int ms_transfer_data(struct realtek_pci_ms *host, unsigned char data_dir,
12962306a36Sopenharmony_ci		u8 tpc, u8 cfg, struct scatterlist *sg)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
13262306a36Sopenharmony_ci	int err;
13362306a36Sopenharmony_ci	unsigned int length = sg->length;
13462306a36Sopenharmony_ci	u16 sec_cnt = (u16)(length / 512);
13562306a36Sopenharmony_ci	u8 val, trans_mode, dma_dir;
13662306a36Sopenharmony_ci	struct memstick_dev *card = host->msh->card;
13762306a36Sopenharmony_ci	bool pro_card = card->id.type == MEMSTICK_TYPE_PRO;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n",
14062306a36Sopenharmony_ci			__func__, tpc, (data_dir == READ) ? "READ" : "WRITE",
14162306a36Sopenharmony_ci			length);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (data_dir == READ) {
14462306a36Sopenharmony_ci		dma_dir = DMA_DIR_FROM_CARD;
14562306a36Sopenharmony_ci		trans_mode = pro_card ? MS_TM_AUTO_READ : MS_TM_NORMAL_READ;
14662306a36Sopenharmony_ci	} else {
14762306a36Sopenharmony_ci		dma_dir = DMA_DIR_TO_CARD;
14862306a36Sopenharmony_ci		trans_mode = pro_card ? MS_TM_AUTO_WRITE : MS_TM_NORMAL_WRITE;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	rtsx_pci_init_cmd(pcr);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
15462306a36Sopenharmony_ci	if (pro_card) {
15562306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_H,
15662306a36Sopenharmony_ci				0xFF, (u8)(sec_cnt >> 8));
15762306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_L,
15862306a36Sopenharmony_ci				0xFF, (u8)sec_cnt);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0,
16362306a36Sopenharmony_ci			DMA_DONE_INT, DMA_DONE_INT);
16462306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, 0xFF, (u8)(length >> 24));
16562306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, 0xFF, (u8)(length >> 16));
16662306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, 0xFF, (u8)(length >> 8));
16762306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)length);
16862306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL,
16962306a36Sopenharmony_ci			0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512);
17062306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
17162306a36Sopenharmony_ci			0x01, RING_BUFFER);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER,
17462306a36Sopenharmony_ci			0xFF, MS_TRANSFER_START | trans_mode);
17562306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER,
17662306a36Sopenharmony_ci			MS_TRANSFER_END, MS_TRANSFER_END);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	rtsx_pci_send_cmd_no_wait(pcr);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	err = rtsx_pci_transfer_data(pcr, sg, 1, data_dir == READ, 10000);
18162306a36Sopenharmony_ci	if (err < 0) {
18262306a36Sopenharmony_ci		ms_clear_error(host);
18362306a36Sopenharmony_ci		return err;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val);
18762306a36Sopenharmony_ci	if (pro_card) {
18862306a36Sopenharmony_ci		if (val & (MS_INT_CMDNK | MS_INT_ERR |
18962306a36Sopenharmony_ci				MS_CRC16_ERR | MS_RDY_TIMEOUT))
19062306a36Sopenharmony_ci			return -EIO;
19162306a36Sopenharmony_ci	} else {
19262306a36Sopenharmony_ci		if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT))
19362306a36Sopenharmony_ci			return -EIO;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int ms_write_bytes(struct realtek_pci_ms *host, u8 tpc,
20062306a36Sopenharmony_ci		u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
20362306a36Sopenharmony_ci	int err, i;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (!data)
20862306a36Sopenharmony_ci		return -EINVAL;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	rtsx_pci_init_cmd(pcr);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	for (i = 0; i < cnt; i++)
21362306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
21462306a36Sopenharmony_ci				PPBUF_BASE2 + i, 0xFF, data[i]);
21562306a36Sopenharmony_ci	if (cnt % 2)
21662306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
21762306a36Sopenharmony_ci				PPBUF_BASE2 + i, 0xFF, 0xFF);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
22062306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
22162306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
22262306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
22362306a36Sopenharmony_ci			0x01, PINGPONG_BUFFER);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER,
22662306a36Sopenharmony_ci			0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES);
22762306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER,
22862306a36Sopenharmony_ci			MS_TRANSFER_END, MS_TRANSFER_END);
22962306a36Sopenharmony_ci	if (int_reg)
23062306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	err = rtsx_pci_send_cmd(pcr, 5000);
23362306a36Sopenharmony_ci	if (err < 0) {
23462306a36Sopenharmony_ci		u8 val;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val);
23762306a36Sopenharmony_ci		dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		if (int_reg)
24062306a36Sopenharmony_ci			*int_reg = val & 0x0F;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		ms_print_debug_regs(host);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		ms_clear_error(host);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		if (!(tpc & 0x08)) {
24762306a36Sopenharmony_ci			if (val & MS_CRC16_ERR)
24862306a36Sopenharmony_ci				return -EIO;
24962306a36Sopenharmony_ci		} else {
25062306a36Sopenharmony_ci			if (!(val & 0x80)) {
25162306a36Sopenharmony_ci				if (val & (MS_INT_ERR | MS_INT_CMDNK))
25262306a36Sopenharmony_ci					return -EIO;
25362306a36Sopenharmony_ci			}
25462306a36Sopenharmony_ci		}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		return -ETIMEDOUT;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (int_reg) {
26062306a36Sopenharmony_ci		u8 *ptr = rtsx_pci_get_cmd_data(pcr) + 1;
26162306a36Sopenharmony_ci		*int_reg = *ptr & 0x0F;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int ms_read_bytes(struct realtek_pci_ms *host, u8 tpc,
26862306a36Sopenharmony_ci		u8 cfg, u8 cnt, u8 *data, u8 *int_reg)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
27162306a36Sopenharmony_ci	int err, i;
27262306a36Sopenharmony_ci	u8 *ptr;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (!data)
27762306a36Sopenharmony_ci		return -EINVAL;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	rtsx_pci_init_cmd(pcr);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
28262306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
28362306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
28462306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
28562306a36Sopenharmony_ci			0x01, PINGPONG_BUFFER);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER,
28862306a36Sopenharmony_ci			0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES);
28962306a36Sopenharmony_ci	rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER,
29062306a36Sopenharmony_ci			MS_TRANSFER_END, MS_TRANSFER_END);
29162306a36Sopenharmony_ci	for (i = 0; i < cnt - 1; i++)
29262306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
29362306a36Sopenharmony_ci	if (cnt % 2)
29462306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0);
29562306a36Sopenharmony_ci	else
29662306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD,
29762306a36Sopenharmony_ci				PPBUF_BASE2 + cnt - 1, 0, 0);
29862306a36Sopenharmony_ci	if (int_reg)
29962306a36Sopenharmony_ci		rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	err = rtsx_pci_send_cmd(pcr, 5000);
30262306a36Sopenharmony_ci	if (err < 0) {
30362306a36Sopenharmony_ci		u8 val;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val);
30662306a36Sopenharmony_ci		dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		if (int_reg)
30962306a36Sopenharmony_ci			*int_reg = val & 0x0F;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		ms_print_debug_regs(host);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		ms_clear_error(host);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		if (!(tpc & 0x08)) {
31662306a36Sopenharmony_ci			if (val & MS_CRC16_ERR)
31762306a36Sopenharmony_ci				return -EIO;
31862306a36Sopenharmony_ci		} else {
31962306a36Sopenharmony_ci			if (!(val & 0x80)) {
32062306a36Sopenharmony_ci				if (val & (MS_INT_ERR | MS_INT_CMDNK))
32162306a36Sopenharmony_ci					return -EIO;
32262306a36Sopenharmony_ci			}
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		return -ETIMEDOUT;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	ptr = rtsx_pci_get_cmd_data(pcr) + 1;
32962306a36Sopenharmony_ci	for (i = 0; i < cnt; i++)
33062306a36Sopenharmony_ci		data[i] = *ptr++;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (int_reg)
33362306a36Sopenharmony_ci		*int_reg = *ptr & 0x0F;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return 0;
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int rtsx_pci_ms_issue_cmd(struct realtek_pci_ms *host)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct memstick_request *req = host->req;
34162306a36Sopenharmony_ci	int err = 0;
34262306a36Sopenharmony_ci	u8 cfg = 0, int_reg;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "%s\n", __func__);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (req->need_card_int) {
34762306a36Sopenharmony_ci		if (host->ifmode != MEMSTICK_SERIAL)
34862306a36Sopenharmony_ci			cfg = WAIT_INT;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (req->long_data) {
35262306a36Sopenharmony_ci		err = ms_transfer_data(host, req->data_dir,
35362306a36Sopenharmony_ci				req->tpc, cfg, &(req->sg));
35462306a36Sopenharmony_ci	} else {
35562306a36Sopenharmony_ci		if (req->data_dir == READ) {
35662306a36Sopenharmony_ci			err = ms_read_bytes(host, req->tpc, cfg,
35762306a36Sopenharmony_ci					req->data_len, req->data, &int_reg);
35862306a36Sopenharmony_ci		} else {
35962306a36Sopenharmony_ci			err = ms_write_bytes(host, req->tpc, cfg,
36062306a36Sopenharmony_ci					req->data_len, req->data, &int_reg);
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci	if (err < 0)
36462306a36Sopenharmony_ci		return err;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (req->need_card_int && (host->ifmode == MEMSTICK_SERIAL)) {
36762306a36Sopenharmony_ci		err = ms_read_bytes(host, MS_TPC_GET_INT,
36862306a36Sopenharmony_ci				NO_WAIT_INT, 1, &int_reg, NULL);
36962306a36Sopenharmony_ci		if (err < 0)
37062306a36Sopenharmony_ci			return err;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (req->need_card_int) {
37462306a36Sopenharmony_ci		dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", int_reg);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		if (int_reg & MS_INT_CMDNK)
37762306a36Sopenharmony_ci			req->int_reg |= MEMSTICK_INT_CMDNAK;
37862306a36Sopenharmony_ci		if (int_reg & MS_INT_BREQ)
37962306a36Sopenharmony_ci			req->int_reg |= MEMSTICK_INT_BREQ;
38062306a36Sopenharmony_ci		if (int_reg & MS_INT_ERR)
38162306a36Sopenharmony_ci			req->int_reg |= MEMSTICK_INT_ERR;
38262306a36Sopenharmony_ci		if (int_reg & MS_INT_CED)
38362306a36Sopenharmony_ci			req->int_reg |= MEMSTICK_INT_CED;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void rtsx_pci_ms_handle_req(struct work_struct *work)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct realtek_pci_ms *host = container_of(work,
39262306a36Sopenharmony_ci			struct realtek_pci_ms, handle_req);
39362306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
39462306a36Sopenharmony_ci	struct memstick_host *msh = host->msh;
39562306a36Sopenharmony_ci	int rc;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	mutex_lock(&pcr->pcr_mutex);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	rtsx_pci_start_run(pcr);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	rtsx_pci_switch_clock(host->pcr, host->clock, host->ssc_depth,
40262306a36Sopenharmony_ci			false, true, false);
40362306a36Sopenharmony_ci	rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, MS_MOD_SEL);
40462306a36Sopenharmony_ci	rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
40562306a36Sopenharmony_ci			CARD_SHARE_MASK, CARD_SHARE_48_MS);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (!host->req) {
40862306a36Sopenharmony_ci		do {
40962306a36Sopenharmony_ci			rc = memstick_next_req(msh, &host->req);
41062306a36Sopenharmony_ci			dev_dbg(ms_dev(host), "next req %d\n", rc);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci			if (!rc)
41362306a36Sopenharmony_ci				host->req->error = rtsx_pci_ms_issue_cmd(host);
41462306a36Sopenharmony_ci		} while (!rc);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	mutex_unlock(&pcr->pcr_mutex);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic void rtsx_pci_ms_request(struct memstick_host *msh)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct realtek_pci_ms *host = memstick_priv(msh);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "--> %s\n", __func__);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD))
42762306a36Sopenharmony_ci		return;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	schedule_work(&host->handle_req);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int rtsx_pci_ms_set_param(struct memstick_host *msh,
43362306a36Sopenharmony_ci		enum memstick_param param, int value)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct realtek_pci_ms *host = memstick_priv(msh);
43662306a36Sopenharmony_ci	struct rtsx_pcr *pcr = host->pcr;
43762306a36Sopenharmony_ci	unsigned int clock = 0;
43862306a36Sopenharmony_ci	u8 ssc_depth = 0;
43962306a36Sopenharmony_ci	int err;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
44262306a36Sopenharmony_ci			__func__, param, value);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD);
44562306a36Sopenharmony_ci	if (err)
44662306a36Sopenharmony_ci		return err;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	switch (param) {
44962306a36Sopenharmony_ci	case MEMSTICK_POWER:
45062306a36Sopenharmony_ci		if (value == MEMSTICK_POWER_ON)
45162306a36Sopenharmony_ci			err = ms_power_on(host);
45262306a36Sopenharmony_ci		else if (value == MEMSTICK_POWER_OFF)
45362306a36Sopenharmony_ci			err = ms_power_off(host);
45462306a36Sopenharmony_ci		else
45562306a36Sopenharmony_ci			return -EINVAL;
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	case MEMSTICK_INTERFACE:
45962306a36Sopenharmony_ci		if (value == MEMSTICK_SERIAL) {
46062306a36Sopenharmony_ci			clock = 19000000;
46162306a36Sopenharmony_ci			ssc_depth = RTSX_SSC_DEPTH_500K;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci			err = rtsx_pci_write_register(pcr, MS_CFG, 0x58,
46462306a36Sopenharmony_ci					MS_BUS_WIDTH_1 | PUSH_TIME_DEFAULT);
46562306a36Sopenharmony_ci			if (err < 0)
46662306a36Sopenharmony_ci				return err;
46762306a36Sopenharmony_ci		} else if (value == MEMSTICK_PAR4) {
46862306a36Sopenharmony_ci			clock = 39000000;
46962306a36Sopenharmony_ci			ssc_depth = RTSX_SSC_DEPTH_1M;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci			err = rtsx_pci_write_register(pcr, MS_CFG,
47262306a36Sopenharmony_ci					0x58, MS_BUS_WIDTH_4 | PUSH_TIME_ODD);
47362306a36Sopenharmony_ci			if (err < 0)
47462306a36Sopenharmony_ci				return err;
47562306a36Sopenharmony_ci		} else {
47662306a36Sopenharmony_ci			return -EINVAL;
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		err = rtsx_pci_switch_clock(pcr, clock,
48062306a36Sopenharmony_ci				ssc_depth, false, true, false);
48162306a36Sopenharmony_ci		if (err < 0)
48262306a36Sopenharmony_ci			return err;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		host->ssc_depth = ssc_depth;
48562306a36Sopenharmony_ci		host->clock = clock;
48662306a36Sopenharmony_ci		host->ifmode = value;
48762306a36Sopenharmony_ci		break;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return 0;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci#ifdef CONFIG_PM
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int rtsx_pci_ms_suspend(struct platform_device *pdev, pm_message_t state)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct realtek_pci_ms *host = platform_get_drvdata(pdev);
49862306a36Sopenharmony_ci	struct memstick_host *msh = host->msh;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "--> %s\n", __func__);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	memstick_suspend_host(msh);
50362306a36Sopenharmony_ci	return 0;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic int rtsx_pci_ms_resume(struct platform_device *pdev)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct realtek_pci_ms *host = platform_get_drvdata(pdev);
50962306a36Sopenharmony_ci	struct memstick_host *msh = host->msh;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	dev_dbg(ms_dev(host), "--> %s\n", __func__);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	memstick_resume_host(msh);
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci#else /* CONFIG_PM */
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci#define rtsx_pci_ms_suspend NULL
52062306a36Sopenharmony_ci#define rtsx_pci_ms_resume NULL
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci#endif /* CONFIG_PM */
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic void rtsx_pci_ms_card_event(struct platform_device *pdev)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct realtek_pci_ms *host = platform_get_drvdata(pdev);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	memstick_detect_change(host->msh);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int rtsx_pci_ms_drv_probe(struct platform_device *pdev)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	struct memstick_host *msh;
53462306a36Sopenharmony_ci	struct realtek_pci_ms *host;
53562306a36Sopenharmony_ci	struct rtsx_pcr *pcr;
53662306a36Sopenharmony_ci	struct pcr_handle *handle = pdev->dev.platform_data;
53762306a36Sopenharmony_ci	int rc;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (!handle)
54062306a36Sopenharmony_ci		return -ENXIO;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	pcr = handle->pcr;
54362306a36Sopenharmony_ci	if (!pcr)
54462306a36Sopenharmony_ci		return -ENXIO;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	dev_dbg(&(pdev->dev),
54762306a36Sopenharmony_ci			": Realtek PCI-E Memstick controller found\n");
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	msh = memstick_alloc_host(sizeof(*host), &pdev->dev);
55062306a36Sopenharmony_ci	if (!msh)
55162306a36Sopenharmony_ci		return -ENOMEM;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	host = memstick_priv(msh);
55462306a36Sopenharmony_ci	host->pcr = pcr;
55562306a36Sopenharmony_ci	host->msh = msh;
55662306a36Sopenharmony_ci	host->pdev = pdev;
55762306a36Sopenharmony_ci	platform_set_drvdata(pdev, host);
55862306a36Sopenharmony_ci	pcr->slots[RTSX_MS_CARD].p_dev = pdev;
55962306a36Sopenharmony_ci	pcr->slots[RTSX_MS_CARD].card_event = rtsx_pci_ms_card_event;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	mutex_init(&host->host_mutex);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	INIT_WORK(&host->handle_req, rtsx_pci_ms_handle_req);
56462306a36Sopenharmony_ci	msh->request = rtsx_pci_ms_request;
56562306a36Sopenharmony_ci	msh->set_param = rtsx_pci_ms_set_param;
56662306a36Sopenharmony_ci	msh->caps = MEMSTICK_CAP_PAR4;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	rc = memstick_add_host(msh);
56962306a36Sopenharmony_ci	if (rc) {
57062306a36Sopenharmony_ci		memstick_free_host(msh);
57162306a36Sopenharmony_ci		return rc;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return 0;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int rtsx_pci_ms_drv_remove(struct platform_device *pdev)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct realtek_pci_ms *host = platform_get_drvdata(pdev);
58062306a36Sopenharmony_ci	struct rtsx_pcr *pcr;
58162306a36Sopenharmony_ci	struct memstick_host *msh;
58262306a36Sopenharmony_ci	int rc;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (!host)
58562306a36Sopenharmony_ci		return 0;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	pcr = host->pcr;
58862306a36Sopenharmony_ci	pcr->slots[RTSX_MS_CARD].p_dev = NULL;
58962306a36Sopenharmony_ci	pcr->slots[RTSX_MS_CARD].card_event = NULL;
59062306a36Sopenharmony_ci	msh = host->msh;
59162306a36Sopenharmony_ci	host->eject = true;
59262306a36Sopenharmony_ci	cancel_work_sync(&host->handle_req);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	mutex_lock(&host->host_mutex);
59562306a36Sopenharmony_ci	if (host->req) {
59662306a36Sopenharmony_ci		dev_dbg(&(pdev->dev),
59762306a36Sopenharmony_ci			"%s: Controller removed during transfer\n",
59862306a36Sopenharmony_ci			dev_name(&msh->dev));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		rtsx_pci_complete_unfinished_transfer(pcr);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		host->req->error = -ENOMEDIUM;
60362306a36Sopenharmony_ci		do {
60462306a36Sopenharmony_ci			rc = memstick_next_req(msh, &host->req);
60562306a36Sopenharmony_ci			if (!rc)
60662306a36Sopenharmony_ci				host->req->error = -ENOMEDIUM;
60762306a36Sopenharmony_ci		} while (!rc);
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci	mutex_unlock(&host->host_mutex);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	memstick_remove_host(msh);
61262306a36Sopenharmony_ci	memstick_free_host(msh);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	dev_dbg(&(pdev->dev),
61562306a36Sopenharmony_ci		": Realtek PCI-E Memstick controller has been removed\n");
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic struct platform_device_id rtsx_pci_ms_ids[] = {
62162306a36Sopenharmony_ci	{
62262306a36Sopenharmony_ci		.name = DRV_NAME_RTSX_PCI_MS,
62362306a36Sopenharmony_ci	}, {
62462306a36Sopenharmony_ci		/* sentinel */
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci};
62762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic struct platform_driver rtsx_pci_ms_driver = {
63062306a36Sopenharmony_ci	.probe		= rtsx_pci_ms_drv_probe,
63162306a36Sopenharmony_ci	.remove		= rtsx_pci_ms_drv_remove,
63262306a36Sopenharmony_ci	.id_table       = rtsx_pci_ms_ids,
63362306a36Sopenharmony_ci	.suspend	= rtsx_pci_ms_suspend,
63462306a36Sopenharmony_ci	.resume		= rtsx_pci_ms_resume,
63562306a36Sopenharmony_ci	.driver		= {
63662306a36Sopenharmony_ci		.name	= DRV_NAME_RTSX_PCI_MS,
63762306a36Sopenharmony_ci	},
63862306a36Sopenharmony_ci};
63962306a36Sopenharmony_cimodule_platform_driver(rtsx_pci_ms_driver);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
64262306a36Sopenharmony_ciMODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>");
64362306a36Sopenharmony_ciMODULE_DESCRIPTION("Realtek PCI-E Memstick Card Host Driver");
644