aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoredwin_rong <edwin_rong@realsil.com.cn>2011-07-19 17:10:35 +0800
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-23 12:11:46 -0700
commit1dac4186bcc663cb8c2bcc59481aea8fe9124a6c (patch)
tree6313380d862a0a128ddd4f05ef1be3b5f74b9002
parentdd89e20d7e9d507b3122de2f79661b5fc2c2198e (diff)
Staging: add driver for Realtek RTS5139 cardreader
This driver is used for Realtek RTS5139 USB cardreader, which supports many cards, such as SD, MS, XD series cards. Signed-off-by: edwin_rong <edwin_rong@realsil.com.cn> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/rts5139/Kconfig16
-rw-r--r--drivers/staging/rts5139/Makefile37
-rw-r--r--drivers/staging/rts5139/TODO5
-rw-r--r--drivers/staging/rts5139/debug.h46
-rw-r--r--drivers/staging/rts5139/ms.c4190
-rw-r--r--drivers/staging/rts5139/ms.h263
-rw-r--r--drivers/staging/rts5139/ms_mg.c642
-rw-r--r--drivers/staging/rts5139/ms_mg.h41
-rw-r--r--drivers/staging/rts5139/rts51x.c967
-rw-r--r--drivers/staging/rts5139/rts51x.h205
-rw-r--r--drivers/staging/rts5139/rts51x_card.c986
-rw-r--r--drivers/staging/rts5139/rts51x_card.h881
-rw-r--r--drivers/staging/rts5139/rts51x_chip.c1167
-rw-r--r--drivers/staging/rts5139/rts51x_chip.h904
-rw-r--r--drivers/staging/rts5139/rts51x_fop.c298
-rw-r--r--drivers/staging/rts5139/rts51x_fop.h62
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.c2233
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.h162
-rw-r--r--drivers/staging/rts5139/rts51x_sys.h54
-rw-r--r--drivers/staging/rts5139/rts51x_transport.c1000
-rw-r--r--drivers/staging/rts5139/rts51x_transport.h80
-rw-r--r--drivers/staging/rts5139/sd.c3400
-rw-r--r--drivers/staging/rts5139/sd.h304
-rw-r--r--drivers/staging/rts5139/sd_cprm.c1215
-rw-r--r--drivers/staging/rts5139/sd_cprm.h54
-rw-r--r--drivers/staging/rts5139/trace.h137
-rw-r--r--drivers/staging/rts5139/xd.c2254
-rw-r--r--drivers/staging/rts5139/xd.h193
30 files changed, 21799 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 06c9081d596..a097763529f 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -64,6 +64,8 @@ source "drivers/staging/rtl8712/Kconfig"
source "drivers/staging/rts_pstor/Kconfig"
+source "drivers/staging/rts5139/Kconfig"
+
source "drivers/staging/frontier/Kconfig"
source "drivers/staging/pohmelfs/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index f3c5e33bb26..a84a6b331b3 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_RTS_PSTOR) += rts_pstor/
+obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_SPECTRA) += spectra/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_POHMELFS) += pohmelfs/
diff --git a/drivers/staging/rts5139/Kconfig b/drivers/staging/rts5139/Kconfig
new file mode 100644
index 00000000000..f940e516945
--- /dev/null
+++ b/drivers/staging/rts5139/Kconfig
@@ -0,0 +1,16 @@
+config RTS5139
+ tristate "Realtek RTS5139 USB card reader support"
+ depends on USB_SUPPORT && SCSI
+ help
+ Say Y here to include driver code to support the Realtek
+ RTS5139 USB card readers.
+
+ If this driver is compiled as a module, it will be named rts5139.
+
+config RTS5139_DEBUG
+ bool "Realtek RTS5139 Card Reader verbose debug"
+ depends on RTS5139
+ help
+ Say Y here in order to have the rts5139 code generate
+ verbose debugging messages.
+
diff --git a/drivers/staging/rts5139/Makefile b/drivers/staging/rts5139/Makefile
new file mode 100644
index 00000000000..82b8958e8d3
--- /dev/null
+++ b/drivers/staging/rts5139/Makefile
@@ -0,0 +1,37 @@
+# Driver for Realtek RTS51xx USB card reader
+#
+# Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# Author:
+# wwang (wei_wang@realsil.com.cn)
+# No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+# Maintainer:
+# Edwin Rong (edwin_rong@realsil.com.cn)
+# No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+#
+# Makefile for the RTS51xx USB Card Reader drivers.
+#
+
+TARGET_MODULE := rts5139
+
+EXTRA_CFLAGS := -Idrivers/scsi -I$(PWD)
+
+obj-m += $(TARGET_MODULE).o
+
+common-obj := rts51x_transport.o rts51x_scsi.o rts51x_fop.o
+
+$(TARGET_MODULE)-objs := $(common-obj) rts51x.o rts51x_chip.o rts51x_card.o \
+ xd.o sd.o ms.o sd_cprm.o ms_mg.o
diff --git a/drivers/staging/rts5139/TODO b/drivers/staging/rts5139/TODO
new file mode 100644
index 00000000000..4bde726ea5f
--- /dev/null
+++ b/drivers/staging/rts5139/TODO
@@ -0,0 +1,5 @@
+TODO:
+- support more USB card reader of Realtek family
+- use kernel coding style
+- checkpatch.pl fixes
+
diff --git a/drivers/staging/rts5139/debug.h b/drivers/staging/rts5139/debug.h
new file mode 100644
index 00000000000..73dec133a1b
--- /dev/null
+++ b/drivers/staging/rts5139/debug.h
@@ -0,0 +1,46 @@
+/* Driver for Realtek RTS51xx USB card reader
+ * Header file
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * wwang (wei_wang@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ * Maintainer:
+ * Edwin Rong (edwin_rong@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#ifndef __RTS51X_DEBUG_H
+#define __RTS51X_DEBUG_H
+
+#include <linux/kernel.h>
+
+#define RTS51X_TIP "rts51x: "
+
+#ifdef CONFIG_RTS5139_DEBUG
+#define RTS51X_DEBUGP(x...) printk(KERN_DEBUG RTS51X_TIP x)
+#define RTS51X_DEBUGPN(x...) printk(KERN_DEBUG x)
+#define RTS51X_DEBUGPX(x...) printk(x)
+#define RTS51X_DEBUG(x) x
+#else
+#define RTS51X_DEBUGP(x...)
+#define RTS51X_DEBUGPN(x...)
+#define RTS51X_DEBUGPX(x...)
+#define RTS51X_DEBUG(x)
+#endif
+
+#endif /* __RTS51X_DEBUG_H */
diff --git a/drivers/staging/rts5139/ms.c b/drivers/staging/rts5139/ms.c
new file mode 100644
index 00000000000..63f191dd031
--- /dev/null
+++ b/drivers/staging/rts5139/ms.c
@@ -0,0 +1,4190 @@
+/* Driver for Realtek RTS51xx USB card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * wwang (wei_wang@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ * Maintainer:
+ * Edwin Rong (edwin_rong@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "debug.h"
+#include "trace.h"
+#include "rts51x.h"
+#include "rts51x_transport.h"
+#include "rts51x_scsi.h"
+#include "rts51x_card.h"
+#include "ms.h"
+
+static inline void ms_set_err_code(struct rts51x_chip *chip, u8 err_code)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+
+ ms_card->err_code = err_code;
+}
+
+static inline int ms_check_err_code(struct rts51x_chip *chip, u8 err_code)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+
+ return (ms_card->err_code == err_code);
+}
+
+static int ms_parse_err_code(struct rts51x_chip *chip)
+{
+ TRACE_RET(chip, STATUS_FAIL);
+}
+
+static int ms_transfer_tpc(struct rts51x_chip *chip, u8 trans_mode, u8 tpc,
+ u8 cnt, u8 cfg)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+
+ RTS51X_DEBUGP("ms_transfer_tpc: tpc = 0x%x\n", tpc);
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
+ PINGPONG_BUFFER);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
+ MS_TRANSFER_START | trans_mode);
+ rts51x_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END,
+ MS_TRANSFER_END);
+
+ rts51x_add_cmd(chip, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
+
+ retval = rts51x_send_cmd(chip, MODE_CR, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval = rts51x_get_rsp(chip, 2, 5000);
+ if (CHECK_MS_TRANS_FAIL(chip, retval)) {
+ rts51x_clear_ms_error(chip);
+ ms_set_err_code(chip, MS_TO_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+
+ if (!(tpc & 0x08)) { /* Read Packet */
+ /* Check CRC16 & Ready Timeout */
+ if (chip->rsp_buf[1] & MS_CRC16_ERR) {
+ ms_set_err_code(chip, MS_CRC16_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+ } else { /* Write Packet */
+ if (CHK_MSPRO(ms_card) && !(chip->rsp_buf[1] & 0x80)) {
+ if (chip->rsp_buf[1] & (MS_INT_ERR | MS_INT_CMDNK)) {
+ ms_set_err_code(chip, MS_CMD_NK);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+ }
+ }
+
+ /* Check Timeout of Ready Signal */
+ if (chip->rsp_buf[1] & MS_RDY_TIMEOUT) {
+ rts51x_clear_ms_error(chip);
+ ms_set_err_code(chip, MS_TO_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int ms_transfer_data(struct rts51x_chip *chip, u8 trans_mode, u8 tpc,
+ u16 sec_cnt, u8 cfg, int mode_2k, int use_sg, void *buf,
+ int buf_len)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+ u8 val, err_code = 0, flag = 0;
+ enum dma_data_direction dir;
+ unsigned int pipe;
+
+ if (!buf || !buf_len)
+ TRACE_RET(chip, STATUS_FAIL);
+
+ if (trans_mode == MS_TM_AUTO_READ) {
+ pipe = RCV_BULK_PIPE(chip);
+ dir = DMA_FROM_DEVICE;
+ flag = MODE_CDIR;
+ err_code = MS_FLASH_READ_ERROR;
+ } else if (trans_mode == MS_TM_AUTO_WRITE) {
+ pipe = SND_BULK_PIPE(chip);
+ dir = DMA_TO_DEVICE;
+ flag = MODE_CDOR;
+ err_code = MS_FLASH_WRITE_ERROR;
+ } else {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_SECTOR_CNT_H, 0xFF,
+ (u8) (sec_cnt >> 8));
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_SECTOR_CNT_L, 0xFF,
+ (u8) sec_cnt);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
+ RING_BUFFER);
+
+ if (mode_2k)
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_CFG, MS_2K_SECTOR_MODE,
+ MS_2K_SECTOR_MODE);
+ else
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_CFG, MS_2K_SECTOR_MODE,
+ 0);
+
+ trans_dma_enable(dir, chip, sec_cnt * 512, DMA_512);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
+ MS_TRANSFER_START | trans_mode);
+ rts51x_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END,
+ MS_TRANSFER_END);
+
+ retval = rts51x_send_cmd(chip, flag | STAGE_MS_STATUS, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval =
+ rts51x_transfer_data_rcc(chip, pipe, buf, buf_len, use_sg, NULL,
+ 15000, flag);
+ if (retval != STATUS_SUCCESS) {
+ ms_set_err_code(chip, err_code);
+ rts51x_clear_ms_error(chip);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = rts51x_get_rsp(chip, 3, 15000);
+ if (CHECK_MS_TRANS_FAIL(chip, retval)) {
+ ms_set_err_code(chip, err_code);
+ rts51x_clear_ms_error(chip);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ ms_card->last_rw_int = val = chip->rsp_buf[1];
+ if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT))
+ TRACE_RET(chip, STATUS_FAIL);
+
+ return STATUS_SUCCESS;
+}
+
+int ms_write_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *data,
+ int data_len)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval, i;
+
+ if (!data || (data_len < cnt))
+ TRACE_RET(chip, STATUS_ERROR);
+
+ rts51x_init_cmd(chip);
+
+ for (i = 0; i < cnt; i++) {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF,
+ data[i]);
+ }
+ if (cnt % 2)
+ rts51x_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i,
+ 0xFF, 0xFF);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
+ PINGPONG_BUFFER);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
+ MS_TRANSFER_START | MS_TM_WRITE_BYTES);
+ rts51x_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END,
+ MS_TRANSFER_END);
+
+ retval = rts51x_send_cmd(chip, MODE_CR, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval = rts51x_get_rsp(chip, 1, 5000);
+ if (CHECK_MS_TRANS_FAIL(chip, retval)) {
+ u8 val = 0;
+
+ rts51x_ep0_read_register(chip, MS_TRANS_CFG, &val);
+ RTS51X_DEBUGP("MS_TRANS_CFG: 0x%02x\n", val);
+
+ rts51x_clear_ms_error(chip);
+
+ if (!(tpc & 0x08)) { /* Read Packet */
+ /* Check CRC16 & Ready Timeout */
+ if (val & MS_CRC16_ERR) {
+ ms_set_err_code(chip, MS_CRC16_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+ } else { /* Write Packet */
+ if (CHK_MSPRO(ms_card) && !(val & 0x80)) {
+ if (val & (MS_INT_ERR | MS_INT_CMDNK)) {
+ ms_set_err_code(chip, MS_CMD_NK);
+ TRACE_RET(chip,
+ ms_parse_err_code(chip));
+ }
+ }
+ }
+
+ /* Check Timeout of Ready Signal */
+ if (val & MS_RDY_TIMEOUT) {
+ ms_set_err_code(chip, MS_TO_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+
+ ms_set_err_code(chip, MS_TO_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int ms_read_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *data,
+ int data_len)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval, i;
+
+ if (!data)
+ TRACE_RET(chip, STATUS_ERROR);
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
+ PINGPONG_BUFFER);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
+ MS_TRANSFER_START | MS_TM_READ_BYTES);
+ rts51x_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END,
+ MS_TRANSFER_END);
+
+ for (i = 0; i < data_len - 1; i++)
+ rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
+
+ if (data_len % 2)
+ rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0,
+ 0);
+ else
+ rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1,
+ 0, 0);
+
+ retval = rts51x_send_cmd(chip, MODE_CR, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval = rts51x_get_rsp(chip, data_len + 1, 5000);
+ if (CHECK_MS_TRANS_FAIL(chip, retval)) {
+ u8 val = 0;
+
+ rts51x_ep0_read_register(chip, MS_TRANS_CFG, &val);
+ RTS51X_DEBUGP("MS_TRANS_CFG: 0x%02x\n", val);
+
+ rts51x_clear_ms_error(chip);
+
+ if (!(tpc & 0x08)) { /* Read Packet */
+ /* Check CRC16 & Ready Timeout */
+ if (val & MS_CRC16_ERR) {
+ ms_set_err_code(chip, MS_CRC16_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+ } else { /* Write Packet */
+ if (CHK_MSPRO(ms_card) && !(val & 0x80)) {
+ if (val & (MS_INT_ERR | MS_INT_CMDNK)) {
+ ms_set_err_code(chip, MS_CMD_NK);
+ TRACE_RET(chip,
+ ms_parse_err_code(chip));
+ }
+ }
+ }
+
+ /* Check Timeout of Ready Signal */
+ if (val & MS_RDY_TIMEOUT) {
+ ms_set_err_code(chip, MS_TO_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+
+ ms_set_err_code(chip, MS_TO_ERROR);
+ TRACE_RET(chip, ms_parse_err_code(chip));
+ }
+
+ rts51x_read_rsp_buf(chip, 1, data, data_len);
+
+ return STATUS_SUCCESS;
+}
+
+int ms_set_rw_reg_addr(struct rts51x_chip *chip,
+ u8 read_start, u8 read_cnt, u8 write_start, u8 write_cnt)
+{
+ int retval, i;
+ u8 data[4];
+
+ data[0] = read_start;
+ data[1] = read_cnt;
+ data[2] = write_start;
+ data[3] = write_cnt;
+
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
+ retval =
+ ms_write_bytes(chip, SET_RW_REG_ADRS, 4, NO_WAIT_INT, data,
+ 4);
+ if (retval == STATUS_SUCCESS)
+ return STATUS_SUCCESS;
+ rts51x_clear_ms_error(chip);
+ }
+
+ TRACE_RET(chip, STATUS_FAIL);
+}
+
+static int ms_send_cmd(struct rts51x_chip *chip, u8 cmd, u8 cfg)
+{
+ u8 data[2];
+
+ data[0] = cmd;
+ data[1] = 0;
+
+ return ms_write_bytes(chip, PRO_SET_CMD, 1, cfg, data, 1);
+}
+
+static int ms_set_cmd(struct rts51x_chip *chip,
+ u8 read_start, u8 read_count,
+ u8 write_start, u8 write_count,
+ u8 cmd, u8 cfg, u8 *data, int data_len, u8 *int_stat)
+{
+ int retval, i;
+ u8 val;
+
+ if (!data || (data_len <= 0) || (data_len > 128)) {
+ RTS51X_DEBUGP("ms_set_cmd (data_len = %d)\n", data_len);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ retval =
+ ms_set_rw_reg_addr(chip, read_start, read_count, write_start,
+ write_count);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
+ retval =
+ ms_write_bytes(chip, WRITE_REG, write_count, NO_WAIT_INT,
+ data, data_len);
+ if (retval == STATUS_SUCCESS)
+ break;
+ }
+ if (i == MS_MAX_RETRY_COUNT)
+ TRACE_RET(chip, STATUS_FAIL);
+
+ ms_set_err_code(chip, MS_NO_ERROR);
+
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
+ retval = ms_send_cmd(chip, cmd, WAIT_INT);
+ if (retval == STATUS_SUCCESS)
+ break;
+ }
+ if (i == MS_MAX_RETRY_COUNT)
+ TRACE_RET(chip, STATUS_FAIL);
+ /* GET_INT Register */
+ ms_set_err_code(chip, MS_NO_ERROR);
+ retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ if (int_stat)
+ *int_stat = val;
+
+ return STATUS_SUCCESS;
+}
+
+#ifdef MS_SPEEDUP
+static int ms_auto_set_cmd(struct rts51x_chip *chip,
+ u8 read_start, u8 read_count,
+ u8 write_start, u8 write_count,
+ u8 cmd, u8 cfg, u8 *data, int data_len,
+ u8 *int_stat)
+{
+ int retval;
+ int i;
+
+ if (!data || (data_len <= 0) || (data_len > 128)) {
+ RTS51X_DEBUGP("ms_auto_set_cmd (data_len = %d)\n", data_len);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_READ_START, 0xFF, read_start);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_READ_COUNT, 0xFF, read_count);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_WRITE_START, 0xFF, write_start);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_WRITE_COUNT, 0xFF, write_count);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_COMMAND, 0xFF, cmd);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
+ PINGPONG_BUFFER);
+
+ for (i = 0; i < data_len; i++) {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF,
+ data[i]);
+ }
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
+ MS_TRANSFER_START | MS_TM_SET_CMD);
+ rts51x_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END,
+ MS_TRANSFER_END);
+
+ retval = rts51x_send_cmd(chip, MODE_CR | STAGE_MS_STATUS, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval = rts51x_get_rsp(chip, 3, 5000);
+
+ if (CHECK_MS_TRANS_FAIL(chip, retval)) {
+ rts51x_clear_ms_error(chip);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ if (int_stat)
+ *int_stat = chip->rsp_buf[2];
+
+ return STATUS_SUCCESS;
+}
+#endif
+
+static int ms_set_init_para(struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+
+ if (CHK_HG8BIT(ms_card)) {
+ if (chip->asic_code)
+ ms_card->ms_clock = chip->option.asic_ms_hg_clk;
+ else
+ ms_card->ms_clock = chip->option.fpga_ms_hg_clk;
+ } else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) {
+ if (chip->asic_code)
+ ms_card->ms_clock = chip->option.asic_ms_4bit_clk;
+ else
+ ms_card->ms_clock = chip->option.fpga_ms_4bit_clk;
+ } else {
+ if (chip->asic_code)
+ ms_card->ms_clock = 38;
+ else
+ ms_card->ms_clock = CLK_40;
+ }
+
+ retval = switch_clock(chip, ms_card->ms_clock);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval = rts51x_select_card(chip, MS_CARD);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ return STATUS_SUCCESS;
+}
+
+int ms_switch_clock(struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+
+ retval = rts51x_select_card(chip, MS_CARD);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ retval = switch_clock(chip, ms_card->ms_clock);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ return STATUS_SUCCESS;
+}
+
+static void ms_pull_ctl_disable(struct rts51x_chip *chip)
+{
+ if (CHECK_PKG(chip, LQFP48)) {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
+ } else {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
+ }
+}
+
+static void ms_pull_ctl_enable(struct rts51x_chip *chip)
+{
+ if (CHECK_PKG(chip, LQFP48)) {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
+ } else {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
+ }
+}
+
+static int ms_prepare_reset(struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+
+ ms_card->ms_type = 0;
+ ms_card->check_ms_flow = 0;
+ ms_card->switch_8bit_fail = 0;
+ ms_card->delay_write.delay_write_flag = 0;
+
+ ms_card->pro_under_formatting = 0;
+
+ rts51x_init_cmd(chip);
+
+ if (chip->asic_code) {
+ ms_pull_ctl_enable(chip);
+ } else {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL,
+ FPGA_MS_PULL_CTL_BIT | 0x20, 0);
+ }
+ /* Tri-state MS output */
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
+
+ if (!chip->option.FT2_fast_mode) {
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
+ POWER_OFF);
+ }
+
+ retval = rts51x_send_cmd(chip, MODE_C, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ if (!chip->option.FT2_fast_mode) {
+ wait_timeout(250);
+
+ card_power_on(chip, MS_CARD);
+ wait_timeout(150);
+
+#ifdef SUPPORT_OCP
+ rts51x_get_card_status(chip, &(chip->card_status));
+ /* get OCP status */
+ chip->ocp_stat = (chip->card_status >> 4) & 0x03;
+
+ if (chip->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
+ RTS51X_DEBUGP("Over current, OCPSTAT is 0x%x\n",
+ chip->ocp_stat);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+#endif
+ }
+
+ rts51x_init_cmd(chip);
+
+ /* Enable MS Output */
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN,
+ MS_OUTPUT_EN);
+
+ /* Reset Registers */
+ if (chip->asic_code)
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_CFG, 0xFF,
+ SAMPLE_TIME_RISING | PUSH_TIME_DEFAULT |
+ NO_EXTEND_TOGGLE | MS_BUS_WIDTH_1);
+ else
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_CFG, 0xFF,
+ SAMPLE_TIME_FALLING | PUSH_TIME_DEFAULT |
+ NO_EXTEND_TOGGLE | MS_BUS_WIDTH_1);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF,
+ NO_WAIT_INT | NO_AUTO_READ_INT_REG);
+
+ retval = rts51x_send_cmd(chip, MODE_C, 100);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ return ms_set_init_para(chip);
+}
+
+static int ms_identify_media_type(struct rts51x_chip *chip, int switch_8bit_bus)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval, i;
+ u8 val;
+
+ retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1);
+ if (retval != STATUS_SUCCESS)
+ TRACE_RET(chip, retval);
+
+ /* Get Register form MS-PRO card */
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
+ retval =
+ ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG, 6,
+ NO_WAIT_INT);
+ if (retval == STATUS_SUCCESS)
+ break;
+ }
+ if (i == MS_MAX_RETRY_COUNT)
+ TRACE_RET(chip, STATUS_FAIL);
+
+ RTS51X_READ_REG(chip, PPBUF_BASE2 + 2, &val);
+ RTS51X_DEBUGP("Type register: 0x%x\n", val);
+ if (val != 0x01) {
+ if (val != 0x02)
+ ms_card->check_ms_flow = 1;
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+ /* Category Register */
+ RTS51X_READ_REG(chip, PPBUF_BASE2 + 4, &val);
+ RTS51X_DEBUGP("Category register: 0x%x\n", val);
+ if (val != 0) {
+ ms_card->check_ms_flow = 1;
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+ /* Class Register */
+ RTS51X_READ_REG(chip, PPBUF_BASE2 + 5, &val);
+ RTS51X_DEBUGP("Class register: 0x%x\n", val);
+ if (val == 0) {
+ RTS51X_READ_REG(chip, PPBUF_BASE2, &val);
+ if (val & WRT_PRTCT)
+ chip->card_wp |= MS_CARD;
+ else
+ chip->card_wp &= ~MS_CARD;
+ } else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) {
+ chip->card_wp |= MS_CARD;
+ } else {
+ ms_card->check_ms_flow = 1;
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ ms_card->ms_type |= TYPE_MSPRO;
+
+ /* Check MSPro-HG Card, use IF Mode Register to distinguish */
+ RTS51X_READ_REG(chip, PPBUF_BASE2 + 3, &val);
+ RTS51X_DEBUGP("IF Mode register: 0x%x\n", val);
+ if (val == 0) {
+ ms_card->ms_type &= 0x0F;
+ } else if (val == 7) {
+ if (switch_8bit_bus)
+ ms_card->ms_type |= MS_HG;
+ else
+ ms_card->ms_type &= 0x0F;
+ } else {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ /* end Procedure to identify Media Type */
+ return STATUS_SUCCESS;
+}
+
+static int ms_confirm_cpu_startup(struct rts51x_chip *chip)
+{
+ int retval, i, k;
+ u8 val;
+
+ /* Confirm CPU StartUp */
+ k = 0;
+ do {
+ if (monitor_card_cd(chip, MS_CARD) == CD_NOT_EXIST)
+ TRACE_RET(chip, STATUS_FAIL);
+
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
+ retval =
+ ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val,
+ 1);
+ if (retval == STATUS_SUCCESS)
+ break;
+ }
+ if (i == MS_MAX_RETRY_COUNT)
+ TRACE_RET(chip, STATUS_FAIL);
+
+ if (k > 100)
+ TRACE_RET(chip, STATUS_FAIL);
+ k++;
+ wait_timeout(100);
+ } while (!(val & INT_REG_CED));
+
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++