예제 #1
0
파일: rtsx_chip.c 프로젝트: MaxChina/linux
static int rts5208_init(struct rtsx_chip *chip)
{
	int retval;
	u16 reg = 0;
	u8 val = 0;

	RTSX_WRITE_REG(chip, CLK_SEL, 0x03, 0x03);
	RTSX_READ_REG(chip, CLK_SEL, &val);
	if (val == 0)
		chip->asic_code = 1;
	else
		chip->asic_code = 0;

	if (chip->asic_code) {
		retval = rtsx_read_phy_register(chip, 0x1C, &reg);
		if (retval != STATUS_SUCCESS)
			TRACE_RET(chip, STATUS_FAIL);

		RTSX_DEBUGP("Value of phy register 0x1C is 0x%x\n", reg);
		chip->ic_version = (reg >> 4) & 0x07;
		if (reg & PHY_DEBUG_MODE)
			chip->phy_debug_mode = 1;
		else
			chip->phy_debug_mode = 0;

	} else {
예제 #2
0
void do_reset_sd_card(struct rtsx_chip *chip)
{
	int retval;
	
	RTSX_DEBUGP(("%s: %d, card2lun = 0x%x\n", __FUNCTION__, 
		     chip->sd_reset_counter, chip->card2lun[SD_CARD]));
	
	if (chip->card2lun[SD_CARD] >= MAX_ALLOWED_LUN_CNT) {
		clear_bit(SD_NR, &(chip->need_reset));
		chip->sd_reset_counter = 0;
		chip->sd_show_cnt = 0;
		return;
	}
	
	chip->rw_fail_cnt[chip->card2lun[SD_CARD]] = 0;
	
	rtsx_set_stat(chip, RTSX_STAT_RUN);
	rtsx_write_register(chip, SDIO_CTRL, 0xFF, 0);
	
	retval = reset_sd_card(chip);
	if (chip->need_release & SD_CARD) {
		return;
	}
	if (retval == STATUS_SUCCESS) {
		clear_bit(SD_NR, &(chip->need_reset));
		chip->sd_reset_counter = 0;
		chip->sd_show_cnt = 0;
		chip->card_ready |= SD_CARD;
		chip->card_fail &= ~SD_CARD;
		chip->rw_card[chip->card2lun[SD_CARD]] = sd_rw;
	} else {
		if (chip->sd_io || (chip->sd_reset_counter >= MAX_RESET_CNT)) {
			clear_bit(SD_NR, &(chip->need_reset));
			chip->sd_reset_counter = 0;
			chip->sd_show_cnt = 0;
		} else {
			chip->sd_reset_counter ++;
		}
		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;

		rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0);
		if (!chip->ft2_fast_mode) {
			card_power_off(chip, SD_CARD);
		}
		if (chip->sd_io) {
			
			chip->sd_int = 0;
			try_to_switch_sdio_ctrl(chip);
		} else {
			disable_card_clock(chip, SD_CARD);
		}
	}
}
예제 #3
0
void try_to_switch_sdio_ctrl(struct rtsx_chip *chip)
{
	u8 reg1 = 0, reg2 = 0;

	rtsx_read_register(chip, 0xFF34, &reg1);
	rtsx_read_register(chip, 0xFF38, &reg2);
	RTSX_DEBUGP("reg 0xFF34: 0x%x, reg 0xFF38: 0x%x\n", reg1, reg2);
	if ((reg1 & 0xC0) && (reg2 & 0xC0)) {
		chip->sd_int = 1;
		rtsx_write_register(chip, SDIO_CTRL, 0xFF, SDIO_BUS_CTRL | SDIO_CD_CTRL);
		rtsx_write_register(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON);
	}
}
예제 #4
0
void dynamic_configure_sdio_aspm(struct rtsx_chip *chip)
{
	u8 buf[12], reg;
	int i;

	for (i = 0; i < 12; i++) {
		rtsx_read_register(chip, 0xFF08 + i, &buf[i]);
	}
	rtsx_read_register(chip, 0xFF25, &reg);
	if ((memcmp(buf, chip->sdio_raw_data, 12) != 0) || (reg & 0x03)) {
		chip->sdio_counter = 0;
		chip->sdio_idle = 0;
	} else {
		if (!chip->sdio_idle) {
			chip->sdio_counter ++;
			if (chip->sdio_counter >= SDIO_IDLE_COUNT) {
				chip->sdio_counter = 0;
				chip->sdio_idle = 1;
			}
		}
	}
	memcpy(chip->sdio_raw_data, buf, 12);

	if (chip->sdio_idle) {
		if (!chip->sdio_aspm) {
			RTSX_DEBUGP(("SDIO enter ASPM!\n"));
			rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC, 
					0x30 | (chip->aspm_level[1] << 2));
			chip->sdio_aspm = 1;
		}
	} else {
		if (chip->sdio_aspm) {
			RTSX_DEBUGP(("SDIO exit ASPM!\n"));
			rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC, 0x30);
			chip->sdio_aspm = 0;
		}
	}	
}
예제 #5
0
파일: rtsx_chip.c 프로젝트: MaxChina/linux
void rtsx_enable_bus_int(struct rtsx_chip *chip)
{
	u32 reg = 0;
#ifndef DISABLE_CARD_INT
	int i;
#endif

	reg = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN;

#ifndef DISABLE_CARD_INT
	for (i = 0; i <= chip->max_lun; i++) {
		RTSX_DEBUGP("lun2card[%d] = 0x%02x\n", i, chip->lun2card[i]);

		if (chip->lun2card[i] & XD_CARD)
			reg |= XD_INT_EN;
		if (chip->lun2card[i] & SD_CARD)
			reg |= SD_INT_EN;
		if (chip->lun2card[i] & MS_CARD)
			reg |= MS_INT_EN;
	}
	if (chip->hw_bypass_sd)
		reg &= ~((u32)SD_INT_EN);
#endif

	if (chip->ic_version >= IC_VER_C)
		reg |= DELINK_INT_EN;
#ifdef SUPPORT_OCP
	reg |= OC_INT_EN;
#endif
	if (!chip->adma_mode)
		reg |= DATA_DONE_INT_EN;

	/* Enable Bus Interrupt */
	rtsx_writel(chip, RTSX_BIER, reg);

	RTSX_DEBUGP("RTSX_BIER: 0x%08x\n", reg);
}
예제 #6
0
파일: rtsx_card.c 프로젝트: 7799/linux
int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
	u32 sec_addr, u16 sec_cnt)
{
	int retval;
	unsigned int lun = SCSI_LUN(srb);
	int i;

	if (chip->rw_card[lun] == NULL)
		TRACE_RET(chip, STATUS_FAIL);

	for (i = 0; i < 3; i++) {
		chip->rw_need_retry = 0;

		retval = chip->rw_card[lun](srb, chip, sec_addr, sec_cnt);
		if (retval != STATUS_SUCCESS) {
			if (rtsx_check_chip_exist(chip) != STATUS_SUCCESS) {
				rtsx_release_chip(chip);
				TRACE_RET(chip, STATUS_FAIL);
			}
			if (detect_card_cd(chip, chip->cur_card) !=
							STATUS_SUCCESS)
				TRACE_RET(chip, STATUS_FAIL);

			if (!chip->rw_need_retry) {
				RTSX_DEBUGP("RW fail, but no need to retry\n");
				break;
			}
		} else {
			chip->rw_need_retry = 0;
			break;
		}

		RTSX_DEBUGP("Retry RW, (i = %d)\n", i);
	}

	return retval;
}
예제 #7
0
void do_reset_ms_card(struct rtsx_chip *chip)
{
	int retval;

	RTSX_DEBUGP("%s: %d, card2lun = 0x%x\n", __func__,
		     chip->ms_reset_counter, chip->card2lun[MS_CARD]);

	if (chip->card2lun[MS_CARD] >= MAX_ALLOWED_LUN_CNT) {
		clear_bit(MS_NR, &(chip->need_reset));
		chip->ms_reset_counter = 0;
		chip->ms_show_cnt = 0;
		return;
	}

	chip->rw_fail_cnt[chip->card2lun[MS_CARD]] = 0;

	rtsx_set_stat(chip, RTSX_STAT_RUN);
	rtsx_write_register(chip, SDIO_CTRL, 0xFF, 0);

	retval = reset_ms_card(chip);
	if (chip->need_release & MS_CARD)
		return;
	if (retval == STATUS_SUCCESS) {
		clear_bit(MS_NR, &(chip->need_reset));
		chip->ms_reset_counter = 0;
		chip->card_ready |= MS_CARD;
		chip->card_fail &= ~MS_CARD;
		chip->rw_card[chip->card2lun[MS_CARD]] = ms_rw;
	} else {
		if (chip->ms_reset_counter >= MAX_RESET_CNT) {
			clear_bit(MS_NR, &(chip->need_reset));
			chip->ms_reset_counter = 0;
			chip->ms_show_cnt = 0;
		} else {
			chip->ms_reset_counter++;
		}
		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;

		rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0);
		if (!chip->ft2_fast_mode)
			card_power_off(chip, MS_CARD);
		disable_card_clock(chip, MS_CARD);
	}
}
예제 #8
0
파일: rtsx_card.c 프로젝트: 7799/linux
int detect_card_cd(struct rtsx_chip *chip, int card)
{
	u32 card_cd, status;

	if (card == SD_CARD) {
		card_cd = SD_EXIST;
	} else if (card == MS_CARD) {
		card_cd = MS_EXIST;
	} else if (card == XD_CARD) {
		card_cd = XD_EXIST;
	} else {
		RTSX_DEBUGP("Wrong card type: 0x%x\n", card);
		TRACE_RET(chip, STATUS_FAIL);
	}

	status = rtsx_readl(chip, RTSX_BIPR);
	if (!(status & card_cd))
		TRACE_RET(chip, STATUS_FAIL);

	return STATUS_SUCCESS;
}
예제 #9
0
int switch_normal_clock(struct rtsx_chip *chip, int clk)
{
	u8 sel, div, mcu_cnt;
	int sd_vpclk_phase_reset = 0;

	if (chip->cur_clk == clk)
		return STATUS_SUCCESS;

	if (CHECK_PID(chip, 0x5209) && (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:
		RTSX_DEBUGP("Switch clock to 20MHz\n");
		sel = SSC_80;
		div = CLK_DIV_4;
		mcu_cnt = 7;
		break;

	case CLK_30:
		RTSX_DEBUGP("Switch clock to 30MHz\n");
		sel = SSC_120;
		div = CLK_DIV_4;
		mcu_cnt = 7;
		break;

	case CLK_40:
		RTSX_DEBUGP("Switch clock to 40MHz\n");
		sel = SSC_80;
		div = CLK_DIV_2;
		mcu_cnt = 7;
		break;

	case CLK_50:
		RTSX_DEBUGP("Switch clock to 50MHz\n");
		sel = SSC_100;
		div = CLK_DIV_2;
		mcu_cnt = 6;
		break;

	case CLK_60:
		RTSX_DEBUGP("Switch clock to 60MHz\n");
		sel = SSC_120;
		div = CLK_DIV_2;
		mcu_cnt = 6;
		break;

	case CLK_80:
		RTSX_DEBUGP("Switch clock to 80MHz\n");
		sel = SSC_80;
		div = CLK_DIV_1;
		mcu_cnt = 5;
		break;

	case CLK_100:
		RTSX_DEBUGP("Switch clock to 100MHz\n");
		sel = SSC_100;
		div = CLK_DIV_1;
		mcu_cnt = 5;
		break;

	case CLK_120:
		RTSX_DEBUGP("Switch clock to 120MHz\n");
		sel = SSC_120;
		div = CLK_DIV_1;
		mcu_cnt = 5;
		break;

	case CLK_150:
		RTSX_DEBUGP("Switch clock to 150MHz\n");
		sel = SSC_150;
		div = CLK_DIV_1;
		mcu_cnt = 4;
		break;

	case CLK_200:
		RTSX_DEBUGP("Switch clock to 200MHz\n");
		sel = SSC_200;
		div = CLK_DIV_1;
		mcu_cnt = 4;
		break;

	default:
		RTSX_DEBUGP("Try to switch to an illegal clock (%d)\n", clk);
		TRACE_RET(chip, STATUS_FAIL);
	}

	RTSX_WRITE_REG(chip, CLK_CTL, 0xFF, CLK_LOW_FREQ);
	if (sd_vpclk_phase_reset) {
		RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
		RTSX_WRITE_REG(chip, SD_VPCLK1_CTL, PHASE_NOT_RESET, 0);
	}
	RTSX_WRITE_REG(chip, CLK_DIV, 0xFF, (div << 4) | mcu_cnt);
	RTSX_WRITE_REG(chip, CLK_SEL, 0xFF, sel);

	if (sd_vpclk_phase_reset) {
		udelay(200);
		RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
		RTSX_WRITE_REG(chip, SD_VPCLK1_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
		udelay(200);
	}
	RTSX_WRITE_REG(chip, CLK_CTL, 0xFF, 0);

	chip->cur_clk = clk;

	return STATUS_SUCCESS;
}
예제 #10
0
int switch_ssc_clock(struct rtsx_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, ssc_depth_mask;
	int sd_vpclk_phase_reset = 0;

	if (chip->cur_clk == clk)
		return STATUS_SUCCESS;

	if (CHECK_PID(chip, 0x5209)) {
		min_N = 80;
		max_N = 208;
		max_div = CLK_DIV_8;
	} else {
		min_N = 60;
		max_N = 120;
		max_div = CLK_DIV_4;
	}

	if (CHECK_PID(chip, 0x5209) && (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;
	}

	RTSX_DEBUGP("Switch SSC clock to %dMHz (cur_clk = %d)\n", clk, chip->cur_clk);

	if ((clk <= 2) || (N > max_N)) {
		TRACE_RET(chip, STATUS_FAIL);
	}

	mcu_cnt = (u8)(125/clk + 3);
	if (CHECK_PID(chip, 0x5209)) {
		if (mcu_cnt > 15)
			mcu_cnt = 15;
	} else {
		if (mcu_cnt > 7)
			mcu_cnt = 7;
	}

	div = CLK_DIV_1;
	while ((N < min_N) && (div < max_div)) {
		N = (N + 2) * 2 - 2;
		div++;
	}
	RTSX_DEBUGP("N = %d, div = %d\n", N, div);

	if (chip->ssc_en) {
		if (CHECK_PID(chip, 0x5209)) {
			if (chip->cur_card == SD_CARD) {
				if (CHK_SD_SDR104(sd_card)) {
					ssc_depth = chip->ssc_depth_sd_sdr104;
				} else if (CHK_SD_SDR50(sd_card)) {
					ssc_depth = chip->ssc_depth_sd_sdr50;
				} else if (CHK_SD_DDR50(sd_card)) {
					ssc_depth = double_depth(chip->ssc_depth_sd_ddr50);
				} else if (CHK_SD_HS(sd_card)) {
					ssc_depth = double_depth(chip->ssc_depth_sd_hs);
				} else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) {
					ssc_depth = double_depth(chip->ssc_depth_mmc_52m);
				} else {
					ssc_depth = double_depth(chip->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->ssc_depth_ms_hg);
					} else {
						ssc_depth = double_depth(chip->ssc_depth_ms_4bit);
					}
				} else {
					if (CHK_MS4BIT(ms_card)) {
						ssc_depth = double_depth(chip->ssc_depth_ms_4bit);
					} else {
						ssc_depth = double_depth(chip->ssc_depth_low_speed);
					}
				}
			} else {
				ssc_depth = double_depth(chip->ssc_depth_low_speed);
			}

			if (ssc_depth) {
				if (div == CLK_DIV_2) {
					if (ssc_depth > 1) {
						ssc_depth -= 1;
					} else {
						ssc_depth = SSC_DEPTH_4M;
					}
				} else if (div == CLK_DIV_4) {
					if (ssc_depth > 2) {
						ssc_depth -= 2;
					} else {
						ssc_depth = SSC_DEPTH_4M;
					}
				} else if (div == CLK_DIV_8) {
					if (ssc_depth > 3) {
						ssc_depth -= 3;
					} else {
						ssc_depth = SSC_DEPTH_4M;
					}
				}
			}
		} else {
			ssc_depth = 0x01;
			N -= 2;
		}
	} else {
		ssc_depth = 0;
	}

	if (CHECK_PID(chip, 0x5209)) {
		ssc_depth_mask = SSC_DEPTH_MASK;
	} else {
		ssc_depth_mask = 0x03;
	}

	RTSX_DEBUGP("ssc_depth = %d\n", ssc_depth);

	rtsx_init_cmd(chip);
	rtsx_add_cmd(chip, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
	rtsx_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0xFF, (div << 4) | mcu_cnt);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL2, ssc_depth_mask, ssc_depth);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
	if (sd_vpclk_phase_reset) {
		rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
		rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
	}

	retval = rtsx_send_cmd(chip, 0, WAIT_TIME);
	if (retval < 0) {
		TRACE_RET(chip, STATUS_ERROR);
	}

	udelay(10);
	RTSX_WRITE_REG(chip, CLK_CTL, CLK_LOW_FREQ, 0);

	chip->cur_clk = clk;

	return STATUS_SUCCESS;
}
예제 #11
0
void rtsx_init_cards(struct rtsx_chip *chip)
{
	if (RTSX_TST_DELINK(chip) && (rtsx_get_stat(chip) != RTSX_STAT_SS)) {
		RTSX_DEBUGP("Reset chip in polling thread!\n");
		rtsx_reset_chip(chip);
		RTSX_CLR_DELINK(chip);
	}

#ifdef DISABLE_CARD_INT
	card_cd_debounce(chip, &(chip->need_reset), &(chip->need_release));
#endif

	if (chip->need_release) {
		if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN)) {
			if (chip->int_reg & XD_EXIST) {
				clear_bit(SD_NR, &(chip->need_release));
				clear_bit(MS_NR, &(chip->need_release));
			}
		}

		if (!(chip->card_exist & SD_CARD) && !chip->sd_io)
			clear_bit(SD_NR, &(chip->need_release));
		if (!(chip->card_exist & XD_CARD))
			clear_bit(XD_NR, &(chip->need_release));
		if (!(chip->card_exist & MS_CARD))
			clear_bit(MS_NR, &(chip->need_release));

		RTSX_DEBUGP("chip->need_release = 0x%x\n", (unsigned int)(chip->need_release));

#ifdef SUPPORT_OCP
		if (chip->need_release) {
			if (CHECK_PID(chip, 0x5209)) {
				u8 mask = 0, val = 0;
				if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
					if (chip->ocp_stat & (MS_OC_NOW | MS_OC_EVER)) {
						mask |= MS_OCP_INT_CLR | MS_OC_CLR;
						val |= MS_OCP_INT_CLR | MS_OC_CLR;
					}
				}
				if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
					mask |= SD_OCP_INT_CLR | SD_OC_CLR;
					val |= SD_OCP_INT_CLR | SD_OC_CLR;
				}
				if (mask)
					rtsx_write_register(chip, OCPCTL, mask, val);
			} else {
				if (chip->ocp_stat & (CARD_OC_NOW | CARD_OC_EVER))
					rtsx_write_register(chip, OCPCLR,
							    CARD_OC_INT_CLR | CARD_OC_CLR,
							    CARD_OC_INT_CLR | CARD_OC_CLR);
			}
			chip->ocp_stat = 0;
		}
#endif
		if (chip->need_release) {
			rtsx_set_stat(chip, RTSX_STAT_RUN);
			rtsx_force_power_on(chip, SSC_PDCTL | OC_PDCTL);
		}

		if (chip->need_release & SD_CARD) {
			clear_bit(SD_NR, &(chip->need_release));
			chip->card_exist &= ~SD_CARD;
			chip->card_ejected &= ~SD_CARD;
			chip->card_fail &= ~SD_CARD;
			CLR_BIT(chip->lun_mc, chip->card2lun[SD_CARD]);
			chip->rw_fail_cnt[chip->card2lun[SD_CARD]] = 0;
			rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH);

			release_sdio(chip);
			release_sd_card(chip);
		}

		if (chip->need_release & XD_CARD) {
			clear_bit(XD_NR, &(chip->need_release));
			chip->card_exist &= ~XD_CARD;
			chip->card_ejected &= ~XD_CARD;
			chip->card_fail &= ~XD_CARD;
			CLR_BIT(chip->lun_mc, chip->card2lun[XD_CARD]);
			chip->rw_fail_cnt[chip->card2lun[XD_CARD]] = 0;

			release_xd_card(chip);

			if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN))
				rtsx_write_register(chip, HOST_SLEEP_STATE, 0xC0, 0xC0);
		}

		if (chip->need_release & MS_CARD) {
			clear_bit(MS_NR, &(chip->need_release));
			chip->card_exist &= ~MS_CARD;
			chip->card_ejected &= ~MS_CARD;
			chip->card_fail &= ~MS_CARD;
			CLR_BIT(chip->lun_mc, chip->card2lun[MS_CARD]);
			chip->rw_fail_cnt[chip->card2lun[MS_CARD]] = 0;

			release_ms_card(chip);
		}

		RTSX_DEBUGP("chip->card_exist = 0x%x\n", chip->card_exist);

		if (!chip->card_exist)
			turn_off_led(chip, LED_GPIO);
	}

	if (chip->need_reset) {
		RTSX_DEBUGP("chip->need_reset = 0x%x\n", (unsigned int)(chip->need_reset));

		rtsx_reset_cards(chip);
	}

	if (chip->need_reinit) {
		RTSX_DEBUGP("chip->need_reinit = 0x%x\n", (unsigned int)(chip->need_reinit));

		rtsx_reinit_cards(chip, 0);
	}
}
예제 #12
0
파일: rtsx.c 프로젝트: GerardGarcia/linux
static int __devinit rtsx_probe(struct pci_dev *pci,
				const struct pci_device_id *pci_id)
{
	struct Scsi_Host *host;
	struct rtsx_dev *dev;
	int err = 0;
	struct task_struct *th;

	RTSX_DEBUGP("Realtek PCI-E card reader detected\n");

	err = pci_enable_device(pci);
	if (err < 0) {
		printk(KERN_ERR "PCI enable device failed!\n");
		return err;
	}

	err = pci_request_regions(pci, CR_DRIVER_NAME);
	if (err < 0) {
		printk(KERN_ERR "PCI request regions for %s failed!\n",
		       CR_DRIVER_NAME);
		pci_disable_device(pci);
		return err;
	}

	/*
	 * Ask the SCSI layer to allocate a host structure, with extra
	 * space at the end for our private rtsx_dev structure.
	 */
	host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev));
	if (!host) {
		printk(KERN_ERR "Unable to allocate the scsi host\n");
		pci_release_regions(pci);
		pci_disable_device(pci);
		return -ENOMEM;
	}

	dev = host_to_rtsx(host);
	memset(dev, 0, sizeof(struct rtsx_dev));

	dev->chip = kzalloc(sizeof(struct rtsx_chip), GFP_KERNEL);
	if (dev->chip == NULL)
		goto errout;

	spin_lock_init(&dev->reg_lock);
	mutex_init(&(dev->dev_mutex));
	init_completion(&dev->cmnd_ready);
	init_completion(&dev->control_exit);
	init_completion(&dev->polling_exit);
	init_completion(&(dev->notify));
	init_completion(&dev->scanning_done);
	init_waitqueue_head(&dev->delay_wait);

	dev->pci = pci;
	dev->irq = -1;

	printk(KERN_INFO "Resource length: 0x%x\n",
	       (unsigned int)pci_resource_len(pci, 0));
	dev->addr = pci_resource_start(pci, 0);
	dev->remap_addr = ioremap_nocache(dev->addr, pci_resource_len(pci, 0));
	if (dev->remap_addr == NULL) {
		printk(KERN_ERR "ioremap error\n");
		err = -ENXIO;
		goto errout;
	}

	/*
	 * Using "unsigned long" cast here to eliminate gcc warning in
	 * 64-bit system
	 */
	printk(KERN_INFO "Original address: 0x%lx, remapped address: 0x%lx\n",
	       (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr));

	dev->rtsx_resv_buf = dma_alloc_coherent(&(pci->dev), RTSX_RESV_BUF_LEN,
			&(dev->rtsx_resv_buf_addr), GFP_KERNEL);
	if (dev->rtsx_resv_buf == NULL) {
		printk(KERN_ERR "alloc dma buffer fail\n");
		err = -ENXIO;
		goto errout;
	}
	dev->chip->host_cmds_ptr = dev->rtsx_resv_buf;
	dev->chip->host_cmds_addr = dev->rtsx_resv_buf_addr;
	dev->chip->host_sg_tbl_ptr = dev->rtsx_resv_buf + HOST_CMDS_BUF_LEN;
	dev->chip->host_sg_tbl_addr = dev->rtsx_resv_buf_addr +
				      HOST_CMDS_BUF_LEN;

	dev->chip->rtsx = dev;

	rtsx_init_options(dev->chip);

	printk(KERN_INFO "pci->irq = %d\n", pci->irq);

	if (dev->chip->msi_en) {
		if (pci_enable_msi(pci) < 0)
			dev->chip->msi_en = 0;
	}

	if (rtsx_acquire_irq(dev) < 0) {
		err = -EBUSY;
		goto errout;
	}

	pci_set_master(pci);
	synchronize_irq(dev->irq);

	rtsx_init_chip(dev->chip);

	/* Start up our control thread */
	th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME);
	if (IS_ERR(th)) {
		printk(KERN_ERR "Unable to start control thread\n");
		err = PTR_ERR(th);
		goto errout;
	}
	dev->ctl_thread = th;

	err = scsi_add_host(host, &pci->dev);
	if (err) {
		printk(KERN_ERR "Unable to add the scsi host\n");
		goto errout;
	}

	/* Start up the thread for delayed SCSI-device scanning */
	th = kthread_create(rtsx_scan_thread, dev, "rtsx-scan");
	if (IS_ERR(th)) {
		printk(KERN_ERR "Unable to start the device-scanning thread\n");
		quiesce_and_remove_host(dev);
		err = PTR_ERR(th);
		goto errout;
	}

	wake_up_process(th);

	/* Start up the thread for polling thread */
	th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling");
	if (IS_ERR(th)) {
		printk(KERN_ERR "Unable to start the device-polling thread\n");
		quiesce_and_remove_host(dev);
		err = PTR_ERR(th);
		goto errout;
	}
	dev->polling_thread = th;

	pci_set_drvdata(pci, dev);

	return 0;

	/* We come here if there are any problems */
errout:
	printk(KERN_ERR "rtsx_probe() failed\n");
	release_everything(dev);

	return err;
}
예제 #13
0
파일: rtsx_chip.c 프로젝트: MaxChina/linux
int rtsx_reset_chip(struct rtsx_chip *chip)
{
	int retval;

	rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);

	rtsx_disable_aspm(chip);

	RTSX_WRITE_REG(chip, HOST_SLEEP_STATE, 0x03, 0x00);

	/* Disable card clock */
	RTSX_WRITE_REG(chip, CARD_CLK_EN, 0x1E, 0);

#ifdef SUPPORT_OCP
	/* SSC power on, OCD power on */
	if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
		RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, 0);
	else
		RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, MS_OC_POWER_DOWN);

	RTSX_WRITE_REG(chip, OCPPARA1, OCP_TIME_MASK, OCP_TIME_800);
	RTSX_WRITE_REG(chip, OCPPARA2, OCP_THD_MASK, OCP_THD_244_946);
	RTSX_WRITE_REG(chip, OCPCTL, 0xFF, CARD_OC_INT_EN | CARD_DETECT_EN);
#else
	/* OC power down */
	RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, OC_POWER_DOWN);
#endif

	if (!CHECK_PID(chip, 0x5288))
		RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0xFF, 0x03);

	/* Turn off LED */
	RTSX_WRITE_REG(chip, CARD_GPIO, 0xFF, 0x03);

	/* Reset delink mode */
	RTSX_WRITE_REG(chip, CHANGE_LINK_STATE, 0x0A, 0);

	/* Card driving select */
	RTSX_WRITE_REG(chip, CARD_DRIVE_SEL, 0xFF, chip->card_drive_sel);

#ifdef LED_AUTO_BLINK
	RTSX_WRITE_REG(chip, CARD_AUTO_BLINK, 0xFF,
			LED_BLINK_SPEED | BLINK_EN | LED_GPIO0);
#endif

	if (chip->asic_code) {
		/* Enable SSC Clock */
		RTSX_WRITE_REG(chip, SSC_CTL1, 0xFF, SSC_8X_EN | SSC_SEL_4M);
		RTSX_WRITE_REG(chip, SSC_CTL2, 0xFF, 0x12);
	}

	/* Disable cd_pwr_save (u_force_rst_core_en=0, u_cd_rst_core_en=0)
	      0xFE5B
	      bit[1]    u_cd_rst_core_en	rst_value = 0
	      bit[2]    u_force_rst_core_en	rst_value = 0
	      bit[5]    u_mac_phy_rst_n_dbg	rst_value = 1
	      bit[4]	u_non_sticky_rst_n_dbg	rst_value = 0
	*/
	RTSX_WRITE_REG(chip, CHANGE_LINK_STATE, 0x16, 0x10);

	/* Enable ASPM */
	if (chip->aspm_l0s_l1_en) {
		if (chip->dynamic_aspm) {
			if (CHK_SDIO_EXIST(chip)) {
				if (CHECK_PID(chip, 0x5288)) {
					retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, chip->aspm_l0s_l1_en);
					if (retval != STATUS_SUCCESS)
						TRACE_RET(chip, STATUS_FAIL);
				}
			}
		} else {
			if (CHECK_PID(chip, 0x5208))
				RTSX_WRITE_REG(chip, ASPM_FORCE_CTL,
					0xFF, 0x3F);

			retval = rtsx_write_config_byte(chip, LCTLR,
							chip->aspm_l0s_l1_en);
			if (retval != STATUS_SUCCESS)
				TRACE_RET(chip, STATUS_FAIL);

			chip->aspm_level[0] = chip->aspm_l0s_l1_en;
			if (CHK_SDIO_EXIST(chip)) {
				chip->aspm_level[1] = chip->aspm_l0s_l1_en;
				if (CHECK_PID(chip, 0x5288))
					retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, chip->aspm_l0s_l1_en);
				else
					retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF, chip->aspm_l0s_l1_en);

				if (retval != STATUS_SUCCESS)
					TRACE_RET(chip, STATUS_FAIL);

			}

			chip->aspm_enabled = 1;
		}
	} else {
		if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
			retval = rtsx_write_phy_register(chip, 0x07, 0x0129);
			if (retval != STATUS_SUCCESS)
				TRACE_RET(chip, STATUS_FAIL);
		}
		retval = rtsx_write_config_byte(chip, LCTLR,
						chip->aspm_l0s_l1_en);
		if (retval != STATUS_SUCCESS)
			TRACE_RET(chip, STATUS_FAIL);
	}

	retval = rtsx_write_config_byte(chip, 0x81, 1);
	if (retval != STATUS_SUCCESS)
		TRACE_RET(chip, STATUS_FAIL);

	if (CHK_SDIO_EXIST(chip)) {
		if (CHECK_PID(chip, 0x5288))
			retval = rtsx_write_cfg_dw(chip, 2, 0xC0,
						0xFF00, 0x0100);
		else
			retval = rtsx_write_cfg_dw(chip, 1, 0xC0,
						0xFF00, 0x0100);

		if (retval != STATUS_SUCCESS)
			TRACE_RET(chip, STATUS_FAIL);

	}

	if (CHECK_PID(chip, 0x5288)) {
		if (!CHK_SDIO_EXIST(chip)) {
			retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF,
						0x0103);
			if (retval != STATUS_SUCCESS)
				TRACE_RET(chip, STATUS_FAIL);

			retval = rtsx_write_cfg_dw(chip, 2, 0x84, 0xFF, 0x03);
			if (retval != STATUS_SUCCESS)
				TRACE_RET(chip, STATUS_FAIL);

		}
	}

	RTSX_WRITE_REG(chip, IRQSTAT0, LINK_RDY_INT, LINK_RDY_INT);

	RTSX_WRITE_REG(chip, PERST_GLITCH_WIDTH, 0xFF, 0x80);

	/* Enable PCIE interrupt */
	if (chip->asic_code) {
		if (CHECK_PID(chip, 0x5208)) {
			if (chip->phy_debug_mode) {
				RTSX_WRITE_REG(chip, CDRESUMECTL, 0x77, 0);
				rtsx_disable_bus_int(chip);
			} else {
				rtsx_enable_bus_int(chip);
			}

			if (chip->ic_version >= IC_VER_D) {
				u16 reg;
				retval = rtsx_read_phy_register(chip, 0x00,
								&reg);
				if (retval != STATUS_SUCCESS)
					TRACE_RET(chip, STATUS_FAIL);

				reg &= 0xFE7F;
				reg |= 0x80;
				retval = rtsx_write_phy_register(chip, 0x00,
								reg);
				if (retval != STATUS_SUCCESS)
					TRACE_RET(chip, STATUS_FAIL);

				retval = rtsx_read_phy_register(chip, 0x1C,
								&reg);
				if (retval != STATUS_SUCCESS)
					TRACE_RET(chip, STATUS_FAIL);

				reg &= 0xFFF7;
				retval = rtsx_write_phy_register(chip, 0x1C,
								reg);
				if (retval != STATUS_SUCCESS)
					TRACE_RET(chip, STATUS_FAIL);

			}

			if (chip->driver_first_load &&
				(chip->ic_version < IC_VER_C))
				rtsx_calibration(chip);

		} else {
			rtsx_enable_bus_int(chip);
		}
	} else {
		rtsx_enable_bus_int(chip);
	}

	chip->need_reset = 0;

	chip->int_reg = rtsx_readl(chip, RTSX_BIPR);

	if (chip->hw_bypass_sd)
		goto NextCard;
	RTSX_DEBUGP("In rtsx_reset_chip, chip->int_reg = 0x%x\n",
		chip->int_reg);
	if (chip->int_reg & SD_EXIST) {
#ifdef HW_AUTO_SWITCH_SD_BUS
		if (CHECK_PID(chip, 0x5208) && (chip->ic_version < IC_VER_C))
			retval = rtsx_pre_handle_sdio_old(chip);
		else
			retval = rtsx_pre_handle_sdio_new(chip);

		RTSX_DEBUGP("chip->need_reset = 0x%x (rtsx_reset_chip)\n",
			(unsigned int)(chip->need_reset));
#else  /* HW_AUTO_SWITCH_SD_BUS */
		retval = rtsx_pre_handle_sdio_old(chip);
#endif  /* HW_AUTO_SWITCH_SD_BUS */
		if (retval != STATUS_SUCCESS)
			TRACE_RET(chip, STATUS_FAIL);

	} else {
		chip->sd_io = 0;
		RTSX_WRITE_REG(chip, SDIO_CTRL, SDIO_BUS_CTRL | SDIO_CD_CTRL,
			0);
	}

NextCard:
	if (chip->int_reg & XD_EXIST)
		chip->need_reset |= XD_CARD;
	if (chip->int_reg & MS_EXIST)
		chip->need_reset |= MS_CARD;
	if (chip->int_reg & CARD_EXIST)
		RTSX_WRITE_REG(chip, SSC_CTL1, SSC_RSTB, SSC_RSTB);

	RTSX_DEBUGP("In rtsx_init_chip, chip->need_reset = 0x%x\n",
		(unsigned int)(chip->need_reset));

	RTSX_WRITE_REG(chip, RCCTL, 0x01, 0x00);

	if (CHECK_PID(chip, 0x5208) || CHECK_PID(chip, 0x5288)) {
		/* Turn off main power when entering S3/S4 state */
		RTSX_WRITE_REG(chip, MAIN_PWR_OFF_CTL, 0x03, 0x03);
	}

	if (chip->remote_wakeup_en && !chip->auto_delink_en) {
		RTSX_WRITE_REG(chip, WAKE_SEL_CTL, 0x07, 0x07);
		if (chip->aux_pwr_exist)
			RTSX_WRITE_REG(chip, PME_FORCE_CTL, 0xFF, 0x33);
	} else {
		RTSX_WRITE_REG(chip, WAKE_SEL_CTL, 0x07, 0x04);
		RTSX_WRITE_REG(chip, PME_FORCE_CTL, 0xFF, 0x30);
	}

	if (CHECK_PID(chip, 0x5208) && (chip->ic_version >= IC_VER_D))
		RTSX_WRITE_REG(chip, PETXCFG, 0x1C, 0x14);

	if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
		retval = rtsx_clr_phy_reg_bit(chip, 0x1C, 2);
		if (retval != STATUS_SUCCESS)
			TRACE_RET(chip, STATUS_FAIL);
	}

	if (chip->ft2_fast_mode) {
		RTSX_WRITE_REG(chip, CARD_PWR_CTL, 0xFF,
			MS_PARTIAL_POWER_ON | SD_PARTIAL_POWER_ON);
		udelay(chip->pmos_pwr_on_interval);
		RTSX_WRITE_REG(chip, CARD_PWR_CTL, 0xFF,
			MS_POWER_ON | SD_POWER_ON);

		wait_timeout(200);
	}

	/* Reset card */
	rtsx_reset_detected_cards(chip, 0);

	chip->driver_first_load = 0;

	return STATUS_SUCCESS;
}
예제 #14
0
파일: rtsx_chip.c 프로젝트: MaxChina/linux
static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
{
	u8 tmp;
	int sw_bypass_sd = 0;
	int retval;

	if (chip->driver_first_load) {
		if (CHECK_PID(chip, 0x5288)) {
			RTSX_READ_REG(chip, 0xFE5A, &tmp);
			if (tmp & 0x08)
				sw_bypass_sd = 1;
		} else if (CHECK_PID(chip, 0x5208)) {
			RTSX_READ_REG(chip, 0xFE70, &tmp);
			if (tmp & 0x80)
				sw_bypass_sd = 1;
		}
	} else {
		if (chip->sdio_in_charge)
			sw_bypass_sd = 1;
	}
	RTSX_DEBUGP("chip->sdio_in_charge = %d\n", chip->sdio_in_charge);
	RTSX_DEBUGP("chip->driver_first_load = %d\n", chip->driver_first_load);
	RTSX_DEBUGP("sw_bypass_sd = %d\n", sw_bypass_sd);

	if (sw_bypass_sd) {
		u8 cd_toggle_mask = 0;

		RTSX_READ_REG(chip, TLPTISTAT, &tmp);
		cd_toggle_mask = 0x08;

		if (tmp & cd_toggle_mask) {
			/* Disable sdio_bus_auto_switch */
			if (CHECK_PID(chip, 0x5288))
				RTSX_WRITE_REG(chip, 0xFE5A, 0x08, 0x00);
			else if (CHECK_PID(chip, 0x5208))
				RTSX_WRITE_REG(chip, 0xFE70, 0x80, 0x00);

			RTSX_WRITE_REG(chip, TLPTISTAT, 0xFF, tmp);

			chip->need_reset |= SD_CARD;
		} else {
			RTSX_DEBUGP("Chip inserted with SDIO!\n");

			if (chip->asic_code) {
				retval = sd_pull_ctl_enable(chip);
				if (retval != STATUS_SUCCESS)
					TRACE_RET(chip, STATUS_FAIL);
			} else {
				RTSX_WRITE_REG(chip, FPGA_PULL_CTL,
					FPGA_SD_PULL_CTL_BIT | 0x20, 0);
			}
			retval = card_share_mode(chip, SD_CARD);
			if (retval != STATUS_SUCCESS)
				TRACE_RET(chip, STATUS_FAIL);

			/* Enable sdio_bus_auto_switch */
			if (CHECK_PID(chip, 0x5288))
				RTSX_WRITE_REG(chip, 0xFE5A, 0x08, 0x08);
			else if (CHECK_PID(chip, 0x5208))
				RTSX_WRITE_REG(chip, 0xFE70, 0x80, 0x80);

			chip->chip_insert_with_sdio = 1;
			chip->sd_io = 1;
		}
	} else {
		RTSX_WRITE_REG(chip, TLPTISTAT, 0x08, 0x08);

		chip->need_reset |= SD_CARD;
	}

	return STATUS_SUCCESS;
}
예제 #15
0
파일: rtsx_card.c 프로젝트: 7799/linux
int switch_ssc_clock(struct rtsx_chip *chip, int clk)
{
	int retval;
	u8 N = (u8)(clk - 2), min_N, max_N;
	u8 mcu_cnt, div, max_div, ssc_depth, ssc_depth_mask;
	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;

	RTSX_DEBUGP("Switch SSC clock to %dMHz (cur_clk = %d)\n",
			clk, chip->cur_clk);

	if ((clk <= 2) || (N > max_N))
		TRACE_RET(chip, STATUS_FAIL);

	mcu_cnt = (u8)(125/clk + 3);
	if (mcu_cnt > 7)
		mcu_cnt = 7;

	div = CLK_DIV_1;
	while ((N < min_N) && (div < max_div)) {
		N = (N + 2) * 2 - 2;
		div++;
	}
	RTSX_DEBUGP("N = %d, div = %d\n", N, div);

	if (chip->ssc_en) {
		ssc_depth = 0x01;
		N -= 2;
	} else {
		ssc_depth = 0;
	}

	ssc_depth_mask = 0x03;

	RTSX_DEBUGP("ssc_depth = %d\n", ssc_depth);

	rtsx_init_cmd(chip);
	rtsx_add_cmd(chip, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
	rtsx_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0xFF, (div << 4) | mcu_cnt);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL2, ssc_depth_mask, ssc_depth);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
	rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
	if (sd_vpclk_phase_reset) {
		rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
			PHASE_NOT_RESET, 0);
		rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
			PHASE_NOT_RESET, PHASE_NOT_RESET);
	}

	retval = rtsx_send_cmd(chip, 0, WAIT_TIME);
	if (retval < 0)
		TRACE_RET(chip, STATUS_ERROR);

	udelay(10);
	RTSX_WRITE_REG(chip, CLK_CTL, CLK_LOW_FREQ, 0);

	chip->cur_clk = clk;

	return STATUS_SUCCESS;
}