| /* 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 <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) { |
| rts51x_clear_start_time(chip); |
| 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)) { */ |
| 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)) { */ |
| if (!(chip->card_status & MS_CD) || (value & MS_INT)) |
| release_map |= MS_CARD; |
| } |
| } else { |
| if (chip->card_status & XD_CD) { |
| rts51x_clear_start_time(chip); |
| reset_map |= XD_CARD; |
| } else if (chip->card_status & SD_CD) { |
| rts51x_clear_start_time(chip); |
| reset_map |= SD_CARD; |
| } else if (chip->card_status & MS_CD) { |
| rts51x_clear_start_time(chip); |
| reset_map |= MS_CARD; |
| } else { |
| if (rts51x_check_start_time(chip)) |
| rts51x_set_start_time(chip); |
| } |
| } |
| |
| 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; |
| /* To make sure that the SSC clock div_n is |
| * equal or greater than min_N */ |
| 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 clock divided by 2, ssc depth must |
| * be multiplied by 2 */ |
| if (ssc_depth > 1) |
| ssc_depth -= 1; |
| else |
| ssc_depth = SSC_DEPTH_2M; |
| } else if (div == CLK_DIV_4) { |
| /* If clock divided by 4, ssc depth must |
| * be multiplied by 4 */ |
| if (ssc_depth > 2) |
| ssc_depth -= 2; |
| else |
| ssc_depth = SSC_DEPTH_2M; |
| } |
| } |
| } else { |
| /* Disable SSC */ |
| 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) |
| { |
| RTS51X_DEBUGP("eject card\n"); |
| RTS51X_SET_STAT(chip, STAT_RUN); |
| 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); |
| /* RTS51X_WRITE_REG(chip, CARD_PWR_CTL, |
| LDO3318_PWR_MASK, LDO_SUSPEND); */ |
| } |
| /* else if(card==XD_CARD) |
| { |
| RTS51X_WRITE_REG(chip, CARD_PWR_CTL, |
| mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND); |
| //RTS51X_WRITE_REG(chip, CARD_PWR_CTL, |
| // LDO3318_PWR_MASK, 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, |
| }; |
| if (chip->rts5179) { |
| retval = rts51x_ep0_read_register(chip, CARD_GPIO, &temp_reg); |
| if (retval != STATUS_SUCCESS) |
| TRACE_RET(chip, STATUS_FAIL); |
| temp_reg ^= gpio_oe[gpio]; |
| temp_reg &= 0xfe; /* bit 0 always set 0 */ |
| retval = |
| rts51x_ep0_write_register(chip, CARD_GPIO, 0x03, temp_reg); |
| if (retval != STATUS_SUCCESS) |
| TRACE_RET(chip, STATUS_FAIL); |
| } else { |
| 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; |
| } |