summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c
diff options
context:
space:
mode:
authorRoman Yeryomin <roman@advem.lv>2013-05-17 20:40:24 +0300
committerRoman Yeryomin <roman@advem.lv>2013-05-17 20:40:24 +0300
commite6d87036412b952cb083eff2dc716aee97a771f2 (patch)
tree273dd3daaa85553832d3cc6d48276229dc7fbe09 /target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c
parenta18fec42221baa52fff4c5ffd45ec8f32e3add36 (diff)
Move to rsdk 3.2.4. Compiles cleanly.
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Diffstat (limited to 'target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c')
-rw-r--r--target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c1252
1 files changed, 1252 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c b/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c
new file mode 100644
index 000000000..7dfee9ae5
--- /dev/null
+++ b/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_chip.c
@@ -0,0 +1,1252 @@
+/* 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:
+ *
+ * Author:
+ * wwang (wei_wang@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/workqueue.h>
+
+#include "debug.h"
+#include "trace.h"
+#include "rts51x.h"
+#include "rts51x_chip.h"
+#include "rts51x_card.h"
+#include "rts51x_transport.h"
+#include "rts51x_sys.h"
+#include "xd.h"
+#include "ms.h"
+#include "sd.h"
+
+static int check_sd_speed_prior(u32 sd_speed_prior)
+{
+ int i, fake_para = 0;
+
+ for (i = 0; i < 4; i++) {
+ u8 tmp = (u8)(sd_speed_prior >> (i*8));
+ if ((tmp < 0x01) || (tmp > 0x04)) {
+ fake_para = 1;
+ break;
+ }
+ }
+
+ return !fake_para;
+}
+
+int rts51x_reset_chip(struct rts51x_chip *chip)
+{
+ int retval;
+
+ if(CHECK_PKG(chip, LQFP48)){
+ RTS51X_WRITE_REG(chip, CARD_PWR_CTL, LDO3318_PWR_MASK, LDO_SUSPEND);
+ RTS51X_WRITE_REG(chip, CARD_PWR_CTL, FORCE_LDO_POWERB, FORCE_LDO_POWERB);
+ RTS51X_WRITE_REG(chip, CARD_PULL_CTL1, 0x30, 0x10);
+ RTS51X_WRITE_REG(chip, CARD_PULL_CTL5, 0x03, 0x01);
+ RTS51X_WRITE_REG(chip, CARD_PULL_CTL6, 0x0C, 0x04);
+ }
+
+ if (chip->asic_code) {
+ RTS51X_WRITE_REG(chip, SYS_DUMMY0, NYET_MSAK, NYET_EN);
+ RTS51X_WRITE_REG(chip, CD_DEGLITCH_WIDTH, 0xFF, 0x08);
+ rts51x_write_register(chip, CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN, 0x00);
+ rts51x_write_register(chip,SD30_DRIVE_SEL,SD30_DRIVE_MASK,chip->option.sd30_pad_drive);
+ rts51x_write_register(chip,CARD_DRIVE_SEL,SD20_DRIVE_MASK,chip->option.sd20_pad_drive);
+
+ if(!chip->option.ww_enable)
+ {
+ if(CHECK_PKG(chip, LQFP48))
+ {
+ rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x80);
+ rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0xA0);
+ }
+ else
+ {
+ rts51x_write_register(chip, CARD_PULL_CTL1, 0x30, 0x20);
+ rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x80);
+ rts51x_write_register(chip, CARD_PULL_CTL6, 0x0c, 0x08);
+ }
+ }
+ }
+
+ if (chip->option.sd_ctl & SUPPORT_UHS50_MMC44)
+ {
+ SET_UHS50(chip);
+ RTS51X_DEBUGP(("option enable UHS50&MMC44,sd_ctl:0x%x \n",chip->option.sd_ctl));
+ }
+ else
+ {
+ if(CHECK_PID(chip, 0x0139)&&CHECK_PKG(chip, LQFP48))
+ {
+ SET_UHS50(chip);
+ RTS51X_DEBUGP(("PID enable UHS50&MMC44\n"));
+ }
+ else
+ {
+ CLEAR_UHS50(chip);
+ RTS51X_DEBUGP(("PID disable UHS50&MMC44\n"));
+ }
+ }
+
+ if(chip->option.ms_errreg_fix && (chip->ic_version>1)){
+ rts51x_write_register(chip, 0xFD4D, 0x01, 0x01);
+ }
+
+ retval = rts51x_write_phy_register(chip, 0xC2, 0x7C);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE);
+#ifdef LED_AUTO_BLINK
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_AUTO_BLINK,
+ BLINK_ENABLE|BLINK_SPEED_MASK,
+ BLINK_ENABLE|chip->option.led_blink_speed);
+#endif
+ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
+ EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
+
+ retval = rts51x_send_cmd(chip, MODE_C, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+#ifdef SUPPORT_OCP
+ if(chip->asic_code)
+ {
+ rts51x_write_register(chip, OCPCTL, MS_OCP_DETECT_EN, MS_OCP_DETECT_EN);
+ RTS51X_DEBUGP(("Enable OCP detect!\n"));
+ }
+#endif
+
+ if(chip->option.FT2_fast_mode)
+ {
+ card_power_on(chip, SD_CARD|MS_CARD|XD_CARD);
+ wait_timeout(10);
+ }
+
+#ifndef USING_POLLING_CYCLE_DELINK
+ rts51x_clear_start_time(chip);
+#endif
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_init_chip(struct rts51x_chip *chip)
+{
+ int retval;
+ u8 val;
+
+ chip->max_lun = 0;
+ chip->cur_clk = 0;
+ chip->cur_card = 0;
+
+ chip->card2lun[XD_CARD] = 0;
+ chip->card2lun[SD_CARD] = 0;
+ chip->card2lun[MS_CARD] = 0;
+ chip->card_ejected = 0;
+
+ chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD;
+
+#ifdef CLOSE_SSC_POWER
+ rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
+ udelay(100);
+ rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
+#endif
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ RTS51X_READ_REG(chip, HW_VERSION, &val);
+ if((val&0x0f)>=2)
+ {
+ chip->option.rcc_bug_fix_en = 0;
+ }
+ RTS51X_DEBUGP(("rcc bug fix enable:%d\n",chip->option.rcc_bug_fix_en));
+ RTS51X_DEBUGP(("HW_VERSION: 0x%x\n", val));
+ if (val & FPGA_VER) {
+ chip->asic_code = 0;
+ RTS51X_DEBUGP(("FPGA!\n"));
+ } else {
+ chip->asic_code = 1;
+ RTS51X_DEBUGP(("ASIC!\n"));
+ }
+ chip->ic_version = val & HW_VER_MASK;
+
+ if (!check_sd_speed_prior(chip->option.sd_speed_prior)) {
+ chip->option.sd_speed_prior = 0x01020403;
+ }
+ RTS51X_DEBUGP(("sd_speed_prior = 0x%08x\n", chip->option.sd_speed_prior));
+
+ RTS51X_READ_REG(chip, CARD_SHARE_MODE, &val);
+ if (val & CARD_SHARE_LQFP_SEL) {
+ chip->package = LQFP48;
+ RTS51X_DEBUGP(("Package: LQFP48\n"));
+ } else {
+ chip->package = QFN24;
+ RTS51X_DEBUGP(("Package: QFN24\n"));
+ }
+
+ RTS51X_READ_REG(chip, HS_USB_STAT, &val);
+ if (val & USB_HI_SPEED) {
+ chip->usb_speed = USB_20;
+ RTS51X_DEBUGP(("USB High Speed\n"));
+ } else {
+ chip->usb_speed = USB_11;
+ RTS51X_DEBUGP(("USB Full Speed\n"));
+ }
+
+ retval = rts51x_reset_chip(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_release_chip(struct rts51x_chip *chip)
+{
+ xd_free_l2p_tbl(chip);
+ ms_free_l2p_tbl(chip);
+ chip->card_ready = 0;
+ return STATUS_SUCCESS;
+}
+
+#ifndef LED_AUTO_BLINK
+static inline void rts51x_blink_led(struct rts51x_chip *chip)
+{
+ if (chip->card_ready) {
+ if (chip->led_toggle_counter < chip->option.led_toggle_interval) {
+ chip->led_toggle_counter ++;
+ } else {
+ chip->led_toggle_counter = 0;
+ toggle_gpio(chip, LED_GPIO);
+ }
+ }
+}
+#endif
+
+void rts51x_polling_func(struct rts51x_chip *chip)
+{
+#ifdef SUPPORT_SD_LOCK
+ struct sd_info *sd_card = &(chip->sd_card);
+
+ if (sd_card->sd_erase_status) {
+ if (chip->card_exist & SD_CARD) {
+ u8 val;
+ rts51x_read_register(chip, SD_BUS_STAT, &val);
+ if (val & SD_DAT0_STATUS) {
+ sd_card->sd_erase_status = SD_NOT_ERASE;
+ sd_card->sd_lock_notify = 1;
+
+ sd_cleanup_work(chip);
+ release_sd_card(chip);
+ chip->card_ready &= ~SD_CARD;
+ chip->card_exist &= ~SD_CARD;
+ chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
+ clear_bit(chip->card2lun[SD_CARD], &(chip->lun_mc));
+ }
+ } else {
+ sd_card->sd_erase_status = SD_NOT_ERASE;
+ }
+ }
+#endif
+
+ rts51x_init_cards(chip);
+
+#ifdef SUPPORT_OCP
+ if((chip->ocp_stat&(MS_OCP_NOW|MS_OCP_EVER))&&(chip->card_exist))
+ {
+
+ rts51x_prepare_run(chip);
+
+ if(chip->card_exist&SD_CARD)
+ {
+ rts51x_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0);
+ }
+ else if(chip->card_exist&MS_CARD)
+ {
+ rts51x_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0);
+ }
+ else if(chip->card_exist&XD_CARD)
+ {
+ rts51x_write_register(chip, CARD_OE, XD_OUTPUT_EN, 0);
+ }
+ }
+#endif
+
+ if (chip->idle_counter < IDLE_MAX_COUNT) {
+ chip->idle_counter ++;
+ } else {
+ if (!RTS51X_CHK_STAT(chip, STAT_IDLE)) {
+ RTS51X_DEBUGP(("Idle state!\n"));
+ RTS51X_SET_STAT(chip, STAT_IDLE);
+
+#ifndef LED_AUTO_BLINK
+ chip->led_toggle_counter = 0;
+#endif
+ turn_off_led(chip, LED_GPIO);
+#ifdef CLOSE_SSC_POWER
+ if(!chip->card_ready)
+ {
+ rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
+ rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_DOWN);
+ RTS51X_DEBUGP(("Close SSC clock power!\n"));
+ }
+#endif
+ }
+ }
+
+ switch (RTS51X_GET_STAT(chip)) {
+ case STAT_RUN:
+#ifndef LED_AUTO_BLINK
+ rts51x_blink_led(chip);
+#endif
+ do_remaining_work(chip);
+ break;
+
+ case STAT_IDLE:
+ break;
+
+ default:
+ break;
+ }
+
+ if (chip->option.auto_delink_en && !chip->card_ready) {
+
+#ifdef USING_POLLING_CYCLE_DELINK
+ if (chip->auto_delink_counter <= chip->option.delink_delay* 2) {
+ if (chip->auto_delink_counter == chip->option.delink_delay) {
+
+ clear_first_install_mark(chip);
+
+ if (chip->card_exist) {
+ if(!chip->card_ejected){
+ RTS51X_DEBUGP(("False card inserted, do force delink\n"));
+ rts51x_write_register(chip, AUTO_DELINK_EN,
+ AUTO_DELINK | FORCE_DELINK,
+ AUTO_DELINK | FORCE_DELINK);
+
+ chip->auto_delink_counter = chip->option.delink_delay * 2 + 1;
+ }
+ } else {
+ RTS51X_DEBUGP(("No card inserted, do delink\n"));
+ rts51x_write_register(chip, AUTO_DELINK_EN,
+ AUTO_DELINK, AUTO_DELINK);
+ }
+ }
+
+ if (chip->auto_delink_counter == chip->option.delink_delay * 2) {
+ RTS51X_DEBUGP(("Try to do force delink\n"));
+ rts51x_write_register(chip, AUTO_DELINK_EN,
+ AUTO_DELINK | FORCE_DELINK,
+ AUTO_DELINK | FORCE_DELINK);
+ }
+
+ chip->auto_delink_counter ++;
+ }
+#else
+ int retvalue;
+ retvalue = rts51x_get_card_status(chip, &chip->card_status);
+ if((retvalue==STATUS_SUCCESS)&&(!(chip->card_status&(SD_CD|MS_CD|XD_CD)))){
+ if (rts51x_count_delink_time(chip)>= chip->option.delink_delay) {
+
+ clear_first_install_mark(chip);
+
+ RTS51X_DEBUGP(("No card inserted, do delink\n"));
+ rts51x_write_register(chip, AUTO_DELINK_EN,
+ AUTO_DELINK, AUTO_DELINK);
+ }
+ }
+ if((retvalue==STATUS_SUCCESS)&&(chip->card_status&(SD_CD|MS_CD|XD_CD))){
+ if(!chip->card_ejected)
+ {
+ if(chip->auto_delink_counter>1)
+ {
+ if (rts51x_count_delink_time(chip) > chip->option.delink_delay*2) {
+ RTS51X_DEBUGP(("Try to do force delink\n"));
+ rts51x_write_register(chip, AUTO_DELINK_EN,
+ AUTO_DELINK | FORCE_DELINK,
+ AUTO_DELINK | FORCE_DELINK);
+ }
+ }
+ }
+ }
+ chip->auto_delink_counter++;
+#endif
+ } else {
+ chip->auto_delink_counter = 0;
+#ifndef USING_POLLING_CYCLE_DELINK
+ rts51x_clear_start_time(chip);
+#endif
+ }
+}
+
+void rts51x_add_cmd(struct rts51x_chip *chip,
+ u8 cmd_type,
+ u16 reg_addr,
+ u8 mask,
+ u8 data)
+{
+ int i;
+
+ if (chip->cmd_idx < ((CMD_BUF_LEN - CMD_OFFSET) / 4)) {
+ i = CMD_OFFSET + chip->cmd_idx * 4;
+
+ chip->cmd_buf[i++] = ((cmd_type & 0x03) << 6) | (u8)((reg_addr >> 8) & 0x3F);
+ chip->cmd_buf[i++] = (u8)reg_addr;
+ chip->cmd_buf[i++] = mask;
+ chip->cmd_buf[i++] = data;
+
+ chip->cmd_idx ++;
+ }
+}
+
+int rts51x_send_cmd(struct rts51x_chip *chip, u8 flag, int timeout)
+{
+ int result;
+
+ chip->cmd_buf[CNT_H] = (u8)(chip->cmd_idx >> 8);
+ chip->cmd_buf[CNT_L] = (u8)(chip->cmd_idx);
+ chip->cmd_buf[STAGE_FLAG] = flag;
+
+ result = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
+ (void *)(chip->cmd_buf),
+ chip->cmd_idx * 4 + CMD_OFFSET,
+ 0, NULL, timeout, MODE_C);
+ if (result != STATUS_SUCCESS) {
+ TRACE_RET(chip, result);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_get_rsp(struct rts51x_chip *chip, int rsp_len, int timeout)
+{
+ int result;
+
+ if (rsp_len <= 0) {
+ TRACE_RET(chip, STATUS_ERROR);
+ }
+
+ if (rsp_len % 4) {
+ rsp_len += (4 - rsp_len % 4);
+ }
+
+ result = rts51x_transfer_data_rcc(chip, RCV_BULK_PIPE(chip),
+ (void *)chip->rsp_buf, rsp_len,
+ 0, NULL, timeout, STAGE_R);
+ if (result != STATUS_SUCCESS) {
+ TRACE_RET(chip, result);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_get_card_status(struct rts51x_chip *chip, u16 *status)
+{
+ int retval;
+ u16 val;
+
+#ifdef GET_CARD_STATUS_USING_EPC
+ retval = rts51x_get_epc_status(chip, &val);
+
+ if(retval != STATUS_SUCCESS)
+ {
+ TRACE_RET(chip, retval);
+ }
+#else
+ retval = rts51x_ctrl_transfer(chip, RCV_CTRL_PIPE(chip), 0x02, 0xC0,
+ 0, 0, &val, 2, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+#endif
+
+ if (status) {
+ *status = cpu_to_le16(val);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_write_register(struct rts51x_chip *chip, u16 addr, u8 mask, u8 data)
+{
+ int retval;
+
+ rts51x_init_cmd(chip);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, addr, mask, data);
+ retval = rts51x_send_cmd(chip, MODE_C, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 *data)
+{
+ int retval;
+
+ if (data) {
+ *data = 0;
+ }
+ rts51x_init_cmd(chip);
+ rts51x_add_cmd(chip, READ_REG_CMD, addr, 0, 0);
+ retval = rts51x_send_cmd(chip, MODE_CR, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ retval = rts51x_get_rsp(chip, 1, 100);
+
+#ifdef RCC_BUG_FIX_SP
+ if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1))
+ {
+ rts51x_ep0_read_register(chip, addr, chip->rsp_buf);
+ retval = STATUS_SUCCESS;
+ rts51x_reset_pipe(chip,0);
+ rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
+ rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
+ }
+#endif
+
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ if (data) {
+ *data = chip->rsp_buf[0];
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_ep0_write_register(struct rts51x_chip *chip, u16 addr, u8 mask, u8 data)
+{
+ int retval;
+ u16 value = 0, index = 0;
+
+ value |= (u16)(3 & 0x03) << 14;
+ value |= (u16)(addr & 0x3FFF);
+ index |= (u16)mask << 8;
+ index |= (u16)data;
+
+ retval = rts51x_ctrl_transfer(chip, SND_CTRL_PIPE(chip), 0x00, 0x40,
+ cpu_to_be16(value), cpu_to_be16(index), NULL, 0, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 *data)
+{
+ int retval;
+ u16 value = 0;
+ u8 val;
+
+ if (data) {
+ *data = 0;
+ }
+
+ value |= (u16)(2 & 0x03) << 14;
+ value |= (u16)(addr & 0x3FFF);
+
+ retval = rts51x_ctrl_transfer(chip, RCV_CTRL_PIPE(chip), 0x00, 0xC0,
+ cpu_to_be16(value), 0, &val, 1, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ if (data) {
+ *data = val;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_seq_write_register(struct rts51x_chip *chip, u16 addr, u16 len, u8 *data)
+{
+ int result;
+ u16 cmd_len = len + 12;
+
+ if (!data) {
+ TRACE_RET(chip, STATUS_ERROR);
+ }
+
+ cmd_len = (cmd_len <= CMD_BUF_LEN) ? cmd_len : CMD_BUF_LEN;
+
+ if (cmd_len % 4) {
+ cmd_len += (4 - cmd_len % 4);
+ }
+
+ chip->cmd_buf[0] = 'R';
+ chip->cmd_buf[1] = 'T';
+ chip->cmd_buf[2] = 'C';
+ chip->cmd_buf[3] = 'R';
+ chip->cmd_buf[PACKET_TYPE] = SEQ_WRITE;
+ chip->cmd_buf[5] = (u8)(len >> 8);
+ chip->cmd_buf[6] = (u8)len;
+ chip->cmd_buf[STAGE_FLAG] = 0;
+ chip->cmd_buf[8] = (u8)(addr >> 8);
+ chip->cmd_buf[9] = (u8)addr;
+
+ memcpy(chip->cmd_buf + 12, data, len);
+
+ result = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
+ (void *)(chip->cmd_buf), cmd_len, 0, NULL, 100, MODE_C);
+ if (result != STATUS_SUCCESS) {
+ TRACE_RET(chip, result);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_seq_read_register(struct rts51x_chip *chip, u16 addr, u16 len, u8 *data)
+{
+ int result;
+ u16 rsp_len;
+
+ if (!data) {
+ TRACE_RET(chip, STATUS_ERROR);
+ }
+
+ if (len % 4) {
+ rsp_len = len + (4 - len % 4);
+ } else {
+ rsp_len = len;
+ }
+
+ chip->cmd_buf[0] = 'R';
+ chip->cmd_buf[1] = 'T';
+ chip->cmd_buf[2] = 'C';
+ chip->cmd_buf[3] = 'R';
+ chip->cmd_buf[PACKET_TYPE] = SEQ_READ;
+ chip->cmd_buf[5] = (u8)(rsp_len >> 8);
+ chip->cmd_buf[6] = (u8)rsp_len;
+ chip->cmd_buf[STAGE_FLAG] = STAGE_R;
+ chip->cmd_buf[8] = (u8)(addr >> 8);
+ chip->cmd_buf[9] = (u8)addr;
+
+ result = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
+ (void *)(chip->cmd_buf), 12, 0, NULL, 100, MODE_C);
+ if (result != STATUS_SUCCESS) {
+ TRACE_RET(chip, result);
+ }
+
+ result = rts51x_transfer_data_rcc(chip, RCV_BULK_PIPE(chip),
+ (void *)data, rsp_len, 0, NULL, 100, STAGE_DI);
+ if (result != STATUS_SUCCESS) {
+ TRACE_RET(chip, result);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_read_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len)
+{
+ int retval;
+
+ if (!buf) {
+ TRACE_RET(chip, STATUS_ERROR);
+ }
+
+ retval = rts51x_seq_read_register(chip, PPBUF_BASE2, (u16)buf_len, buf);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_write_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len)
+{
+ int retval;
+
+ if (!buf) {
+ TRACE_RET(chip, STATUS_ERROR);
+ }
+
+ retval = rts51x_seq_write_register(chip, PPBUF_BASE2, (u16)buf_len, buf);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_write_phy_register(struct rts51x_chip *chip, u8 addr, u8 val)
+{
+ int retval;
+
+ RTS51X_DEBUGP(("Write 0x%x to phy register 0x%x\n", val, addr));
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, (addr >> 4) & 0x0F);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+
+ retval = rts51x_send_cmd(chip, MODE_C, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int rts51x_read_phy_register(struct rts51x_chip *chip, u8 addr, u8 *val)
+{
+ int retval;
+
+ RTS51X_DEBUGP(("Read from phy register 0x%x\n", addr));
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, 0x07);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, (addr >> 4) & 0x0F);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+ rts51x_add_cmd(chip, READ_REG_CMD, HS_VSTAOUT, 0, 0);
+
+ retval = rts51x_send_cmd(chip, MODE_CR, 100);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ retval = rts51x_get_rsp(chip, 1, 100);
+
+#ifdef RCC_BUG_FIX_SP
+ if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1))
+ {
+ chip->rcc_read_response = 0;
+ rts51x_ep0_read_register(chip, HS_VSTAOUT, chip->rsp_buf);
+ retval = STATUS_SUCCESS;
+ rts51x_reset_pipe(chip,0);
+ rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
+ rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
+ }
+#endif
+
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ if (val) {
+ *val = chip->rsp_buf[0];
+ }
+
+ RTS51X_DEBUGP(("Return value: 0x%x\n", chip->rsp_buf[0]));
+
+ return STATUS_SUCCESS;
+}
+
+void rts51x_do_before_power_down(struct rts51x_chip *chip)
+{
+ RTS51X_DEBUGP(("rts51x_do_before_power_down\n"));
+
+ rts51x_prepare_run(chip);
+
+ rts51x_release_cards(chip);
+ turn_off_led(chip, LED_GPIO);
+
+ chip->cur_clk = 0;
+ chip->card_exist = 0;
+ chip->cur_card = 0;
+
+ if(chip->asic_code&&!chip->option.ww_enable)
+ {
+ if(CHECK_PKG(chip, LQFP48))
+ {
+ rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
+ rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0x50);
+ }
+ else
+ {
+ rts51x_write_register(chip, CARD_PULL_CTL1, 0x30, 0x10);
+ rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
+ rts51x_write_register(chip, CARD_PULL_CTL6, 0x0c, 0x04);
+ }
+ }
+
+ if(CHECK_PKG(chip, LQFP48)){
+ rts51x_write_register(chip, CARD_PWR_CTL, LDO3318_PWR_MASK, LDO_OFF);
+ }
+}
+
+void rts51x_clear_hw_error(struct rts51x_chip *chip)
+{
+ rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
+}
+
+void rts51x_prepare_run(struct rts51x_chip *chip)
+{
+#ifdef CLOSE_SSC_POWER
+ if (RTS51X_CHK_STAT(chip, STAT_IDLE) && (!chip->card_ready)) {
+ rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
+ udelay(100);
+ RTS51X_DEBUGP(("Open SSC clock power.\n"));
+
+ rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
+ }
+#endif
+
+
+}
+
+#ifdef _MSG_TRACE
+void rts51x_trace_msg(struct rts51x_chip *chip, unsigned char *buf, int clear)
+{
+ unsigned char *ptr;
+ int i, msg_cnt;
+
+ if (!buf) {
+ return;
+ }
+
+ ptr = buf;
+
+ if (chip->trace_msg[chip->msg_idx].valid) {
+ msg_cnt = TRACE_ITEM_CNT;
+ } else {
+ msg_cnt = chip->msg_idx;
+ }
+ *(ptr++) = (u8)(msg_cnt >> 24);
+ *(ptr++) = (u8)(msg_cnt >> 16);
+ *(ptr++) = (u8)(msg_cnt >> 8);
+ *(ptr++) = (u8)msg_cnt;
+ RTS51X_DEBUGP(("Trace message count is %d\n", msg_cnt));
+
+ for (i = 1; i <= msg_cnt; i++) {
+ int j, idx;
+
+ idx = chip->msg_idx - i;
+ if (idx < 0) {
+ idx += TRACE_ITEM_CNT;
+ }
+
+ *(ptr++) = (u8)(chip->trace_msg[idx].line >> 8);
+ *(ptr++) = (u8)(chip->trace_msg[idx].line);
+ for (j = 0; j < MSG_FUNC_LEN; j++) {
+ *(ptr++) = chip->trace_msg[idx].func[j];
+ }
+ for (j = 0; j < MSG_FILE_LEN; j++) {
+ *(ptr++) = chip->trace_msg[idx].file[j];
+ }
+ for (j = 0; j < TIME_VAL_LEN; j++) {
+ *(ptr++) = chip->trace_msg[idx].timeval_buf[j];
+ }
+ }
+
+ if (clear) {
+ chip->msg_idx = 0;
+ for (i = 0; i < TRACE_ITEM_CNT; i++) {
+ chip->trace_msg[i].valid = 0;
+ }
+ }
+}
+#endif
+
+void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status, u8 status_len)
+{
+ struct sd_info *sd_card = &(chip->sd_card);
+ struct ms_info *ms_card = &(chip->ms_card);
+ u8 card = get_lun_card(chip, lun);
+#ifdef SUPPORT_OC
+ u8 oc_now_mask = 0, oc_ever_mask = 0;
+#endif
+
+ if (!status || (status_len < 32)) {
+ return;
+ }
+
+ status[0] = (u8)RTS51X_GET_PID(chip);
+ status[1] = (u8)(chip->ic_version);
+
+ if (chip->option.auto_delink_en) {
+ status[2] = 0x10;
+ } else {
+ status[2] = 0x00;
+ }
+
+ status[3] = 20;
+ status[4] = 10;
+ status[5] = 05;
+ status[6] = 21;
+
+ if (chip->card_wp) {
+ status[7] = 0x20;
+ } else {
+ status[7] = 0x00;
+ }
+
+#ifdef SUPPORT_OC
+ status[8] = 0;
+ oc_now_mask = MS_OCP_NOW;
+ oc_ever_mask = MS_OCP_EVER;
+
+ if (chip->ocp_stat & oc_now_mask) {
+ status[8] |= 0x02;
+ }
+ if (chip->ocp_stat & oc_ever_mask) {
+ status[8] |= 0x01;
+ }
+#endif
+
+ if (card == SD_CARD) {
+ if (CHK_SD(sd_card)) {
+ if (CHK_SD_HCXC(sd_card)) {
+ if (sd_card->capacity > 0x4000000) {
+ status[0x0E] = 0x02;
+ } else {
+ status[0x0E] = 0x01;
+ }
+ } else {
+ status[0x0E] = 0x00;
+ }
+
+ if (CHK_SD_SDR104(sd_card)) {
+ status[0x0F] = 0x03;
+ } else if (CHK_SD_DDR50(sd_card)) {
+ status[0x0F] = 0x04;
+ } else if (CHK_SD_SDR50(sd_card)) {
+ status[0x0F] = 0x02;
+ } else if (CHK_SD_HS(sd_card)) {
+ status[0x0F] = 0x01;
+ } else {
+ status[0x0F] = 0x00;
+ }
+ } else {
+ if (CHK_MMC_SECTOR_MODE(sd_card)) {
+ status[0x0E] = 0x01;
+ } else {
+ status[0x0E] = 0x00;
+ }
+
+ if (CHK_MMC_DDR52(sd_card)) {
+ status[0x0F] = 0x03;
+ } else if (CHK_MMC_52M(sd_card)) {
+ status[0x0F] = 0x02;
+ } else if (CHK_MMC_26M(sd_card)) {
+ status[0x0F] = 0x01;
+ } else {
+ status[0x0F] = 0x00;
+ }
+ }
+ } else if (card == MS_CARD) {
+ if (CHK_MSPRO(ms_card)) {
+ if (CHK_MSXC(ms_card)) {
+ status[0x0E] = 0x01;
+ } else {
+ status[0x0E] = 0x00;
+ }
+
+ if (CHK_HG8BIT(ms_card)) {
+ status[0x0F] = 0x01;
+ } else {
+ status[0x0F] = 0x00;
+ }
+ }
+ }
+
+#ifdef SUPPORT_SD_LOCK
+ if (card == SD_CARD) {
+ status[0x17] = 0x80;
+ if (sd_card->sd_erase_status) {
+ status[0x17] |= 0x01;
+ }
+ if (sd_card->sd_lock_status & SD_LOCKED) {
+ status[0x17] |= 0x02;
+ status[0x07] |= 0x40;
+ }
+ if (sd_card->sd_lock_status & SD_PWD_EXIST) {
+ status[0x17] |= 0x04;
+ }
+ } else {
+ status[0x17] = 0x00;
+ }
+
+ RTS51X_DEBUGP(("status[0x17] = 0x%x\n", status[0x17]));
+#endif
+
+ status[0x18] = 0x8A;
+
+ status[0x1A] = 0x28;
+
+#ifdef SUPPORT_SD_LOCK
+ status[0x1F] = 0x01;
+#endif
+
+ status[0x1A] = 0x28;
+}
+
+void rts51x_read_status(struct rts51x_chip *chip, unsigned int lun, u8 *rts51x_status, u8 status_len)
+{
+ if (!rts51x_status || (status_len < 16)) {
+ return;
+ }
+
+ rts51x_status[0] = (u8)(RTS51X_GET_VID(chip) >> 8);
+ rts51x_status[1] = (u8)RTS51X_GET_VID(chip);
+
+ rts51x_status[2] = (u8)(RTS51X_GET_PID(chip) >> 8);
+ rts51x_status[3] = (u8)RTS51X_GET_PID(chip);
+
+ rts51x_status[4] = (u8)lun;
+
+ if (chip->card_exist) {
+ if (chip->card_exist & XD_CARD) {
+ rts51x_status[5] = 4;
+ } else if (chip->card_exist & SD_CARD) {
+ rts51x_status[5] = 2;
+ } else if (chip->card_exist & MS_CARD) {
+ rts51x_status[5] = 3;
+ } else {
+ rts51x_status[5] = 7;
+ }
+ } else {
+ rts51x_status[5] = 7;
+ }
+
+ rts51x_status[6] = 1;
+
+ rts51x_status[7] = (u8)RTS51X_GET_PID(chip);;
+ rts51x_status[8] = chip->ic_version;
+
+ if (check_card_exist(chip, lun)) {
+ rts51x_status[9] = 1;
+ } else {
+ rts51x_status[9] = 0;
+ }
+
+ rts51x_status[10] = 1;
+
+ rts51x_status[11] = XD_CARD | SD_CARD | MS_CARD;
+
+ if (check_card_ready(chip, lun)) {
+ rts51x_status[12] = 1;
+ } else {
+ rts51x_status[12] = 0;
+ }
+
+ if (get_lun_card(chip, lun) == XD_CARD) {
+ rts51x_status[13] = 0x40;
+ } else if (get_lun_card(chip, lun) == SD_CARD) {
+ struct sd_info *sd_card = &(chip->sd_card);
+
+ rts51x_status[13] = 0x20;
+ if (CHK_SD(sd_card)) {
+ if (CHK_SD_HCXC(sd_card)) {
+ rts51x_status[13] |= 0x04;
+ }
+ if (CHK_SD_HS(sd_card)) {
+ rts51x_status[13] |= 0x02;
+ }
+ } else {
+ rts51x_status[13] |= 0x08;
+ if (CHK_MMC_52M(sd_card)) {
+ rts51x_status[13] |= 0x02;
+ }
+ if (CHK_MMC_SECTOR_MODE(sd_card)) {
+ rts51x_status[13] |= 0x04;
+ }
+ }
+ } else if (get_lun_card(chip, lun) == MS_CARD) {
+ struct ms_info *ms_card = &(chip->ms_card);
+
+ if (CHK_MSPRO(ms_card)) {
+ rts51x_status[13] = 0x38;
+ if (CHK_HG8BIT(ms_card)) {
+ rts51x_status[13] |= 0x04;
+ }
+#ifdef SUPPORT_MSXC
+ if (CHK_MSXC(ms_card)) {
+ rts51x_status[13] |= 0x01;
+ }
+#endif
+ } else {
+ rts51x_status[13] = 0x30;
+ }
+ } else {
+ rts51x_status[13] = 0x70;
+ }
+
+ rts51x_status[14] = 0x78;
+
+ rts51x_status[15] = 0x82;
+}
+
+
+int rts51x_transfer_data_rcc(struct rts51x_chip *chip, unsigned int pipe,
+ void *buf, unsigned int len, int use_sg,
+ unsigned int *act_len, int timeout, u8 stage_flag)
+{
+ int retval;
+
+ retval=rts51x_transfer_data(chip, pipe, buf, len, use_sg, act_len, timeout);
+
+#ifdef RCC_BUG_FIX_SP
+ if(retval!=STATUS_SUCCESS)
+ {
+ u8 tmpvalue,tmpvalue1;
+ u16 i, readpointer;
+ u32 tcvalue;
+ u16 bcvalue,oldbcvalue;
+ u8 pollingnum;
+
+ if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1))
+ {
+ if(stage_flag&STAGE_DI)
+ {
+ rts51x_ep0_read_register(chip, SFSM_ED, &tmpvalue);
+ if(!(tmpvalue&CARD_ERR))
+ {
+
+ pollingnum = 0;
+ if(CHECK_USB(chip, USB_20))
+ {
+ do
+ {
+ rts51x_ep0_read_register(chip, MC_FIFO_STAT, &tmpvalue1);
+ if(tmpvalue1&FIFO_FULL)
+ {
+ break;
+ }
+ rts51x_ep0_read_register(chip, MC_DMA_CTL, &tmpvalue1);
+ if(tmpvalue1&DMA_TC_EQ_0)
+ {
+ break;
+ }
+ udelay(100);
+ pollingnum++;
+ }while(pollingnum<10);
+ }
+ else
+ {
+ bcvalue =0x5555;
+ do{
+ rts51x_ep0_read_register(chip, MC_DMA_CTL, &tmpvalue1);
+ if(tmpvalue1&DMA_TC_EQ_0)
+ {
+ break;
+ }
+
+ oldbcvalue = bcvalue;
+ rts51x_ep0_read_register(chip, MC_FIFO_BC1, &tmpvalue1);
+ bcvalue = tmpvalue1;
+ bcvalue<<=8;
+ rts51x_ep0_read_register(chip, MC_FIFO_BC0, &tmpvalue1);
+ bcvalue += tmpvalue1;
+ RTS51X_DEBUGP(("FS read install,bcvalue:%d\n",bcvalue));
+
+ if(!(pollingnum%3)&&(bcvalue==oldbcvalue))
+ {
+ break;
+ }
+ udelay(100);
+ pollingnum ++;
+ }while(pollingnum<10);
+ }
+
+ rts51x_ep0_read_register(chip, MC_FIFO_BC1, &tmpvalue1);
+ bcvalue = tmpvalue1;
+ bcvalue<<=8;
+ rts51x_ep0_read_register(chip, MC_FIFO_BC0, &tmpvalue1);
+ bcvalue += tmpvalue1;
+ RTS51X_DEBUGP(("read install,bcvalue:%d\n",bcvalue));
+
+ if(bcvalue)
+ {
+ rts51x_ep0_read_register(chip, MC_FIFO_RD_PTR1, &tmpvalue1);
+ readpointer = tmpvalue1;
+ readpointer<<=8;
+ rts51x_ep0_read_register(chip, MC_FIFO_RD_PTR0, &tmpvalue1);
+ readpointer+=tmpvalue1;
+ RTS51X_DEBUGP(("read install,buff have data, read pointer:%d\n",readpointer));
+
+ rts51x_ep0_read_register(chip, MC_DMA_TC3, &tmpvalue1);
+ tcvalue = tmpvalue1;
+ tcvalue<<=8;
+ rts51x_ep0_read_register(chip, MC_DMA_TC2, &tmpvalue1);
+ tcvalue+=tmpvalue1;
+ tcvalue<<=8;
+ rts51x_ep0_read_register(chip, MC_DMA_TC1, &tmpvalue1);
+ tcvalue+=tmpvalue1;
+ tcvalue<<=8;
+ rts51x_ep0_read_register(chip, MC_DMA_TC0, &tmpvalue1);
+ tcvalue+=tmpvalue1;
+ RTS51X_DEBUGP(("read intall,DMA tc value:%d\n",tcvalue));
+
+ for(i=0; i<bcvalue;i++)
+ {
+ rts51x_ep0_read_register(chip, (RBUF_BASE+(readpointer&RBUF_SIZE_MASK)+i)&RBUF_SIZE_MASK, &tmpvalue1);
+ *((unsigned char*)buf+len-tcvalue-bcvalue+i) =tmpvalue1;
+ }
+/* else
+ {
+ for(i=0; i<bcvalue; i++)
+ {
+ rts51x_ep0_read_register(chip, (RBUF_BASE+(readpointer&RBUF_SIZE_MASK)+i)&RBUF_SIZE_MASK, &tmpvalue1);
+ *((unsigned char*)buf+len-bcvalue+i) =tmpvalue1;
+ }
+ }*/
+
+ rts51x_ep0_write_register(chip, RCCTL, U_HW_CMD_EN_MASK, U_HW_CMD_DIS);
+ rts51x_reset_pipe(chip,0);
+ rts51x_ep0_write_register(chip, SFSM_ED, HW_CMD_STOP, HW_CMD_STOP);
+ if(tcvalue)
+ {
+ retval=rts51x_transfer_data(chip, pipe, ((unsigned char*)buf+len-tcvalue), tcvalue, use_sg, act_len, timeout);
+ }
+ else
+ {
+ rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
+ retval = STATUS_SUCCESS;
+ }
+ rts51x_ep0_write_register(chip, RCCTL, U_HW_CMD_EN_MASK, U_HW_CMD_EN);
+ }
+ chip->rcc_read_response = 1;
+ }
+ }
+ }
+
+ }
+#endif
+
+ return retval;
+
+}
+