2011-07-19 09:10:35 +00:00
|
|
|
/* 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/workqueue.h>
|
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
#include "trace.h"
|
|
|
|
#include "rts51x.h"
|
|
|
|
#include "rts51x_chip.h"
|
|
|
|
#include "rts51x_card.h"
|
|
|
|
#include "rts51x_transport.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;
|
|
|
|
|
|
|
|
/* Check the legality of sd_speed_prior */
|
|
|
|
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->rts5179)
|
|
|
|
rts51x_write_register(chip, CARD_PULL_CTL5, 0x03, 0x01);
|
2012-05-10 07:59:39 +00:00
|
|
|
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);
|
2011-07-19 09:10:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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)) */
|
|
|
|
if ((CHECK_PID(chip, 0x0139) && CHECK_PKG(chip, LQFP48))
|
|
|
|
|| chip->rts5179) {
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* GPIO OE */
|
|
|
|
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE);
|
|
|
|
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) {
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_card_power_on(chip, SD_CARD | MS_CARD | XD_CARD);
|
2011-07-19 09:10:35 +00:00
|
|
|
wait_timeout(10);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
RTS51X_READ_REG(chip, CFG_MODE_1, &val);
|
|
|
|
if (val & RTS5179) {
|
|
|
|
chip->rts5179 = 1;
|
|
|
|
RTS51X_DEBUGP("device is rts5179\n");
|
|
|
|
} else {
|
|
|
|
chip->rts5179 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_xd_free_l2p_tbl(chip);
|
|
|
|
rts51x_ms_free_l2p_tbl(chip);
|
2011-07-19 09:10:35 +00:00
|
|
|
chip->card_ready = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void rts51x_blink_led(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
/* Read/Write */
|
|
|
|
if (chip->card_ready) {
|
|
|
|
if (chip->led_toggle_counter <
|
|
|
|
chip->option.led_toggle_interval) {
|
|
|
|
chip->led_toggle_counter++;
|
|
|
|
} else {
|
|
|
|
chip->led_toggle_counter = 0;
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_toggle_gpio(chip, LED_GPIO);
|
2011-07-19 09:10:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rts51x_auto_delink_cmd(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
rts51x_write_register(chip, AUTO_DELINK_EN,
|
|
|
|
AUTO_DELINK, AUTO_DELINK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rts51x_auto_delink_force_cmd(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
rts51x_write_register(chip, AUTO_DELINK_EN,
|
|
|
|
AUTO_DELINK | FORCE_DELINK,
|
|
|
|
AUTO_DELINK | FORCE_DELINK);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USING_POLLING_CYCLE_DELINK
|
|
|
|
/* using polling cycle as delink time */
|
|
|
|
static void rts51x_auto_delink_polling_cycle(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
if (chip->auto_delink_counter <=
|
|
|
|
chip->option.delink_delay * 2) {
|
|
|
|
if (chip->auto_delink_counter ==
|
|
|
|
chip->option.delink_delay) {
|
|
|
|
if (chip->card_exist) {
|
|
|
|
/* False card */
|
|
|
|
if (!chip->card_ejected) {
|
|
|
|
/* if card is not ejected or safely
|
|
|
|
* remove,then do force delink */
|
|
|
|
RTS51X_DEBUGP("False card inserted,"
|
|
|
|
"do force delink\n");
|
|
|
|
rts51x_auto_delink_force_cmd(chip);
|
|
|
|
chip->auto_delink_counter =
|
|
|
|
chip->option.delink_delay * 2 + 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RTS51X_DEBUGP("No card inserted, do delink\n");
|
|
|
|
/* rts51x_write_register(chip, CARD_PWR_CTL,
|
|
|
|
DV3318_AUTO_PWR_OFF, 0); */
|
|
|
|
rts51x_auto_delink_cmd(chip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (chip->auto_delink_counter ==
|
|
|
|
chip->option.delink_delay * 2) {
|
|
|
|
RTS51X_DEBUGP("Try to do force delink\n");
|
|
|
|
rts51x_auto_delink_force_cmd(chip);
|
|
|
|
}
|
|
|
|
chip->auto_delink_counter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rts51x_auto_delink(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
rts51x_auto_delink_polling_cycle(chip);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/* some of called funcs are not implemented, so comment it out */
|
|
|
|
static void rts51x_auto_delink(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void rts51x_polling_func(struct rts51x_chip *chip)
|
|
|
|
{
|
|
|
|
|
|
|
|
rts51x_init_cards(chip);
|
|
|
|
|
|
|
|
#ifdef SUPPORT_OCP
|
|
|
|
/* if OCP happen and card exist, then close card OE */
|
|
|
|
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);
|
|
|
|
chip->led_toggle_counter = 0;
|
|
|
|
/* Idle state, turn off LED
|
|
|
|
* to reduce power consumption */
|
|
|
|
if (chip->option.led_always_on
|
|
|
|
&& (chip->card_exist &
|
|
|
|
(SD_CARD | MS_CARD | XD_CARD))
|
|
|
|
&& (!chip->card_ejected)) {
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_turn_on_led(chip, LED_GPIO);
|
2011-07-19 09:10:35 +00:00
|
|
|
} else {
|
|
|
|
if (chip->rts5179) {
|
|
|
|
rts51x_ep0_write_register(chip,
|
|
|
|
CARD_GPIO,
|
|
|
|
0x03, 0x00);
|
|
|
|
} else {
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_turn_off_led(chip, LED_GPIO);
|
2011-07-19 09:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#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:
|
|
|
|
rts51x_blink_led(chip);
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_do_remaining_work(chip);
|
2011-07-19 09:10:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case STAT_IDLE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-06-21 03:17:03 +00:00
|
|
|
if (chip->option.auto_delink_en && !chip->card_ready)
|
2011-07-19 09:10:35 +00:00
|
|
|
rts51x_auto_delink(chip);
|
2012-06-21 03:17:03 +00:00
|
|
|
else
|
2011-07-19 09:10:35 +00:00
|
|
|
chip->auto_delink_counter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
/* rsp_len must aligned to dword */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
int rts51x_get_card_status(struct rts51x_chip *chip, u16 *status)
|
2011-07-19 09:10:35 +00:00
|
|
|
{
|
|
|
|
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 = 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;
|
|
|
|
}
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 *data)
|
2011-07-19 09:10:35 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 *data)
|
2011-07-19 09:10:35 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* cmd_len must aligned to dword */
|
|
|
|
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);
|
|
|
|
/* rsp_len must aligned to dword */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
int rts51x_read_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len)
|
2011-07-19 09:10:35 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
int rts51x_write_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len)
|
2011-07-19 09:10:35 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
int rts51x_read_phy_register(struct rts51x_chip *chip, u8 addr, u8 *val)
|
2011-07-19 09:10:35 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (chip->rts5179)
|
|
|
|
rts51x_ep0_write_register(chip, CARD_GPIO, 0x03, 0x00);
|
|
|
|
else
|
2012-10-19 09:43:34 +00:00
|
|
|
rts51x_turn_off_led(chip, LED_GPIO);
|
2011-07-19 09:10:35 +00:00
|
|
|
|
|
|
|
chip->cur_clk = 0;
|
|
|
|
chip->card_exist = 0;
|
|
|
|
chip->cur_card = 0;
|
2012-05-10 07:59:39 +00:00
|
|
|
if (chip->asic_code) {
|
2011-07-19 09:10:35 +00:00
|
|
|
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
|
|
|
|
|
2012-01-22 21:47:15 +00:00
|
|
|
void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
|
2011-07-19 09:10:35 +00:00
|
|
|
u8 status_len)
|
|
|
|
{
|
|
|
|
struct sd_info *sd_card = &(chip->sd_card);
|
|
|
|
struct ms_info *ms_card = &(chip->ms_card);
|
2012-10-19 09:43:34 +00:00
|
|
|
u8 card = rts51x_get_lun_card(chip, lun);
|
2011-07-19 09:10:35 +00:00
|
|
|
#ifdef SUPPORT_OC
|
|
|
|
u8 oc_now_mask = 0, oc_ever_mask = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!status || (status_len < 32))
|
|
|
|
return;
|
|
|
|
/* IC Version */
|
|
|
|
status[0] = (u8) RTS51X_GET_PID(chip);
|
|
|
|
status[1] = (u8) (chip->ic_version);
|
|
|
|
|
|
|
|
/* Auto delink mode */
|
|
|
|
if (chip->option.auto_delink_en)
|
|
|
|
status[2] = 0x10;
|
|
|
|
else
|
|
|
|
status[2] = 0x00;
|
|
|
|
|
|
|
|
/* Spec version */
|
|
|
|
status[3] = 20;
|
|
|
|
status[4] = 10;
|
|
|
|
status[5] = 05;
|
|
|
|
status[6] = 21;
|
|
|
|
|
|
|
|
/* Card WP */
|
|
|
|
if (chip->card_wp)
|
|
|
|
status[7] = 0x20;
|
|
|
|
else
|
|
|
|
status[7] = 0x00;
|
|
|
|
|
|
|
|
#ifdef SUPPORT_OC
|
|
|
|
/* Over current status */
|
|
|
|
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)
|
|
|
|
/* SDXC */
|
|
|
|
status[0x0E] = 0x02;
|
|
|
|
else /* SDHC */
|
|
|
|
status[0x0E] = 0x01;
|
|
|
|
} else { /* SDSC */
|
|
|
|
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; /* Normal speed */
|
|
|
|
} else {
|
|
|
|
if (CHK_MMC_SECTOR_MODE(sd_card))
|
|
|
|
status[0x0E] = 0x01; /* High capacity */
|
|
|
|
else
|
|
|
|
status[0x0E] = 0x00; /* Normal capacity */
|
|
|
|
|
|
|
|
if (CHK_MMC_DDR52(sd_card))
|
|
|
|
status[0x0F] = 0x03; /* DDR 52M */
|
|
|
|
else if (CHK_MMC_52M(sd_card))
|
|
|
|
status[0x0F] = 0x02; /* SDR 52M */
|
|
|
|
else if (CHK_MMC_26M(sd_card))
|
|
|
|
status[0x0F] = 0x01; /* SDR 26M */
|
|
|
|
else
|
|
|
|
status[0x0F] = 0x00; /* Normal speed */
|
|
|
|
}
|
|
|
|
} else if (card == MS_CARD) {
|
|
|
|
if (CHK_MSPRO(ms_card)) {
|
|
|
|
if (CHK_MSXC(ms_card))
|
|
|
|
status[0x0E] = 0x01; /* XC */
|
|
|
|
else
|
|
|
|
status[0x0E] = 0x00;
|
|
|
|
|
|
|
|
if (CHK_HG8BIT(ms_card))
|
|
|
|
status[0x0F] = 0x01;
|
|
|
|
else
|
|
|
|
status[0x0F] = 0x00;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function 0
|
|
|
|
* Support Magic Gate, CPRM and PhyRegister R/W */
|
|
|
|
status[0x18] = 0x8A;
|
|
|
|
|
|
|
|
/* Function 2
|
|
|
|
* Support OC LUN status & WP LUN status */
|
|
|
|
status[0x1A] = 0x28;
|
|
|
|
|
|
|
|
/* Function 2
|
|
|
|
* Support OC LUN status & WP LUN status */
|
|
|
|
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;
|
|
|
|
/* VID */
|
|
|
|
rts51x_status[0] = (u8) (RTS51X_GET_VID(chip) >> 8);
|
|
|
|
rts51x_status[1] = (u8) RTS51X_GET_VID(chip);
|
|
|
|
|
|
|
|
/* PID */
|
|
|
|
rts51x_status[2] = (u8) (RTS51X_GET_PID(chip) >> 8);
|
|
|
|
rts51x_status[3] = (u8) RTS51X_GET_PID(chip);
|
|
|
|
|
|
|
|
/* gbLUN */
|
|
|
|
rts51x_status[4] = (u8) lun;
|
|
|
|
|
|
|
|
/* Lun Card Number */
|
|
|
|
if (chip->card_exist) {
|
|
|
|
if (chip->card_exist & XD_CARD)
|
|
|
|
rts51x_status[5] = 4; /* xD Card */
|
|
|
|
else if (chip->card_exist & SD_CARD)
|
|
|
|
rts51x_status[5] = 2; /* SD Card */
|
|
|
|
else if (chip->card_exist & MS_CARD)
|
|
|
|
rts51x_status[5] = 3; /* MS Card */
|
|
|
|
else
|
|
|
|
rts51x_status[5] = 7; /* Multi */
|
|
|
|
} else {
|
|
|
|
rts51x_status[5] = 7; /* Multi */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Total LUNs */
|
|
|
|
rts51x_status[6] = 1;
|
|
|
|
|
|
|
|
/* IC Version */
|
|
|
|
rts51x_status[7] = (u8) RTS51X_GET_PID(chip);
|
|
|
|
rts51x_status[8] = chip->ic_version;
|
|
|
|
|
|
|
|
/* Physical Exist */
|
|
|
|
if (check_card_exist(chip, lun))
|
|
|
|
rts51x_status[9] = 1;
|
|
|
|
else
|
|
|
|
rts51x_status[9] = 0;
|
|
|
|
|
|
|
|
/* Multi Flag */
|
|
|
|
rts51x_status[10] = 1;
|
|
|
|
|
|
|
|
/* LUN Valid Map */
|
|
|
|
rts51x_status[11] = XD_CARD | SD_CARD | MS_CARD;
|
|
|
|
|
|
|
|
/* Logical Exist */
|
|
|
|
if (check_card_ready(chip, lun))
|
|
|
|
rts51x_status[12] = 1;
|
|
|
|
else
|
|
|
|
rts51x_status[12] = 0;
|
|
|
|
|
|
|
|
/* Detailed Type */
|
2012-10-19 09:43:34 +00:00
|
|
|
if (rts51x_get_lun_card(chip, lun) == XD_CARD) {
|
2011-07-19 09:10:35 +00:00
|
|
|
rts51x_status[13] = 0x40;
|
2012-10-19 09:43:34 +00:00
|
|
|
} else if (rts51x_get_lun_card(chip, lun) == SD_CARD) {
|
2011-07-19 09:10:35 +00:00
|
|
|
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; /* Hi capacity SD */
|
|
|
|
if (CHK_SD_HS(sd_card))
|
|
|
|
rts51x_status[13] |= 0x02; /* Hi speed SD */
|
|
|
|
} else {
|
|
|
|
rts51x_status[13] |= 0x08; /* MMC card */
|
|
|
|
if (CHK_MMC_52M(sd_card))
|
|
|
|
rts51x_status[13] |= 0x02; /* Hi speed */
|
|
|
|
if (CHK_MMC_SECTOR_MODE(sd_card))
|
|
|
|
rts51x_status[13] |= 0x04; /* Hi capacity */
|
|
|
|
}
|
2012-10-19 09:43:34 +00:00
|
|
|
} else if (rts51x_get_lun_card(chip, lun) == MS_CARD) {
|
2011-07-19 09:10:35 +00:00
|
|
|
struct ms_info *ms_card = &(chip->ms_card);
|
|
|
|
|
|
|
|
if (CHK_MSPRO(ms_card)) {
|
|
|
|
rts51x_status[13] = 0x38; /* MS Pro */
|
|
|
|
if (CHK_HG8BIT(ms_card))
|
|
|
|
rts51x_status[13] |= 0x04; /* HG */
|
|
|
|
#ifdef SUPPORT_MSXC
|
|
|
|
if (CHK_MSXC(ms_card))
|
|
|
|
rts51x_status[13] |= 0x01; /* MSXC */
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
rts51x_status[13] = 0x30;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rts51x_status[13] = 0x70;
|
|
|
|
}
|
|
|
|
/* Support OC, auto delink, vendor r/w, get bus width */
|
|
|
|
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);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
}
|