Exemple #1
0
static void hi_mci_cmd_done(struct himci_host *host, unsigned int stat)
{
	unsigned int i;
	struct mmc_command *cmd = host->cmd;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(cmd);

	host->cmd = NULL;

	for (i = 0; i < 4; i++) {
		if (mmc_resp_type(cmd) == MMC_RSP_R2)
			cmd->resp[i] = himci_readl(host->base +
					MCI_RESP3 - i * 0x4);
		else
			cmd->resp[i] = himci_readl(host->base +
					MCI_RESP0 + i * 0x4);
	}

	if (stat & RTO_INT_STATUS) {
		cmd->error = -ETIMEDOUT;
		himci_trace(3, "irq cmd status stat = 0x%x is timeout error!",
				stat);
	} else if (stat & (RCRC_INT_STATUS | RE_INT_STATUS)) {
		cmd->error = -EILSEQ;
		himci_trace(3, "irq cmd status stat = 0x%x is response error!",
				stat);
	}
}
Exemple #2
0
static int hi_mci_wait_card_complete(struct himci_host *host,
		struct mmc_data *data)
{
	unsigned int card_retry_count = 0;
	unsigned long card_jiffies_timeout;
	unsigned int card_status_reg = 0;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(data);

	card_jiffies_timeout = jiffies + request_timeout;
	while (1) {
		if (!time_before(jiffies, card_jiffies_timeout)) {
			data->error = -ETIMEDOUT;
			himci_trace(3, "wait card ready complete is timeout!");
			return -1;
		}

		do {
			card_status_reg = readl(host->base + MCI_STATUS);
			if (!(card_status_reg & DATA_BUSY)) {
				himci_trace(2, "end");
				return 0;
			}
			card_retry_count++;
		} while (card_retry_count < retry_count);
		schedule();
	}
}
Exemple #3
0
static void hi_mci_data_done(struct himci_host *host, unsigned int stat)
{
	struct mmc_data *data = host->data;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(data);

	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir);

	if (stat & (HTO_INT_STATUS | DRTO_INT_STATUS)) {
		data->error = -ETIMEDOUT;
		himci_trace(3, "irq data status stat = 0x%x is timeout error!",
				stat);
	} else if (stat & (EBE_INT_STATUS | SBE_INT_STATUS | FRUN_INT_STATUS
				| DCRC_INT_STATUS)) {
		data->error = -EILSEQ;
		himci_trace(3, "irq data status stat = 0x%x is data error!",
				stat);
	}

	if (!data->error)
		data->bytes_xfered = data->blocks * data->blksz;
	else
		data->bytes_xfered = 0;

	host->data = NULL;
}
Exemple #4
0
static void hi_mci_finish_request(struct himci_host *host,
		struct mmc_request *mrq)
{
	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(mrq);

	host->mrq = NULL;
	host->cmd = NULL;
	host->data = NULL;
	mmc_request_done(host->mmc, mrq);
}
Exemple #5
0
static void mshci_hi_sdio_set_power(struct platform_device *dev, int val)
{
	struct mshci_host *host = platform_get_drvdata(dev);
	struct himci_host * hi_host = (struct himci_host *)(host->private);
	/*int ret = -1;*/
	u32 loop_count = 1000; /* wait 10S */
	u32 i = 0;

	himci_assert(host);
	himci_assert(hi_host);

	for (i = 0; i < loop_count; i++) {
		if (MMC_HOST_BUSY == host->working || host->mrq) {
			msleep(10);
		} else {
			break;
		}
	}
#if 0
	if (val) {
		printk("%s:val=%d, set io to normal mode\n", __func__, val);
		host->mmc->ios.power_mode = MMC_POWER_UP;
		host->mmc->ios.timing = MMC_TIMING_LEGACY;
		host->mmc->ios.bus_width = MMC_BUS_WIDTH_1;
		host->mmc->ios.clock = 0;
		host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);

		ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, NORMAL);
		if (ret) {
			himci_error("failed to blockmux_set");
		}
		msleep(10);

		host->mmc->ios.power_mode = MMC_POWER_ON;
		host->mmc->ios.clock = 400000;
		host->mmc->ops->set_ios(host->mmc, &host->mmc->ios);

		//to do w00215368
		//blockmux_set(hi_host->piomux_block, hi_host->pblock_config, NORMAL);
	} else {
		printk("%s:val=%d, set io to lowpower mode\n", __func__, val);
		host->mmc->ios.clock = 0;
		host->mmc->ios.power_mode = MMC_POWER_OFF;
		host->mmc->ios.bus_width = MMC_BUS_WIDTH_1;
		host->mmc->ios.timing = MMC_TIMING_LEGACY;

		ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, LOWPOWER);
		if (ret) {
			himci_error("failed to blockmux_set");
		}
	}
#endif
}
Exemple #6
0
static int hi_mci_wait_data_complete(struct himci_host *host)
{
	unsigned int data_irq_reg = 0;
	struct mmc_data *data = host->data;
	long time = request_timeout;
	unsigned long flags;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(data);

	time = wait_event_timeout(host->intr_wait,
		test_bit(HIMCI_PEND_DTO_b, &host->pending_events),
		time);

	if ((time <= 0)
		&& (!test_bit(HIMCI_PEND_DTO_b, &host->pending_events))) {
		data->error = -ETIMEDOUT;
		spin_lock_irqsave(&host->lock, flags);
		data_irq_reg = himci_readl(host->base + MCI_RINTSTS);
		himci_writel(data_irq_reg, host->base + MCI_RINTSTS);
		spin_unlock_irqrestore(&host->lock, flags);
		himci_trace(3, "wait data request complete is timeout! 0x%08X",
			data_irq_reg);
		hi_mci_idma_stop(host);
		hi_mci_data_done(host, data_irq_reg);
		return -1;
	}

	spin_lock_irqsave(&host->lock, flags);
	data_irq_reg = himci_readl(host->base + MCI_RINTSTS);
	himci_writel((HTO_INT_STATUS | DRTO_INT_STATUS | EBE_INT_STATUS
		| SBE_INT_STATUS | FRUN_INT_STATUS | DCRC_INT_STATUS),
		host->base + MCI_RINTSTS);

	host->pending_events &= ~HIMCI_PEND_DTO_m;
	spin_unlock_irqrestore(&host->lock, flags);

	hi_mci_idma_stop(host);
	hi_mci_data_done(host, data_irq_reg);

	return 0;
}
Exemple #7
0
static int hi_mci_get_ro(struct mmc_host *mmc)
{
	unsigned ret;
	struct himci_host *host = mmc_priv(mmc);

	himci_trace(2, "begin");
	himci_assert(mmc);

	ret = hi_mci_ctrl_card_readonly(host);

	return ret;
}
Exemple #8
0
static void hi_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
	struct himci_host *host = mmc_priv(mmc);
	unsigned int tmp_reg;

	himci_trace(2, "begin");
	himci_assert(mmc);
	himci_assert(ios);
	himci_assert(host);

	himci_trace(3, "ios->power_mode = %d ", ios->power_mode);
	switch (ios->power_mode) {
	case MMC_POWER_OFF:
		hi_mci_ctrl_power(host, POWER_OFF);
		break;
	case MMC_POWER_UP:
	case MMC_POWER_ON:
		hi_mci_ctrl_power(host, POWER_ON);
		break;
	}
	himci_trace(3, "ios->clock = %d ", ios->clock);
	if (ios->clock) {
		hi_mci_control_cclk(host, DISABLE);
		hi_mci_set_cclk(host, ios->clock);
		hi_mci_control_cclk(host, ENABLE);
	} else
		hi_mci_control_cclk(host, DISABLE);

	/* set bus_width */
	himci_trace(3, "ios->bus_width = %d ", ios->bus_width);
	if (ios->bus_width == MMC_BUS_WIDTH_4) {
		tmp_reg = himci_readl(host->base + MCI_CTYPE);
		tmp_reg |= CARD_WIDTH;
		himci_writel(tmp_reg, host->base + MCI_CTYPE);
	} else {
		tmp_reg = himci_readl(host->base + MCI_CTYPE);
		tmp_reg &= ~CARD_WIDTH;
		himci_writel(tmp_reg, host->base + MCI_CTYPE);
	}
}
Exemple #9
0
static void hi_mci_set_cclk(struct himci_host *host, unsigned int cclk)
{
	unsigned int reg_value;
	union cmd_arg_s clk_cmd;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(cclk);

	/*
	 * set card clk divider value,
	 * clk_divider = Fmmcclk/(Fmmc_cclk * 2)
	 */
	reg_value = CONFIG_MMC_CLK / (cclk * 2);
	himci_writel(reg_value, host->base + MCI_CLKDIV);

	clk_cmd.cmd_arg = himci_readl(host->base + MCI_CMD);
	clk_cmd.bits.start_cmd = 1;
	clk_cmd.bits.update_clk_reg_only = 1;
	himci_writel(clk_cmd.cmd_arg, host->base + MCI_CMD);
	if (hi_mci_wait_cmd(host) != 0)
		himci_trace(3, "set card clk divider is failed!");
}
Exemple #10
0
static int hi_mci_wait_cmd_complete(struct himci_host *host)
{
	unsigned int cmd_retry_count = 0;
	unsigned long cmd_jiffies_timeout;
	unsigned int cmd_irq_reg = 0;
	struct mmc_command *cmd = host->cmd;
	unsigned long flags;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(cmd);

	cmd_jiffies_timeout = jiffies + request_timeout;
	while (1) {
		if (!time_before(jiffies, cmd_jiffies_timeout)) {
			cmd->error = -ETIMEDOUT;
			himci_trace(3, "wait cmd request complete is timeout!");
			return -1;
		}

		do {
			spin_lock_irqsave(&host->lock, flags);
			cmd_irq_reg = readl(host->base + MCI_RINTSTS);
			if (cmd_irq_reg & CD_INT_STATUS) {
				himci_writel((CD_INT_STATUS | RTO_INT_STATUS
					| RCRC_INT_STATUS | RE_INT_STATUS),
					host->base + MCI_RINTSTS);
				spin_unlock_irqrestore(&host->lock, flags);
				hi_mci_cmd_done(host, cmd_irq_reg);
				return 0;
			}
			spin_unlock_irqrestore(&host->lock, flags);
			cmd_retry_count++;
		} while (cmd_retry_count < retry_count);
		schedule();
	}
}
Exemple #11
0
static void hi_mci_init_card(struct himci_host *host)
{
	unsigned int tmp_reg;
	unsigned long flags;

	himci_trace(2, "begin");
	himci_assert(host);

	hi_mci_sys_reset(host);

	hi_mci_ctrl_power(host, POWER_OFF);
	udelay(500);
	/* card power on */
	hi_mci_ctrl_power(host, POWER_ON);
	udelay(200);

	hi_mci_sys_undo_reset(host);

	/* clear MMC host intr */
	himci_writel(ALL_INT_CLR, host->base + MCI_RINTSTS);

	spin_lock_irqsave(&host->lock, flags);
	host->pending_events = 0;
	spin_unlock_irqrestore(&host->lock, flags);

	/* MASK MMC host intr */
	tmp_reg = himci_readl(host->base + MCI_INTMASK);
	tmp_reg &= ~ALL_INT_MASK;
	tmp_reg |= DTO_INT_MASK;
	himci_writel(tmp_reg, host->base + MCI_INTMASK);

	/* enable inner DMA mode and close intr of MMC host controler */
	tmp_reg = himci_readl(host->base + MCI_CTRL);
	tmp_reg &= ~INTR_EN;
	tmp_reg |= USE_INTERNAL_DMA | INTR_EN;
	himci_writel(tmp_reg, host->base + MCI_CTRL);

	/* set timeout param */
	himci_writel(DATA_TIMEOUT | RESPONSE_TIMEOUT, host->base + MCI_TIMEOUT);

	/* set FIFO param */
	tmp_reg = 0;
	tmp_reg |= BURST_SIZE | RX_WMARK | TX_WMARK;
	himci_writel(tmp_reg, host->base + MCI_FIFOTH);

}
Exemple #12
0
static int hi_mci_wait_cmd(struct himci_host *host)
{
	int wait_retry_count = 0;
	unsigned int reg_data = 0;
	unsigned long flags;

	himci_trace(2, "begin");
	himci_assert(host);

	while (1) {
		/*
		 * Check if CMD::start_cmd bit is clear.
		 * start_cmd = 0 means MMC Host controller has loaded registers
		 * and next command can be loaded in.
		 */
		reg_data = readl(host->base + MCI_CMD);
		if ((reg_data & START_CMD) == 0)
			return 0;

		/* Check if Raw_Intr_Status::HLE bit is set. */
		spin_lock_irqsave(&host->lock, flags);
		reg_data = readl(host->base + MCI_RINTSTS);
		if (reg_data & HLE_INT_STATUS) {
			reg_data |= HLE_INT_STATUS;
			himci_writel(reg_data, host->base + MCI_RINTSTS);
			spin_unlock_irqrestore(&host->lock, flags);

			himci_trace(3, "Other CMD is running,"
					"please operate cmd again!");
			return 1;
		}

		himci_writel(reg_data, host->base + MCI_RINTSTS);
		spin_unlock_irqrestore(&host->lock, flags);
		udelay(100);

		/* Check if number of retries for this are over. */
		wait_retry_count++;
		if (wait_retry_count >= retry_count) {
			himci_trace(3, "wait cmd complete is timeout!");
			return -1;
		}
	}
}
Exemple #13
0
static int hi_mci_suspend(struct platform_device *dev, pm_message_t state)
{
	struct mmc_host *mmc = platform_get_drvdata(dev);
	struct himci_host *host;
	int ret = 0;

	himci_trace(2, "begin");
	himci_assert(dev);

	if (mmc) {
		ret = mmc_suspend_host(mmc);

		host = mmc_priv(mmc);
		hi_mci_sys_ctrl_suspend(host);
	}

	himci_trace(2, "end");

	return ret;
}
Exemple #14
0
static void hi_mci_control_cclk(struct himci_host *host, unsigned int flag)
{
	unsigned int reg;
	union cmd_arg_s cmd_reg;

	himci_trace(2, "begin");
	himci_assert(host);

	reg = himci_readl(host->base + MCI_CLKENA);
	if (flag == ENABLE)
		reg |= CCLK_ENABLE;
	else
		reg &= 0xffff0000;
	himci_writel(reg, host->base + MCI_CLKENA);

	cmd_reg.cmd_arg = himci_readl(host->base + MCI_CMD);
	cmd_reg.bits.start_cmd = 1;
	cmd_reg.bits.update_clk_reg_only = 1;
	himci_writel(cmd_reg.cmd_arg, host->base + MCI_CMD);

	if (hi_mci_wait_cmd(host) != 0)
		himci_trace(3, "disable or enable clk is timeout!");
}
Exemple #15
0
static int hi_mci_resume(struct platform_device *dev)
{
	struct mmc_host *mmc = platform_get_drvdata(dev);
	struct himci_host *host;
	int ret = 0;

	himci_trace(2, "begin");
	himci_assert(dev);

	if (mmc) {
		host = mmc_priv(mmc);
		/* enable mmc clk */
		hi_mci_sys_ctrl_init(host);
		/* enable card */
		hi_mci_init_card(host);

		ret = mmc_resume_host(mmc);
	}

	himci_trace(2, "end");

	return ret;
}
Exemple #16
0
static int __devexit hi_mci_remove(struct platform_device *pdev)
{
	struct mmc_host *mmc = platform_get_drvdata(pdev);

	himci_trace(2, "begin");
	himci_assert(pdev);

	platform_set_drvdata(pdev, NULL);

	if (mmc) {
		struct himci_host *host = mmc_priv(mmc);

		free_irq(host->irq, host);
		del_timer_sync(&host->timer);
		mmc_remove_host(mmc);
		hi_mci_ctrl_power(host, POWER_OFF);
		hi_mci_control_cclk(host, DISABLE);
		iounmap(host->base);
		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->dma_vaddr,
				host->dma_paddr);
		mmc_free_host(mmc);
	}
	return 0;
}
Exemple #17
0
static void hi_mci_detect_card(unsigned long arg)
{
	struct himci_host *host = (struct himci_host *)arg;
	unsigned int i, curr_status, status[3], detect_retry_count = 0;

	himci_assert(host);

	while (1) {
		for (i = 0; i < 3; i++) {
			status[i] = hi_mci_sys_card_detect(host);
			udelay(10);
		}
		if ((status[0] == status[1]) && (status[0] == status[2]))
			break;

		detect_retry_count++;
		if (detect_retry_count >= retry_count) {
			himci_error("this is a dithering,card detect error!");
			goto err;
		}
	}
	curr_status = status[0];
	if (curr_status != host->card_status) {
		himci_trace(2, "begin card_status = %d\n", host->card_status);
		host->card_status = curr_status;
		if (curr_status != CARD_UNPLUGED) {
			hi_mci_init_card(host);
			printk(KERN_INFO "card connected!\n");
		} else
			printk(KERN_INFO "card disconnected!\n");

		mmc_detect_change(host->mmc, 0);
	}
err:
	mod_timer(&host->timer, jiffies + detect_time);
}
Exemple #18
0
static int hi_mci_setup_data(struct himci_host *host, struct mmc_data *data)
{
	unsigned int sg_phyaddr, sg_length;
	unsigned int i, ret = 0;
	unsigned int data_size;
	unsigned int max_des, des_cnt;
	struct himci_des *des;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(data);

	host->data = data;

	if (data->flags & MMC_DATA_READ)
		host->dma_dir = DMA_FROM_DEVICE;
	else
		host->dma_dir = DMA_TO_DEVICE;

	host->dma_sg = data->sg;
	host->dma_sg_num = dma_map_sg(mmc_dev(host->mmc),
			data->sg, data->sg_len, host->dma_dir);
	himci_assert(host->dma_sg_num);
	himci_trace(2, "host->dma_sg_num is %d\n", host->dma_sg_num);

	data_size = data->blksz * data->blocks;
	if (data_size > (DMA_BUFFER * MAX_DMA_DES)) {
		himci_error("mci request data_size is too big!\n");
		ret = -1;
		goto out;
	}

	himci_trace(2, "host->dma_paddr is 0x%08X,host->dma_vaddr is 0x%08X\n",
			(unsigned int)host->dma_paddr,
			(unsigned int)host->dma_vaddr);

	max_des = (PAGE_SIZE/sizeof(struct himci_des));
	des = (struct himci_des *)host->dma_vaddr;
	des_cnt = 0;

	for (i = 0; i < host->dma_sg_num; i++) {
		sg_length = sg_dma_len(&data->sg[i]);
		sg_phyaddr = sg_dma_address(&data->sg[i]);
		himci_trace(2, "sg[%d] sg_length is 0x%08X, "
				"sg_phyaddr is 0x%08X\n",
				i, (unsigned int)sg_length,
				(unsigned int)sg_phyaddr);
		while (sg_length) {
			des[des_cnt].idmac_des_ctrl = DMA_DES_OWN
				| DMA_DES_NEXT_DES;
			des[des_cnt].idmac_des_buf_addr = sg_phyaddr;
			/* idmac_des_next_addr is paddr for dma */
			des[des_cnt].idmac_des_next_addr = host->dma_paddr
				+ (des_cnt + 1) * sizeof(struct himci_des);

			if (sg_length >= 0x1F00) {
				des[des_cnt].idmac_des_buf_size = 0x1F00;
				sg_length -= 0x1F00;
				sg_phyaddr += 0x1F00;
			} else {
				/* FIXME:data alignment */
				des[des_cnt].idmac_des_buf_size = sg_length;
				sg_length = 0;
			}

			himci_trace(2, "des[%d] vaddr  is 0x%08X", i,
					(unsigned int)&des[i]);
			himci_trace(2, "des[%d].idmac_des_ctrl is 0x%08X",
			       i, (unsigned int)des[i].idmac_des_ctrl);
			himci_trace(2, "des[%d].idmac_des_buf_size is 0x%08X",
				i, (unsigned int)des[i].idmac_des_buf_size);
			himci_trace(2, "des[%d].idmac_des_buf_addr 0x%08X",
				i, (unsigned int)des[i].idmac_des_buf_addr);
			himci_trace(2, "des[%d].idmac_des_next_addr is 0x%08X",
				i, (unsigned int)des[i].idmac_des_next_addr);
			des_cnt++;
		}

		himci_assert(des_cnt < max_des);
	}
	des[0].idmac_des_ctrl |= DMA_DES_FIRST_DES;
	des[des_cnt - 1].idmac_des_ctrl |= DMA_DES_LAST_DES;
	des[des_cnt - 1].idmac_des_next_addr = 0;
out:
	return ret;
}
Exemple #19
0
static void hi_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
	struct himci_host *host = mmc_priv(mmc);
	int blk_size, tmp_reg, fifo_count = 0;
	int ret = 0;
	unsigned long flags;

	himci_trace(2, "begin");
	himci_assert(mmc);
	himci_assert(mrq);
	himci_assert(host);

	host->mrq = mrq;

	if (host->card_status == CARD_UNPLUGED) {
		mrq->cmd->error = -ENODEV;
		goto  request_end;
	}

	/* prepare data */
	if (mrq->data) {
		ret = hi_mci_setup_data(host, mrq->data);
		if (ret) {
			mrq->data->error = ret;
			himci_trace(3, "data setup is error!");
			goto request_end;
		}

		blk_size = mrq->data->blksz * mrq->data->blocks;
		himci_writel(blk_size, host->base + MCI_BYTCNT);
		himci_writel(mrq->data->blksz, host->base + MCI_BLKSIZ);

		tmp_reg = himci_readl(host->base + MCI_CTRL);
		tmp_reg |= FIFO_RESET;
		himci_writel(tmp_reg, host->base + MCI_CTRL);

		do {
			tmp_reg = himci_readl(host->base + MCI_CTRL);
			fifo_count++;
			if (fifo_count >= retry_count) {
				printk(KERN_INFO "fifo reset is timeout!");
				return;
			}
		} while (tmp_reg&FIFO_RESET);

		/* start DMA */
		hi_mci_idma_start(host);
	} else {
		himci_writel(0, host->base + MCI_BYTCNT);
		himci_writel(0, host->base + MCI_BLKSIZ);
	}

	/* send command */
	ret = hi_mci_exec_cmd(host, mrq->cmd, mrq->data);
	if (ret) {
		mrq->cmd->error = ret;
		himci_trace(3, "cmd execute is error!");
		goto request_end;
	}

	/* wait command send complete */
	ret = hi_mci_wait_cmd_complete(host);
	if (ret)
		goto request_end;

	if (!(mrq->data && !mrq->cmd->error))
		goto request_end;

	/* start data transfer */
	if (mrq->data) {
		/* wait data transfer complete */
		ret = hi_mci_wait_data_complete(host);
		if (ret)
			goto request_end;

		if (mrq->stop) {
			/* send stop command */
			ret = hi_mci_exec_cmd(host, host->mrq->stop,
					host->data);
			if (ret) {
				mrq->cmd->error = ret;
				goto request_end;
			}
			ret = hi_mci_wait_cmd_complete(host);
			if (ret)
				goto request_end;

			if (mrq->data->flags & MMC_DATA_WRITE) {
				/* wait card write data complete */
				hi_mci_wait_card_complete(host, mrq->data);
			}
		}
	}
request_end:
	/* clear MMC host intr */
	spin_lock_irqsave(&host->lock, flags);
	himci_writel(ALL_INT_CLR, host->base + MCI_RINTSTS);
	spin_unlock_irqrestore(&host->lock, flags);

	hi_mci_finish_request(host, mrq);
}
Exemple #20
0
void mshci_hi_set_ios(struct mshci_host *ms_host, struct mmc_ios *ios)
{
	struct himci_host * hi_host = (struct himci_host *)(ms_host->private);
	int ret = -1;

	hi_host_trace(HIMCI_TRACE_GEN_API, "++");

	himci_assert(ios);
	himci_assert(hi_host);

	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->power_mode = %d ", ios->power_mode);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->clock = %d ", ios->clock);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->bus_width = %d ", ios->bus_width);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->timing = %d ", ios->timing);

	/* process power */
	if (hi_host->old_power_mode != ios->power_mode) {
		switch (ios->power_mode) {
		case MMC_POWER_OFF:
		    hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "set io to lowpower");
		    if (hi_host->vcc) {
				regulator_disable(hi_host->vcc);
		    }
			if (hi_host->signal_vcc) {
				regulator_disable(hi_host->signal_vcc);
				regulator_set_mode(hi_host->signal_vcc, REGULATOR_MODE_IDLE);
		    }

		    ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, LOWPOWER);
		    if (ret) {
				himci_error("failed to blockmux_set");
		    }

			break;
		case MMC_POWER_UP:
		    hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "set io to normal");

		    ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, NORMAL);
		    if (ret) {
				himci_error("failed to blockmux_set");
		    }

		    if (hi_host->vcc) {
				ret = regulator_set_voltage(hi_host->vcc, 2850000, 2850000);
				if (ret != 0) {
					himci_error("failed to regulator_set_voltage");
				}

				ret = regulator_enable(hi_host->vcc);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
		    }
			if (hi_host->signal_vcc) {
				ret = regulator_set_voltage(hi_host->signal_vcc, 2600000, 2600000);
				if (ret != 0) {
					himci_error("failed to regulator_set_voltage");
				}
				regulator_set_mode(hi_host->signal_vcc, REGULATOR_MODE_NORMAL);
				ret = regulator_enable(hi_host->signal_vcc);
				if (ret) {
					himci_error("failed to regulator_enable");
				}

		    }
			break;
		case MMC_POWER_ON:
			break;
		default:
			himci_error("unknown power supply mode");
			break;
		}
		hi_host->old_power_mode = ios->power_mode;
	}

	/* process timing */
	if (hi_host->old_timing != ios->timing) {

		hi_host->old_timing = ios->timing;

		if ( get_chipid() == DI_CHIP_ID ) {
			mshci_hi_update_timing(ms_host, 0);

			switch (ios->timing) {
			case MMC_TIMING_LEGACY:
				if (hi_host->pdev->id == 1) {
					/* 2 division, 40M */
					writel((0x1<<6) | (0x7<<22),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 40*1000*1000;
					ms_host->clock++;
				} else if (hi_host->pdev->id == 0) {
					/* 2 division, 40M */
					writel((0x0<<5) | (0x1<<21),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 40*1000*1000;
					ms_host->clock++;
				}
				hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "MMC_TIMING_LEGACY");
				break;
			case MMC_TIMING_UHS_DDR50:
				if (hi_host->pdev->id == 1) {
					/* 1 division, 80M */
					writel((0x0<<6) | (0x7<<22),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 80*1000*1000;
					ms_host->clock++;
				} else {
#if 0
					/*
					 * m53980:
					 * debug purpose.
					 * change clock via sctrl configuration
					 */
					printk("clk div a:0x%x\n", readl(IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2));
					writel((0x7)|(0xF<<16), IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					printk("clk div b:0x%x\n", readl(IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2));
#endif
				}
				hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "MMC_TIMING_UHS_DDR50");
				break;
			case MMC_TIMING_UHS_SDR50:
				if (hi_host->pdev->id == 0) {
					writel((0x1<<5) | (0x1<<21),
						IO_ADDRESS(REG_BASE_SCTRL) + REG_SCCLKDIV2);
					ms_host->max_clk = 80*1000*1000;
					ms_host->clock++;
				}
				hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "MMC_TIMING_UHS_SDR50");
				break;
			default:
				break;
			}
		} else {
			ret = clk_set_rate(hi_host->pclk,hi_host->init_tuning_config[0 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM]);
			if (ret) {
				himci_error("failed to clk_set_rate");
			}
			hi_host->tuning_init_sample =
					(hi_host->init_tuning_config[3 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM] +
					hi_host->init_tuning_config[4 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM]) / 2;
			mshci_hi_set_timing(hi_host,
				hi_host->tuning_init_sample,
				hi_host->init_tuning_config[2 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM],
				hi_host->init_tuning_config[1 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM]);

			ms_host->max_clk = hi_host->init_tuning_config[5 + (ios->timing + 1) * TUNING_INIT_CONFIG_NUM];

			ms_host->clock++;
		}
	}

	hi_host_trace(HIMCI_TRACE_GEN_API, "--");
}
Exemple #21
0
static int __devinit hi_mci_probe(struct platform_device *pdev)
{
	struct mshci_host *ms_host = NULL;
	struct himci_host *hi_host = NULL;
	struct hisik3_mmc_platform_data *plat = NULL;
	struct resource *memres = NULL;


	int ret = 0, irq;
	int err;
	bool RetVal = 0;
	unsigned long flags;
	unsigned int sdcard_frequency = 0;



    #ifdef CONFIG_MACH_HI6620OEM
    if(1 == pdev->id)
    {
        raw_mmc_turn_on();
    }
    #endif

	himci_trace(HIMCI_TRACE_GEN_API, "++");

	himci_assert(pdev);

	plat = pdev->dev.platform_data;

	himci_trace(HIMCI_TRACE_SIGNIFICANT, "id:%d", pdev->id);

    /*通过读取硬件配置项,或者sdcard时钟配置,只需要SD卡流程走,走一遍*/
    #ifdef CONFIG_MACH_HI6620OEM

    if(1 == pdev->id)
    {
        RetVal = get_hw_config_int("sd_card/sdcard_frequency", &sdcard_frequency, NULL);

    	printk("hsad: sd_card/sdcard_frequency = %d, RetVal = %d\n", sdcard_frequency, RetVal);

        /*读取失败,配置默认值*/
    	if (RetVal == false) {
            printk(KERN_ERR "get board type failed.\n");
            g_sdcard_frequency = 90;
    	}

        /*如果获取配置值异常,则配置默认值*/
    	if ((sdcard_frequency != 100)&&(sdcard_frequency != 90)) {
            printk(KERN_ERR "sdcard_frequency %x is error.\n",sdcard_frequency);
            g_sdcard_frequency = 90;
    	}

    	g_sdcard_frequency = sdcard_frequency;
	}

    #endif

	/* 获取自己定义的数据 */
	if (!plat) {
		himci_error("Platform data not available");
		return -ENOENT;
	}
	if(0 == pdev->id)
	{
	     sema_init(&sem_to_rfile_sync_req,0);
	}

    /*创建硬件信号量IPC_SEM_EMMC*/
    if (0 == pdev->id) {
        mutex_lock(&emmc_mutex);
        emmc_sem_flag = 1;
        mutex_unlock(&emmc_mutex);
    }

	irq = platform_get_irq(pdev, 0);
	memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	if ((!irq) || (!memres)) {
		himci_error("resource error");
		ret = -ENOENT;
        goto err_resource_get;
	}

	himci_trace(HIMCI_TRACE_SIGNIFICANT, "irq:%d,start:0x%x,size:0x%x", irq, \
										memres->start, resource_size(memres));

	ms_host = mshci_alloc_host(&pdev->dev, sizeof(struct himci_host));
	if (IS_ERR(ms_host)) {
		himci_error("mshci_alloc_host() failed\n");
		ret = PTR_ERR(ms_host);
        goto err_resource_get;
	}

	hi_host = mshci_priv(ms_host);
	hi_host->ms_host = ms_host;
	hi_host->pdev = pdev;
	hi_host->dev = &pdev->dev;
	hi_host->plat = plat;


	platform_set_drvdata(pdev, ms_host);

	/* MMC IP rstdis */
	if (plat->rstdis_mmc){
        ret = plat->rstdis_mmc();
        if ( ret < 0 ){
	        goto err_resource_get;
	    }
	}

    /* set emmc clk */

	hi_host->pclk = clk_get(&pdev->dev, plat->clk_mmc_low); /* work clk */

	if (IS_ERR(hi_host->pclk)) {
		himci_error("clk_get clk_mmc_low fail!");
		ret = PTR_ERR(hi_host->pclk);
		goto err_io_clk;
	}
	hi_host->clk_mmc_high= clk_get(&pdev->dev, plat->clk_mmc_high); /* highclk used for tuning */

    if (IS_ERR(hi_host->clk_mmc_high)) {
		himci_error("clk_get clk_mmc_high fail!");
		ret = PTR_ERR(hi_host->clk_mmc_high);
		goto err_io_clk;
	}

    ms_host->pclk = NULL;
    ms_host->clk_ref_counter = CLK_DISABLED;
    ms_host->clk_mmc_high = NULL;

	ms_host->pclk = hi_host->pclk;
	ms_host->clk_mmc_high = hi_host->clk_mmc_high;

	if (ret) {
	    himci_error("failed to clk_set_rate");
	}

    if(ms_host->clk_ref_counter == CLK_DISABLED){
        ret = clk_enable(hi_host->pclk);
        ms_host->clk_ref_counter = CLK_ENABLED;
        if (ret) {
            himci_error("clk_enable failed");
            ret = -ENOENT;
            goto err_clk_ops;
        }
    }



	ms_host->ioaddr = ioremap_nocache(memres->start, resource_size(memres));
	if (!ms_host->ioaddr) {
		himci_error("ioremap_nocache failed");
		ret = -ENXIO;
		goto err_req_regs;
	}

	ms_host->hw_name = "hisi_hi6620_mmc";
	ms_host->hw_mmc_id = hi_host->pdev->id;
	ms_host->ops = &mshci_hi_ops;
	ms_host->quirks = 0;
	ms_host->irq = irq;

	/* Setup quirks for the controller */

	if (plat->quirks) {
		ms_host->quirks |= plat->quirks;
	}

	if (plat->caps & MMC_CAP_CLOCK_GATING) {
		/* there is no reason not to use interral clock gating */
		ms_host->mmc->caps |= plat->caps;
		ms_host->mmc->caps |= MMC_CAP_CLOCK_GATING;
		ms_host->clock_gate = 1;
    } else {
		ms_host->mmc->caps |= plat->caps;
		ms_host->clock_gate = 0;
	}

	ms_host->mmc->caps2 = plat->caps2;

	/* sandisk card need clock longer than spec ask */
	/* sdcard also disable ip clock gate c00261379*/
	if (ms_host->hw_mmc_id == 0 || ms_host->hw_mmc_id == 1)
		ms_host->clock_gate = 0;

	if (plat->ocr_mask)
		ms_host->mmc->ocr_avail |= plat->ocr_mask;


    #ifdef CONFIG_MACH_HI6620OEM
    if (plat->iomux_name){
        hi_host->piomux_block = iomux_get_block(plat->iomux_name);
	    hi_host->pblock_config = iomux_get_blockconfig(plat->iomux_name);
    }

    /* todo requlator */
	if (plat->reg_name_ldo) {
		himci_trace(HIMCI_TRACE_SIGNIFICANT, "devname : %s, regname: %s",
					dev_name(hi_host->dev), plat->reg_name_ldo);
		hi_host->vcc_ldo = regulator_get(hi_host->dev, plat->reg_name_ldo);
		if (!IS_ERR(hi_host->vcc_ldo)) {
			/*
			 * Setup a notifier block to update this if another device
			 * causes the voltage to change
			 */
			hi_host->nb.notifier_call = &mshci_hi_disable_voltage;
			ret = regulator_register_notifier(hi_host->vcc_ldo, &hi_host->nb);
			if (ret) {
				dev_err(&pdev->dev,
					"regulator notifier request failed\n");
			}
		} else {
			dev_err(&pdev->dev, "regulator_get() failed\n");
			hi_host->vcc_ldo = NULL;
		}
	}

	if (plat->reg_name_lvs) {
		himci_trace(HIMCI_TRACE_SIGNIFICANT, "devname : %s, regname: %s",
					dev_name(hi_host->dev), plat->reg_name_lvs);
		hi_host->vcc_lvs = regulator_get(hi_host->dev, plat->reg_name_lvs);
		if (!IS_ERR(hi_host->vcc_lvs)) {
			/*
			 * Setup a notifier block to update this if another device
			 * causes the voltage to change
			 */
			hi_host->nb.notifier_call = &mshci_hi_disable_voltage;
			ret = regulator_register_notifier(hi_host->vcc_lvs, &hi_host->nb);
			if (ret) {
				dev_err(&pdev->dev,
					"regulator notifier request failed\n");
			}
		} else {
			dev_err(&pdev->dev, "regulator_get() failed\n");
			hi_host->vcc_lvs = NULL;
		}
	}
	hi_host->ocp_flag = 0;

	if (plat->signal_reg_name) {
		himci_trace(HIMCI_TRACE_SIGNIFICANT, "devname : %s, signal regname: %s",
						dev_name(hi_host->dev), plat->signal_reg_name);
		hi_host->signal_vcc = regulator_get(hi_host->dev, plat->signal_reg_name);
		if (IS_ERR(hi_host->signal_vcc)) {
			dev_err(&pdev->dev, "regulator_get() failed\n");
			hi_host->signal_vcc = NULL;
		}
	}
    #endif

	if( (1 == pdev->id)&&( (ms_host->quirks & MSHCI_QUIRK_CBP_DETECTION) == 0)) {
		ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, LOWPOWER);
		if (ret) {
			himci_error("failed to blockmux_set");
		}
		mshci_sd_lowpower();
		if (hi_host->vcc_lvs){
			ret = regulator_enable(hi_host->vcc_lvs);
			if (ret) {
				himci_error("failed to regulator_enable LDO7");
			}
			ret = regulator_disable(hi_host->vcc_lvs);
			if (ret) {
			himci_error("failed to regulator_disable LDO7");
			}
		}
		udelay(30);
		if (hi_host->signal_vcc){
			ret = regulator_enable(hi_host->signal_vcc);
			if (ret) {
				himci_error("failed to regulator_enable LDO22");
			}
			ret = regulator_disable(hi_host->signal_vcc);
			if (ret) {
				himci_error("failed to regulator_disable LDO22");
			}
		}
	}else {/*for cbp*/
		ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, NORMAL);
		if (ret) {
			himci_error("failed to blockmux_set");
		}

		if (hi_host->vcc_lvs){
			ret = regulator_enable(hi_host->vcc_lvs);
			if (ret) {
				himci_error("failed to regulator_enable LDO7");
			}
		}
		udelay(30);
		if (hi_host->signal_vcc){
			ret = regulator_enable(hi_host->signal_vcc);
			if (ret) {
				himci_error("failed to regulator_enable LDO22");
			}

			ret = regulator_disable(hi_host->signal_vcc);
			if (ret) {
				himci_error("failed to regulator_disable LDO22");
			}
		}
	}

	hi_host->old_sig_voltage = plat->default_signal_voltage;
	hi_host->old_timing = MMC_TIMING_UHS_DDR50;
	hi_host->timing_config = plat->timing_config;
	hi_host->allow_switch_signal_voltage = plat->allow_switch_signal_voltage;
	hi_host->suspend_timing_config = plat->suspend_timing_config;

	if (ms_host->quirks & MSHCI_QUIRK_WLAN_DETECTION) {
		ms_host->flags |= MSHCI_DEVICE_DEAD;
		ms_host->flags |= MMC_PM_KEEP_POWER;
		ms_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
	}

	ret = mshci_add_host(ms_host);
	if (ret) {
		dev_err(&pdev->dev, "mshci_add_host() failed\n");
		goto err_add_host;
	}

	if (ms_host->quirks & MSHCI_QUIRK_WLAN_DETECTION) {
		ms_host->flags |= MSHCI_DEVICE_DEAD;
	        ms_host->flags |= MMC_PM_KEEP_POWER;
	        ms_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
		if (plat->ext_cd_init)
			plat->ext_cd_init(&mshci_hi_notify_change);
		plat->set_power = mshci_hi_sdio_set_power;
	}

	if( (1 == pdev->id)&&( (ms_host->quirks & MSHCI_QUIRK_CBP_DETECTION) != 0)) {
	        ms_host->flags |= MMC_PM_KEEP_POWER;
	        ms_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
	}


	if (ms_host->quirks & MSHCI_QUIRK_EXTERNAL_CARD_DETECTION) {

		err = gpio_request_one(plat->cd_gpio, GPIOF_IN, "ESDHC_CD");
		if (err) {
			dev_warn(mmc_dev(ms_host->mmc),
				"no card-detect pin available!\n");
			goto no_card_detect_pin;
		}
		/*SD_INT_FIX_suspend DTS:2013082704916 modifier: y00241633*/
		err = request_irq(gpio_to_irq(plat->cd_gpio), mshci_hi_card_detect_gpio,
				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
				 mmc_hostname(ms_host->mmc), ms_host);
		if (err) {
			dev_warn(mmc_dev(ms_host->mmc), "request gpio irq error\n");
			goto no_card_detect_irq;
		}

        if ( plat->sw_gpio ){
            /* only sft has this gpio */
		    err = gpio_request_one(plat->sw_gpio, 0, "ESDHC_POWER_SWITCH");
		    if (err) {
			    dev_warn(mmc_dev(ms_host->mmc),
				    "no card-power-switch pin available!\n");
			    goto no_card_power_switch_pin;
		    }

            /*控制I/O口电平 1V8 or 3V3*/
            gpio_direction_output(plat->sw_gpio, 1);
        }

	}

	return 0;

no_card_power_switch_pin:
	plat->sw_gpio = err;
no_card_detect_irq:
	gpio_free(plat->cd_gpio);
no_card_detect_pin:
	plat->cd_gpio = err;
err_add_host:
	iounmap(ms_host->ioaddr);
	ms_host->ioaddr = NULL;
err_req_regs:
	spin_lock_irqsave(&ms_host->lock, flags);
	if(ms_host->clk_ref_counter == CLK_ENABLED){
		clk_disable(hi_host->pclk);
		ms_host->clk_ref_counter = CLK_DISABLED;
	}
	spin_unlock_irqrestore(&ms_host->lock, flags);
err_clk_ops:
    clk_put(hi_host->clk_mmc_high);
	clk_put(hi_host->pclk);
err_io_clk:
	mshci_free_host(ms_host);

err_resource_get:

	return ret;
}
Exemple #22
0
static int mshci_hi_start_signal_voltage_switch(struct mshci_host *ms_host,
				struct mmc_ios *ios)
{
#if 1
	struct himci_host *hi_host = (struct himci_host *)(ms_host->private);




if (ms_host->quirks & MSHCI_QUIRK_EXTERNAL_CARD_DETECTION) {

	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "++");

	himci_assert(ios);
	himci_assert(hi_host);

	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "old_sig_voltage = %d ",
					hi_host->old_sig_voltage);
	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "new_sig_voltage = %d ",
					ios->signal_voltage);
	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "allow_switch_signal_voltage = %d ",
					hi_host->allow_switch_signal_voltage);

	if (hi_host->allow_switch_signal_voltage &&
		(hi_host->old_sig_voltage != ios->signal_voltage)) {
		switch (ios->signal_voltage) {
		case MMC_SIGNAL_VOLTAGE_330:
#ifdef CONFIG_MACH_HI6620OEM

		printk("yuandan 330 \n");

		hi_host->old_sig_voltage = ios->signal_voltage;

		/*
		3.3V IO 设置
 		LDO7   2.85V
 		LDO22  1.425V
 		*/
		if(ms_host->quirks & MSHCI_QUIRK_EXTERNAL_CARD_DETECTION){
			pmussi_reg_write(SOC_SMART_LDO7_REG_ADJ_ADDR(0),SDMMC_3V3_IO_LDO7_SSI_VALUE);
			pmussi_reg_write(SOC_SMART_ENABLE4_ADDR(0),BIT(SOC_SMART_ENABLE4_en_ldo22_int_START));
		}
		sd_ldo22_need_control = 0;

#endif
			break;
		case MMC_SIGNAL_VOLTAGE_180:
#ifdef CONFIG_MACH_HI6620OEM
		printk("yuandan 180 \n");

		hi_host->old_sig_voltage = ios->signal_voltage;

		/*
		1.8V IO 设置
 		LDO7   1.8V
 		LDO22  0V
 		*/
 		if(ms_host->quirks & MSHCI_QUIRK_EXTERNAL_CARD_DETECTION){
 			pmussi_reg_write(SOC_SMART_LDO7_REG_ADJ_ADDR(0),SDMMC_1V8_IO_LDO7_SSI_VALUE);
			udelay(30);
			pmussi_reg_write(SOC_SMART_DR1_ISET_ADDR(0), SDMMC_DR1_ISET_SSI_VALUE);/* DR1 current control */
			pmussi_reg_write(SOC_SMART_DR2_ISET_ADDR(0), SDMMC_DR2_ISET_SSI_VALUE);/* DR2 current control */
			pmussi_reg_write(SOC_SMART_DR_BRE_CTRL_ADDR(0), SDMMC_DR_CONTROL_SSI_VALUE);/* Turn on DR1 DR2 */
			pmussi_reg_write(SOC_SMART_DISABLE4_ADDR(0),BIT(SOC_SMART_DISABLE4_dis_ldo22_int_START));
		}

		sd_ldo22_need_control = 1;
#endif
			break;

		case MMC_SIGNAL_VOLTAGE_120:
			/* FIXME */
			/* 1.20v is not support */
			himci_error("1.20V is not supported");
			break;
		default:
			himci_error("unknown signal voltage");
			break;
		}
	}

	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "--");

}
#endif

	return 0;
}
Exemple #23
0
static int __devinit hi_mci_probe(struct platform_device *pdev)
{
	struct mmc_host *mmc;
	struct himci_host *host = NULL;
	int ret = 0, irq;

	himci_trace(2, "begin");
	himci_assert(pdev);

	mmc = mmc_alloc_host(sizeof(struct himci_host), &pdev->dev);
	if (!mmc) {
		himci_error("no mem for hi mci host controller!\n");
		ret = -ENOMEM;
		goto out;
	}
	mmc->ops = &hi_mci_ops;

	mmc->f_min = CONFIG_MMC_CCLK_MIN;
	mmc->f_max = CONFIG_MMC_CCLK_MAX;
	mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED
		| MMC_CAP_MMC_HIGHSPEED;

	/* reload by this controller */
	mmc->max_blk_count = 2048;
	mmc->max_segs = 1024;
	mmc->max_req_size = 65535;/* see IP manual */
	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
	mmc->ocr = mmc->ocr_avail;


	host = mmc_priv(mmc);
	host->dma_vaddr = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
			&host->dma_paddr, GFP_KERNEL);
	if (!host->dma_vaddr) {
		himci_error("no mem for himci dma!\n");
		ret = -ENOMEM;
		goto out;
	}

	host->mmc = mmc;
	host->base = ioremap_nocache(CONFIG_HIMCI_IOBASE, HI_MCI_IO_SIZE);
	if (!host->base) {
		himci_error("no mem for himci base!\n");
		ret = -ENOMEM;
		goto out;
	}

	/* enable mmc clk */
	hi_mci_sys_ctrl_init(host);

	/* enable card */
	spin_lock_init(&host->lock);
	hi_mci_init_card(host);

	host->card_status = hi_mci_sys_card_detect(host);
	init_timer(&host->timer);

	host->timer.function = hi_mci_detect_card;
	host->timer.data = (unsigned long)host;
	host->timer.expires = jiffies + detect_time;
	platform_set_drvdata(pdev, mmc);
	mmc_add_host(mmc);

	add_timer(&host->timer);

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		printk(KERN_ERR "no IRQ defined!\n");
		goto out;
	}

	init_waitqueue_head(&host->intr_wait);

	host->irq = irq;
	ret = request_irq(irq, hisd_irq, 0, DRIVER_NAME, host);
	if (ret) {
		printk(KERN_ERR "request_irq error!\n");
		goto out;
	}

	return 0;
out:
	if (host) {
		if (host->base)
			iounmap(host->base);

		if (host->dma_vaddr)
			dma_free_coherent(&pdev->dev, PAGE_SIZE,
					host->dma_vaddr, host->dma_paddr);
	}
	if (mmc)
		mmc_free_host(mmc);

	return ret;
}
Exemple #24
0
static int hi_mci_exec_cmd(struct himci_host *host, struct mmc_command *cmd,
		struct mmc_data *data)
{
	union cmd_arg_s  cmd_regs;

	himci_trace(2, "begin");
	himci_assert(host);
	himci_assert(cmd);

	host->cmd = cmd;

	himci_writel(cmd->arg, host->base + MCI_CMDARG);

	cmd_regs.cmd_arg = himci_readl(host->base + MCI_CMD);
	if (data) {
		cmd_regs.bits.data_transfer_expected = 1;
		if (data->flags & (MMC_DATA_WRITE | MMC_DATA_READ))
			cmd_regs.bits.transfer_mode = 0;

		if (data->flags & MMC_DATA_STREAM)
			cmd_regs.bits.transfer_mode = 1;

		if (data->flags & MMC_DATA_WRITE)
			cmd_regs.bits.read_write = 1;
		else if (data->flags & MMC_DATA_READ)
			cmd_regs.bits.read_write = 0;
	} else {
		cmd_regs.bits.data_transfer_expected = 0;
		cmd_regs.bits.transfer_mode = 0;
		cmd_regs.bits.read_write = 0;
	}

	if (cmd == host->mrq->stop) {
		cmd_regs.bits.stop_abort_cmd = 1;
		cmd_regs.bits.wait_prvdata_complete = 0;
	} else {
		cmd_regs.bits.stop_abort_cmd = 0;
		cmd_regs.bits.wait_prvdata_complete = 1;
	}

	switch (mmc_resp_type(cmd)) {
	case MMC_RSP_NONE:
		cmd_regs.bits.response_expect = 0;
		cmd_regs.bits.response_length = 0;
		cmd_regs.bits.check_response_crc = 0;
		break;
	case MMC_RSP_R1:
	case MMC_RSP_R1B:
		cmd_regs.bits.response_expect = 1;
		cmd_regs.bits.response_length = 0;
		cmd_regs.bits.check_response_crc = 1;
		break;
	case MMC_RSP_R2:
		cmd_regs.bits.response_expect = 1;
		cmd_regs.bits.response_length = 1;
		cmd_regs.bits.check_response_crc = 1;
		break;
	case MMC_RSP_R3:
		cmd_regs.bits.response_expect = 1;
		cmd_regs.bits.response_length = 0;
		cmd_regs.bits.check_response_crc = 0;
		break;
	default:
		himci_error("hi_mci: unhandled response type %02x\n",
				mmc_resp_type(cmd));
		return -EINVAL;
	}

	himci_trace(3, "send cmd of card is cmd->opcode = %d ", cmd->opcode);
	if (cmd->opcode == MMC_GO_IDLE_STATE)
		cmd_regs.bits.send_initialization = 1;
	else
		cmd_regs.bits.send_initialization = 0;

	cmd_regs.bits.card_number = 0;
	cmd_regs.bits.cmd_index = cmd->opcode;
	cmd_regs.bits.send_auto_stop = 0;
	cmd_regs.bits.start_cmd = 1;
	cmd_regs.bits.update_clk_reg_only = 0;
	himci_writel(cmd_regs.cmd_arg, host->base + MCI_CMD);

	if (hi_mci_wait_cmd(host) != 0) {
		himci_trace(3, "send card cmd is failed!");
		return -EINVAL;
	}
	return 0;
}
Exemple #25
0
static int mshci_hi_start_signal_voltage_switch(struct mshci_host *ms_host,
				struct mmc_ios *ios)
{
	struct himci_host *hi_host = (struct himci_host *)(ms_host->private);
	int ret =0;
	struct iomux_pin *pin_temp = NULL;

	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "++");

	himci_assert(ios);
	himci_assert(hi_host);

	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "old_sig_voltage = %d ",
					hi_host->old_sig_voltage);
	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "new_sig_voltage = %d ",
					ios->signal_voltage);
	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "allow_switch_signal_voltage = %d ",
					hi_host->allow_switch_signal_voltage);

	if (hi_host->allow_switch_signal_voltage &&
		(hi_host->old_sig_voltage != ios->signal_voltage)) {
		switch (ios->signal_voltage) {
		case MMC_SIGNAL_VOLTAGE_330:
			/* alter driver 6mA */
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "alter driver 6mA");
			pin_temp = iomux_get_pin(SD_CLK_PIN);
			if (pin_temp) {
				ret = pinmux_setdrivestrength(pin_temp, LEVEL2);
				if (ret < 0)
					himci_error("pinmux_setdrivestrength error");
			} else {
				himci_error("failed to get iomux pin");
			}

			hi_host->old_sig_voltage = ios->signal_voltage;
			/* if there is signal vcc, set vcc to signal voltage */
		    if (hi_host->signal_vcc) {
				ret = regulator_set_voltage(hi_host->signal_vcc, 2600000, 2600000);
				if (ret != 0) {
					himci_error("failed to regulator_set_voltage");
				}
				ret = regulator_enable(hi_host->signal_vcc);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
		    }

			/* update time config*/
			mshci_hi_update_timing(ms_host, 0);
			break;
		case MMC_SIGNAL_VOLTAGE_180:
			/* alter driver 8mA */
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "alter driver 8mA");
			pin_temp = iomux_get_pin(SD_CLK_PIN);
			if (pin_temp) {
				ret = pinmux_setdrivestrength(pin_temp, LEVEL3);
				if (ret < 0)
					himci_error("pinmux_setdrivestrength error");
			} else {
				himci_error("failed to get iomux pin");
			}

			hi_host->old_sig_voltage = ios->signal_voltage;
			/* if there is signal vcc, set vcc to signal voltage */
		    if (hi_host->signal_vcc) {
				ret = regulator_set_voltage(hi_host->signal_vcc, 1800000, 1800000);
				if (ret != 0) {
					himci_error("failed to regulator_set_voltage");
				}
				ret = regulator_enable(hi_host->signal_vcc);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
		    }
			/* update time config*/
			mshci_hi_update_timing(ms_host, 0);
			break;

		case MMC_SIGNAL_VOLTAGE_120:
			/* FIXME */
			/* 1.20v is not support */
			himci_error("1.20V is not supported");
			break;
		default:
			himci_error("unknown signal voltage");
			break;
		}
	}

	hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "--");

	return 0;
}
Exemple #26
0
void mshci_hi_set_ios(struct mshci_host *ms_host, struct mmc_ios *ios)
{
	struct himci_host * hi_host = (struct himci_host *)(ms_host->private);
	int ret = -1;
	int cbp_flag = 0;

	hi_host_trace(HIMCI_TRACE_GEN_API, "++");

	himci_assert(ios);
	himci_assert(hi_host);

	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->power_mode = %d ", ios->power_mode);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->clock = %d ", ios->clock);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->bus_width = %d ", ios->bus_width);
	hi_host_trace(HIMCI_TRACE_GEN_INFO, "ios->timing = %d ", ios->timing);

	ret = get_hw_config_int("modem/viacbp82d", &cbp_flag, NULL);
	if ((!ret) || (0 == cbp_flag)) {
		pr_info("%s has no cbp support\n", __func__);
	}

	pr_info("%s mode %d\n", __func__, ios->power_mode);

	/* process power */
	if (hi_host->old_power_mode != ios->power_mode) {
		switch (ios->power_mode) {
		case MMC_POWER_OFF:
			if ((!cbp_flag)&&(1 == ms_host->hw_mmc_id)){
				mshci_sd_power_onoff(ms_host, 0);
				break;
			}
			hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "set io to lowpower");
			if (hi_host->piomux_block && hi_host->pblock_config){
				ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, LOWPOWER);
					if (ret) {
						himci_error("failed to blockmux_set");
					}
			}

			if (hi_host->vcc_lvs){
				ret = regulator_disable(hi_host->vcc_lvs);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
			}

			if (hi_host->vcc_ldo){
				ret = regulator_disable(hi_host->vcc_ldo);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
			}
			break;
		case MMC_POWER_UP:

			hi_host_trace(HIMCI_TRACE_SIGNIFICANT, "set io to normal");
			if ((!cbp_flag)&&(1 == ms_host->hw_mmc_id)){
				mshci_sd_power_onoff(ms_host, 1);
				break;
			}
			if (hi_host->vcc_ldo){
				ret = regulator_enable(hi_host->vcc_ldo);
				if (ret) {
					himci_error("failed to regulator_enable");
				}
			}
			if((1 == hi_host->ms_host->hw_mmc_id)&&(cbp_flag)){
				/*cbp need set as fixed 1.8v*/
				himci_error("sdio regulator_set_voltage 1.8 \n");
				if (hi_host->vcc_lvs) {
					ret = regulator_set_voltage(hi_host->vcc_lvs, SDMMC_1V8_IO_LDO7_180, SDMMC_1V8_IO_LDO7_180);
					if (ret != 0) {
						himci_error("failed to LDO7 regulator_set_voltage 1.8 \n");
					}
				}
			}
            if (hi_host->vcc_lvs){
                    ret = regulator_enable(hi_host->vcc_lvs);
                if (ret) {
                    himci_error("failed to regulator_enable");
                }
            }
            

            if (hi_host->piomux_block && hi_host->pblock_config){
                ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, NORMAL);
                if (ret) {
                    himci_error("failed to blockmux_set");
                }
            }
			break;
		case MMC_POWER_ON:
			break;
		default:
			himci_error("unknown power supply mode");
			break;
		}
		hi_host->old_power_mode = ios->power_mode;
	}

	hi_host_trace(HIMCI_TRACE_GEN_API, "--");
}