diff options
| author | Roman Yeryomin <roman@advem.lv> | 2013-05-17 20:40:24 +0300 |
|---|---|---|
| committer | Roman Yeryomin <roman@advem.lv> | 2013-05-26 00:48:34 +0300 |
| commit | 7e810011201bf926cba09ec07424893e4cd8ce67 (patch) | |
| tree | 202fc7a42607e366848ca59c7a61a8f9fa2712ca /target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_card.c | |
| parent | a45894b5a0f65585440d98bf71ef3e919c84cb5f (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_card.c')
| -rw-r--r-- | target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_card.c | 963 |
1 files changed, 963 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_card.c b/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_card.c new file mode 100644 index 000000000..d859b03c2 --- /dev/null +++ b/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_card.c @@ -0,0 +1,963 @@ +/* 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 <scsi/scsi.h> +#include <scsi/scsi_eh.h> +#include <scsi/scsi_device.h> + +#include "debug.h" +#include "rts51x.h" +#include "rts51x_chip.h" +#include "rts51x_card.h" +#include "rts51x_transport.h" +#include "rts51x_sys.h" +#include "xd.h" +#include "sd.h" +#include "ms.h" + +void do_remaining_work(struct rts51x_chip *chip) +{ + struct sd_info *sd_card = &(chip->sd_card); + struct xd_info *xd_card = &(chip->xd_card); + struct ms_info *ms_card = &(chip->ms_card); + + if (chip->card_ready & SD_CARD) { + if (sd_card->seq_mode) { + RTS51X_SET_STAT(chip, STAT_RUN); + sd_card->counter ++; + } else { + sd_card->counter = 0; + } + } + + if (chip->card_ready & XD_CARD) { + if (xd_card->delay_write.delay_write_flag) { + RTS51X_SET_STAT(chip, STAT_RUN); + xd_card->counter ++; + } else { + xd_card->counter = 0; + } + } + + if (chip->card_ready & MS_CARD) { + if (CHK_MSPRO(ms_card)) { + if (ms_card->seq_mode) { + RTS51X_SET_STAT(chip, STAT_RUN); + ms_card->counter ++; + } else { + ms_card->counter = 0; + } + } else { + if (ms_card->delay_write.delay_write_flag) { + RTS51X_SET_STAT(chip, STAT_RUN); + ms_card->counter ++; + } else { + ms_card->counter = 0; + } + } + } + + if (sd_card->counter > POLLING_WAIT_CNT) { + sd_cleanup_work(chip); + } + + if (xd_card->counter > POLLING_WAIT_CNT) { + xd_cleanup_work(chip); + } + + if (ms_card->counter > POLLING_WAIT_CNT) { + ms_cleanup_work(chip); + } +} + +void do_reset_xd_card(struct rts51x_chip *chip) +{ + int retval; + + if (chip->card2lun[XD_CARD] >= MAX_ALLOWED_LUN_CNT) { + return; + } + + retval = reset_xd_card(chip); + if (retval == STATUS_SUCCESS) { + chip->card_ready |= XD_CARD; + chip->card_fail &= ~XD_CARD; + chip->rw_card[chip->card2lun[XD_CARD]] = xd_rw; + } else { + chip->card_ready &= ~XD_CARD; + chip->card_fail |= XD_CARD; + chip->capacity[chip->card2lun[XD_CARD]] = 0; + chip->rw_card[chip->card2lun[XD_CARD]] = NULL; + + rts51x_init_cmd(chip); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_OFF); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, XD_CLK_EN, 0); + rts51x_send_cmd(chip, MODE_C, 100); + } +} + +void do_reset_sd_card(struct rts51x_chip *chip) +{ + int retval; + + if (chip->card2lun[SD_CARD] >= MAX_ALLOWED_LUN_CNT) { + return; + } + + retval = reset_sd_card(chip); + if (retval == STATUS_SUCCESS) { + chip->card_ready |= SD_CARD; + chip->card_fail &= ~SD_CARD; + chip->rw_card[chip->card2lun[SD_CARD]] = sd_rw; + } else { + chip->card_ready &= ~SD_CARD; + chip->card_fail |= SD_CARD; + chip->capacity[chip->card2lun[SD_CARD]] = 0; + chip->rw_card[chip->card2lun[SD_CARD]] = NULL; + + rts51x_init_cmd(chip); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_OFF); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); + rts51x_send_cmd(chip, MODE_C, 100); + } +} + +void do_reset_ms_card(struct rts51x_chip *chip) +{ + int retval; + + if (chip->card2lun[MS_CARD] >= MAX_ALLOWED_LUN_CNT) { + return; + } + + retval = reset_ms_card(chip); + if (retval == STATUS_SUCCESS) { + chip->card_ready |= MS_CARD; + chip->card_fail &= ~MS_CARD; + chip->rw_card[chip->card2lun[MS_CARD]] = ms_rw; + } else { + chip->card_ready &= ~MS_CARD; + chip->card_fail |= MS_CARD; + chip->capacity[chip->card2lun[MS_CARD]] = 0; + chip->rw_card[chip->card2lun[MS_CARD]] = NULL; + + rts51x_init_cmd(chip); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_OFF); + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); + rts51x_send_cmd(chip, MODE_C, 100); + } +} + +void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset, u8 *need_release) +{ + int retval; + u8 release_map = 0, reset_map = 0; + u8 value; + + retval = rts51x_get_card_status(chip, &(chip->card_status)); +#ifdef SUPPORT_OCP + chip->ocp_stat = (chip->card_status>>4)&0x03; +#endif + + if (retval != STATUS_SUCCESS) { + goto Exit_Debounce; + } + + if (chip->card_exist) { +#ifndef USING_POLLING_CYCLE_DELINK + rts51x_clear_start_time(chip); +#endif + + retval=rts51x_read_register(chip, CARD_INT_PEND, &value); + if(retval!=STATUS_SUCCESS){ + rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH); + rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8); + value = 0; + } + + if (chip->card_exist & XD_CARD) { + if (!(chip->card_status & XD_CD)) { + release_map |= XD_CARD; + } + } else if (chip->card_exist & SD_CARD) { + if (!(chip->card_status & SD_CD)||(value&SD_INT)) { + release_map |= SD_CARD; + } + } else if (chip->card_exist & MS_CARD) { + if (!(chip->card_status & MS_CD)||(value&MS_INT)) { + release_map |= MS_CARD; + } + } + } else { + if (chip->card_status & XD_CD) { +#ifndef USING_POLLING_CYCLE_DELINK + rts51x_clear_start_time(chip); +#endif + reset_map |= XD_CARD; + } else if (chip->card_status & SD_CD) { +#ifndef USING_POLLING_CYCLE_DELINK + rts51x_clear_start_time(chip); +#endif + reset_map |= SD_CARD; + } else if (chip->card_status & MS_CD) { +#ifndef USING_POLLING_CYCLE_DELINK + rts51x_clear_start_time(chip); +#endif + reset_map |= MS_CARD; + } + else { +#ifndef USING_POLLING_CYCLE_DELINK + if(rts51x_check_start_time(chip)) { + rts51x_set_start_time(chip); + } +#endif + } + } + + if (CHECK_PKG(chip, QFN24) && reset_map) { + if (chip->card_exist & XD_CARD) { + reset_map = 0; + goto Exit_Debounce; + } + } + + if (reset_map) { + int xd_cnt = 0, sd_cnt = 0, ms_cnt = 0; + int i; + + for (i = 0; i < (chip->option.debounce_num); i++) { + retval = rts51x_get_card_status(chip, &(chip->card_status)); + if (retval != STATUS_SUCCESS) { + reset_map = release_map = 0; + goto Exit_Debounce; + } + if (chip->card_status & XD_CD) { + xd_cnt ++; + } else { + xd_cnt = 0; + } + if (chip->card_status & SD_CD) { + sd_cnt ++; + } else { + sd_cnt = 0; + } + if (chip->card_status & MS_CD) { + ms_cnt ++; + } else { + ms_cnt = 0; + } + wait_timeout(30); + } + + reset_map = 0; + if (!(chip->card_exist & XD_CARD) && (xd_cnt > (chip->option.debounce_num-1))) { + reset_map |= XD_CARD; + } + if (!(chip->card_exist & SD_CARD) && (sd_cnt > (chip->option.debounce_num-1))) { + reset_map |= SD_CARD; + } + if (!(chip->card_exist & MS_CARD) && (ms_cnt > (chip->option.debounce_num-1))) { + reset_map |= MS_CARD; + } + } + + rts51x_write_register(chip, CARD_INT_PEND, XD_INT|MS_INT|SD_INT, XD_INT|MS_INT|SD_INT); + +Exit_Debounce: + if (need_reset) { + *need_reset = reset_map; + } + if (need_release) { + *need_release = release_map; + } +} + +void rts51x_init_cards(struct rts51x_chip *chip) +{ + u8 need_reset = 0, need_release = 0; + + card_cd_debounce(chip, &need_reset, &need_release); + + if (need_release) { + RTS51X_DEBUGP(("need_release = 0x%x\n", need_release)); + + rts51x_prepare_run(chip); + RTS51X_SET_STAT(chip, STAT_RUN); + +#ifdef SUPPORT_OCP + if(chip->ocp_stat&(MS_OCP_NOW|MS_OCP_EVER)) + { + rts51x_write_register(chip, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR); + chip->ocp_stat = 0; + RTS51X_DEBUGP(("Clear OCP status.\n")); + } +#endif + + if (need_release & XD_CARD) { + chip->card_exist &= ~XD_CARD; + chip->card_ejected = 0; + if (chip->card_ready & XD_CARD) { + release_xd_card(chip); + chip->rw_card[chip->card2lun[XD_CARD]] = NULL; + clear_bit(chip->card2lun[XD_CARD], &(chip->lun_mc)); + } + } + + if (need_release & SD_CARD) { + chip->card_exist &= ~SD_CARD; + chip->card_ejected = 0; + if (chip->card_ready & SD_CARD) { + release_sd_card(chip); + chip->rw_card[chip->card2lun[SD_CARD]] = NULL; + clear_bit(chip->card2lun[SD_CARD], &(chip->lun_mc)); + } + } + + if (need_release & MS_CARD) { + chip->card_exist &= ~MS_CARD; + chip->card_ejected = 0; + if (chip->card_ready & MS_CARD) { + release_ms_card(chip); + chip->rw_card[chip->card2lun[MS_CARD]] = NULL; + clear_bit(chip->card2lun[MS_CARD], &(chip->lun_mc)); + } + } + } + + if (need_reset && !chip->card_ready) { + RTS51X_DEBUGP(("need_reset = 0x%x\n", need_reset)); + + rts51x_prepare_run(chip); + RTS51X_SET_STAT(chip, STAT_RUN); + + if (need_reset & XD_CARD) { + chip->card_exist |= XD_CARD; + do_reset_xd_card(chip); + } else if (need_reset & SD_CARD) { + chip->card_exist |= SD_CARD; + do_reset_sd_card(chip); + } else if (need_reset & MS_CARD) { + chip->card_exist |= MS_CARD; + do_reset_ms_card(chip); + } + } +} + +void rts51x_release_cards(struct rts51x_chip *chip) +{ + if (chip->card_ready & SD_CARD) { + sd_cleanup_work(chip); + release_sd_card(chip); + chip->card_ready &= ~SD_CARD; + } + + if (chip->card_ready & XD_CARD) { + xd_cleanup_work(chip); + release_xd_card(chip); + chip->card_ready &= ~XD_CARD; + } + + if (chip->card_ready & MS_CARD) { + ms_cleanup_work(chip); + release_ms_card(chip); + chip->card_ready &= ~MS_CARD; + } +} + +static inline u8 double_depth(u8 depth) +{ + return ((depth > 1) ? (depth - 1) : depth); +} + +int switch_ssc_clock(struct rts51x_chip *chip, int clk) +{ + struct sd_info *sd_card = &(chip->sd_card); + struct ms_info *ms_card = &(chip->ms_card); + int retval; + u8 N = (u8)(clk - 2), min_N, max_N; + u8 mcu_cnt, div, max_div, ssc_depth; + int sd_vpclk_phase_reset = 0; + + if (chip->cur_clk == clk) { + return STATUS_SUCCESS; + } + + min_N = 60; + max_N = 120; + max_div = CLK_DIV_4; + + RTS51X_DEBUGP(("Switch SSC clock to %dMHz\n", clk)); + + if ((clk <= 2) || (N > max_N)) { + TRACE_RET(chip, STATUS_FAIL); + } + + mcu_cnt = (u8)(60/clk + 3); + if (mcu_cnt > 15) { + mcu_cnt = 15; + } + + div = CLK_DIV_1; + while ((N < min_N) && (div < max_div)) { + N = (N + 2) * 2 - 2; + div ++; + } + RTS51X_DEBUGP(("N = %d, div = %d\n", N, div)); + + if (chip->option.ssc_en) { + if (chip->cur_card == SD_CARD) { + if (CHK_SD_SDR104(sd_card)) { + ssc_depth = chip->option.ssc_depth_sd_sdr104; + } else if (CHK_SD_SDR50(sd_card)) { + ssc_depth = chip->option.ssc_depth_sd_sdr50; + } else if (CHK_SD_DDR50(sd_card)) { + ssc_depth = double_depth(chip->option.ssc_depth_sd_ddr50); + } else if (CHK_SD_HS(sd_card)) { + ssc_depth = double_depth(chip->option.ssc_depth_sd_hs); + } else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) { + ssc_depth = double_depth(chip->option.ssc_depth_mmc_52m); + } else { + ssc_depth = double_depth(chip->option.ssc_depth_low_speed); + } + } else if (chip->cur_card == MS_CARD) { + if (CHK_MSPRO(ms_card)) { + if (CHK_HG8BIT(ms_card)) { + ssc_depth = double_depth(chip->option.ssc_depth_ms_hg); + } else { + ssc_depth = double_depth(chip->option.ssc_depth_ms_4bit); + } + } else { + if (CHK_MS4BIT(ms_card)) { + ssc_depth = double_depth(chip->option.ssc_depth_ms_4bit); + } else { + ssc_depth = double_depth(chip->option.ssc_depth_low_speed); + } + } + } else { + ssc_depth = double_depth(chip->option.ssc_depth_low_speed); + } + + if (ssc_depth) { + if (div == CLK_DIV_2) { + if (ssc_depth > 1) { + ssc_depth -= 1; + } else { + ssc_depth = SSC_DEPTH_2M; + } + } else if (div == CLK_DIV_4) { + if (ssc_depth > 2 ) { + ssc_depth -= 2; + } else { + ssc_depth = SSC_DEPTH_2M; + } + } + } + } else { + ssc_depth = 0; + } + + RTS51X_DEBUGP(("ssc_depth = %d\n", ssc_depth)); + + rts51x_init_cmd(chip); + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE); + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0x3F, (div << 4) | mcu_cnt); + rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CTL2, SSC_DEPTH_MASK, ssc_depth); + rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N); + if (sd_vpclk_phase_reset) { + rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); + } + + retval = rts51x_send_cmd(chip, MODE_C, 2000); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, retval); + } + + if(chip->option.ssc_en&&ssc_depth) + { + rts51x_write_register(chip, SSC_CTL1, 0xff, 0xD0); + } + else + { + rts51x_write_register(chip, SSC_CTL1, 0xff, 0x50); + } + udelay(100); + RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, 0); + + chip->cur_clk = clk; + + return STATUS_SUCCESS; +} + +int switch_normal_clock(struct rts51x_chip *chip, int clk) +{ + int retval; + u8 sel, div, mcu_cnt; + int sd_vpclk_phase_reset = 0; + + if (chip->cur_clk == clk) { + return STATUS_SUCCESS; + } + + if (chip->cur_card == SD_CARD) { + struct sd_info *sd_card = &(chip->sd_card); + if (CHK_SD30_SPEED(sd_card) || CHK_MMC_DDR52(sd_card)) { + sd_vpclk_phase_reset = 1; + } + } + + switch (clk) { + case CLK_20: + RTS51X_DEBUGP(("Switch clock to 20MHz\n")); + sel = SSC_80; + div = CLK_DIV_4; + mcu_cnt = 5; + break; + + case CLK_30: + RTS51X_DEBUGP(("Switch clock to 30MHz\n")); + sel = SSC_60; + div = CLK_DIV_2; + mcu_cnt = 4; + break; + + case CLK_40: + RTS51X_DEBUGP(("Switch clock to 40MHz\n")); + sel = SSC_80; + div = CLK_DIV_2; + mcu_cnt = 3; + break; + + case CLK_50: + RTS51X_DEBUGP(("Switch clock to 50MHz\n")); + sel = SSC_100; + div = CLK_DIV_2; + mcu_cnt = 3; + break; + + case CLK_60: + RTS51X_DEBUGP(("Switch clock to 60MHz\n")); + sel = SSC_60; + div = CLK_DIV_1; + mcu_cnt = 3; + break; + + case CLK_80: + RTS51X_DEBUGP(("Switch clock to 80MHz\n")); + sel = SSC_80; + div = CLK_DIV_1; + mcu_cnt = 2; + break; + + case CLK_100: + RTS51X_DEBUGP(("Switch clock to 100MHz\n")); + sel = SSC_100; + div = CLK_DIV_1; + mcu_cnt = 2; + break; +/* + case CLK_120: + RTS51X_DEBUGP(("Switch clock to 120MHz\n")); + sel = SSC_120; + div = CLK_DIV_1; + mcu_cnt = 2; + break; + + case CLK_150: + RTS51X_DEBUGP(("Switch clock to 150MHz\n")); + sel = SSC_150; + div = CLK_DIV_1; + mcu_cnt = 2; + break;*/ + + default: + RTS51X_DEBUGP(("Try to switch to an illegal clock (%d)\n", clk)); + TRACE_RET(chip, STATUS_FAIL); + } + + if (!sd_vpclk_phase_reset) { + rts51x_init_cmd(chip); + + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE); + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0x3F, (div << 4) | mcu_cnt); + rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CLK_FPGA_SEL, 0xFF, sel); + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0); + + retval = rts51x_send_cmd(chip, MODE_C, 100); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, retval); + } + } else { + rts51x_init_cmd(chip); + + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE); + rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK1_CTL, PHASE_NOT_RESET, 0); + rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0x3F, (div << 4) | mcu_cnt); + rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CLK_FPGA_SEL, 0xFF, sel); + + retval = rts51x_send_cmd(chip, MODE_C, 100); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, retval); + } + + udelay(200); + + rts51x_init_cmd(chip); + + rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); + rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK1_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); + + retval = rts51x_send_cmd(chip, MODE_C, 100); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, retval); + } + + udelay(200); + + RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, 0); + } + + chip->cur_clk = clk; + + return STATUS_SUCCESS; +} + +int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr, u16 sec_cnt) +{ + int retval; + unsigned int lun = SCSI_LUN(srb); + int i; + + if (chip->rw_card[lun] == NULL) { + return STATUS_FAIL; + } + + RTS51X_DEBUGP(("%s card, sector addr: 0x%x, sector cnt: %d\n", + (srb->sc_data_direction == DMA_TO_DEVICE) ? "Write" : "Read", + sec_addr, sec_cnt)); + + chip->rw_need_retry = 0; + for (i = 0; i < 3; i++) { + retval = chip->rw_card[lun](srb, chip, sec_addr, sec_cnt); + if (retval != STATUS_SUCCESS) { + CATCH_TRIGGER(chip); + if(chip->option.reset_or_rw_fail_set_pad_drive) + { + rts51x_write_register(chip, CARD_DRIVE_SEL, SD20_DRIVE_MASK, DRIVE_8mA); + } + } + + if (!chip->rw_need_retry) { + break; + } + + RTS51X_DEBUGP(("Retry RW, (i = %d\n)", i)); + } + + return retval; +} + +u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun) +{ + if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) { + return (u8)XD_CARD; + } else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) { + return (u8)SD_CARD; + } else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) { + return (u8)MS_CARD; + } + + return 0; +} + +int card_share_mode(struct rts51x_chip *chip, int card) +{ + u8 value; + + if (card == SD_CARD) { + value = CARD_SHARE_SD; + } else if (card == MS_CARD) { + value = CARD_SHARE_MS; + } else if (card == XD_CARD) { + value = CARD_SHARE_XD; + } else { + TRACE_RET(chip, STATUS_FAIL); + } + + RTS51X_WRITE_REG(chip, CARD_SHARE_MODE, CARD_SHARE_MASK, value); + + return STATUS_SUCCESS; +} + +int rts51x_select_card(struct rts51x_chip *chip, int card) +{ + int retval; + + if (chip->cur_card != card) { + u8 mod; + + if (card == SD_CARD) { + mod = SD_MOD_SEL; + } else if (card == MS_CARD) { + mod = MS_MOD_SEL; + } else if (card == XD_CARD) { + mod = XD_MOD_SEL; + } else { + TRACE_RET(chip, STATUS_FAIL); + } + RTS51X_WRITE_REG(chip, CARD_SELECT, 0x07, mod); + chip->cur_card = card; + + retval = card_share_mode(chip, card); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, retval); + } + } + + return STATUS_SUCCESS; +} + +void eject_card(struct rts51x_chip *chip, unsigned int lun) +{ + do_remaining_work(chip); + + if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) { + release_sd_card(chip); + chip->card_ejected |= SD_CARD; + chip->card_ready &= ~SD_CARD; + chip->capacity[lun] = 0; + } else if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) { + release_xd_card(chip); + chip->card_ejected |= XD_CARD; + chip->card_ready &= ~XD_CARD; + chip->capacity[lun] = 0; + } else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) { + release_ms_card(chip); + chip->card_ejected |= MS_CARD; + chip->card_ready &= ~MS_CARD; + chip->capacity[lun] = 0; + } + rts51x_write_register(chip, CARD_INT_PEND, XD_INT|MS_INT|SD_INT, XD_INT|MS_INT|SD_INT); +} + +void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip, u32 byte_cnt, u8 pack_size) +{ + if (pack_size > DMA_1024) { + pack_size = DMA_512; + } + + rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); + + rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC3, 0xFF, (u8)(byte_cnt >> 24)); + rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC2, 0xFF, (u8)(byte_cnt >> 16)); + rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC1, 0xFF, (u8)(byte_cnt >> 8)); + rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC0, 0xFF, (u8)byte_cnt); + + if (dir == DMA_FROM_DEVICE) { + rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_CTL, 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_CARD | DMA_EN | pack_size); + } else { + rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_CTL, 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_TO_CARD | DMA_EN | pack_size); + } +} + +int enable_card_clock(struct rts51x_chip *chip, u8 card) +{ + u8 clk_en = 0; + + if (card & XD_CARD) { + clk_en |= XD_CLK_EN; + } + if (card & SD_CARD) { + clk_en |= SD_CLK_EN; + } + if (card & MS_CARD) { + clk_en |= MS_CLK_EN; + } + + RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, clk_en); + + return STATUS_SUCCESS; +} + +int disable_card_clock(struct rts51x_chip *chip, u8 card) +{ + u8 clk_en = 0; + + if (card & XD_CARD) { + clk_en |= XD_CLK_EN; + } + if (card & SD_CARD) { + clk_en |= SD_CLK_EN; + } + if (card & MS_CARD) { + clk_en |= MS_CLK_EN; + } + + RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, 0); + + return STATUS_SUCCESS; +} + +int card_power_on(struct rts51x_chip *chip, u8 card) +{ + u8 mask, val1, val2; + + mask = POWER_MASK; + val1 = PARTIAL_POWER_ON; + val2 = POWER_ON; + +#ifdef SD_XD_IO_FOLLOW_PWR + if((card==SD_CARD)||(card==XD_CARD)) + { + RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND); + } +/* else if(card==XD_CARD) + { + RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND); + }*/ + else + { +#endif + RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val1); +#ifdef SD_XD_IO_FOLLOW_PWR + } +#endif + + udelay(chip->option.pwr_delay); + RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val2); +#ifdef SD_XD_IO_FOLLOW_PWR + if(card==SD_CARD) + { + rts51x_write_register(chip, CARD_PWR_CTL, LDO3318_PWR_MASK, LDO_ON); + } +#endif + + + return STATUS_SUCCESS; +} + +int card_power_off(struct rts51x_chip *chip, u8 card) +{ + u8 mask, val; + + mask = POWER_MASK; + val = POWER_OFF; + RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val); + + return STATUS_SUCCESS; +} + +int monitor_card_cd(struct rts51x_chip *chip, u8 card) +{ + int retval; + u8 card_cd[32] = {0}; + + card_cd[SD_CARD] = SD_CD; + card_cd[XD_CARD] = XD_CD; + card_cd[MS_CARD] = MS_CD; + + retval = rts51x_get_card_status(chip, &(chip->card_status)); + if (retval != STATUS_SUCCESS) { + return CD_NOT_EXIST; + } + + if (chip->card_status & card_cd[card]) { + return CD_EXIST; + } + + return CD_NOT_EXIST; +} + +int toggle_gpio(struct rts51x_chip *chip, u8 gpio) +{ + int retval; + u8 temp_reg; + u8 gpio_output[4] = { + 0x01, + }; + u8 gpio_oe[4] = { + 0x02, + }; + + retval = rts51x_ep0_read_register(chip, CARD_GPIO, &temp_reg); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, STATUS_FAIL); + } + temp_reg ^= gpio_output[gpio]; + retval = rts51x_ep0_write_register(chip, CARD_GPIO, 0xFF, temp_reg | gpio_oe[gpio]); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, STATUS_FAIL); + } + + return STATUS_SUCCESS; +} + +int turn_on_led(struct rts51x_chip *chip, u8 gpio) +{ + int retval; + u8 gpio_oe[4] = { + 0x02, + }; + u8 gpio_mask[4] = { + 0x03, + }; + + retval = rts51x_ep0_write_register(chip, CARD_GPIO, gpio_mask[gpio], gpio_oe[gpio]); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, STATUS_FAIL); + } + + return STATUS_SUCCESS; +} + +int turn_off_led(struct rts51x_chip *chip, u8 gpio) +{ + int retval; + u8 gpio_output[4] = { + 0x01, + }; + u8 gpio_oe[4] = { + 0x02, + }; + u8 gpio_mask[4] = { + 0x03, + }; + + retval = rts51x_ep0_write_register(chip, CARD_GPIO, gpio_mask[gpio], gpio_oe[gpio] | gpio_output[gpio]); + if (retval != STATUS_SUCCESS) { + TRACE_RET(chip, STATUS_FAIL); + } + + return STATUS_SUCCESS; +}
\ No newline at end of file |
