コード例 #1
0
ファイル: omap.c プロジェクト: AllenDou/linux
static int __devexit mmc_omap_remove(struct platform_device *pdev)
{
	struct mmc_omap_host *host = platform_get_drvdata(pdev);
	int i;

	platform_set_drvdata(pdev, NULL);

	BUG_ON(host == NULL);

	for (i = 0; i < host->nr_slots; i++)
		mmc_omap_remove_slot(host->slots[i]);

	if (host->pdata->cleanup)
		host->pdata->cleanup(&pdev->dev);

	mmc_omap_fclk_enable(host, 0);
	free_irq(host->irq, host);
	clk_put(host->fclk);
	clk_disable(host->iclk);
	clk_put(host->iclk);

	if (host->dma_tx)
		dma_release_channel(host->dma_tx);
	if (host->dma_rx)
		dma_release_channel(host->dma_rx);

	iounmap(host->virt_base);
	release_mem_region(pdev->resource[0].start,
			   pdev->resource[0].end - pdev->resource[0].start + 1);
	destroy_workqueue(host->mmc_omap_wq);

	kfree(host);

	return 0;
}
コード例 #2
0
static void
mmc_omap_clk_timer(unsigned long data)
{
	struct mmc_omap_host *host = (struct mmc_omap_host *) data;

	mmc_omap_fclk_enable(host, 0);
}
コード例 #3
0
ファイル: omap.c プロジェクト: 7799/linux
static int mmc_omap_remove(struct platform_device *pdev)
{
	struct mmc_omap_host *host = platform_get_drvdata(pdev);
	int i;

	BUG_ON(host == NULL);

	for (i = 0; i < host->nr_slots; i++)
		mmc_omap_remove_slot(host->slots[i]);

	if (host->pdata->cleanup)
		host->pdata->cleanup(&pdev->dev);

	mmc_omap_fclk_enable(host, 0);
	free_irq(host->irq, host);
	clk_put(host->fclk);
	clk_disable(host->iclk);
	clk_put(host->iclk);

	if (host->dma_tx)
		dma_release_channel(host->dma_tx);
	if (host->dma_rx)
		dma_release_channel(host->dma_rx);

	destroy_workqueue(host->mmc_omap_wq);

	return 0;
}
コード例 #4
0
ファイル: omap.c プロジェクト: A2109devs/lenovo_a2109a_kernel
static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
{
	struct mmc_omap_host *host = slot->host;
	unsigned long flags;

	if (claimed)
		goto no_claim;
	spin_lock_irqsave(&host->slot_lock, flags);
	while (host->mmc != NULL) {
		spin_unlock_irqrestore(&host->slot_lock, flags);
		wait_event(host->slot_wq, host->mmc == NULL);
		spin_lock_irqsave(&host->slot_lock, flags);
	}
	host->mmc = slot->mmc;
	spin_unlock_irqrestore(&host->slot_lock, flags);
no_claim:
	del_timer(&host->clk_timer);
	if (host->current_slot != slot || !claimed)
		mmc_omap_fclk_offdelay(host->current_slot);

	if (host->current_slot != slot) {
		OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00);
		if (host->pdata->switch_slot != NULL)
			host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id);
		host->current_slot = slot;
	}

	if (claimed) {
		mmc_omap_fclk_enable(host, 1);

		/* Doing the dummy read here seems to work around some bug
		 * at least in OMAP24xx silicon where the command would not
		 * start after writing the CMD register. Sigh. */
		OMAP_MMC_READ(host, CON);

		OMAP_MMC_WRITE(host, CON, slot->saved_con);
	} else
		mmc_omap_fclk_enable(host, 0);
}
コード例 #5
0
ファイル: omap.c プロジェクト: 3sOx/asuswrt-merlin
static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
{
	struct mmc_omap_host *host = slot->host;
	unsigned long flags;

	if (claimed)
		goto no_claim;
	spin_lock_irqsave(&host->slot_lock, flags);
	while (host->mmc != NULL) {
		spin_unlock_irqrestore(&host->slot_lock, flags);
		wait_event(host->slot_wq, host->mmc == NULL);
		spin_lock_irqsave(&host->slot_lock, flags);
	}
	host->mmc = slot->mmc;
	spin_unlock_irqrestore(&host->slot_lock, flags);
no_claim:
	del_timer(&host->clk_timer);
	if (host->current_slot != slot || !claimed)
		mmc_omap_fclk_offdelay(host->current_slot);

	if (host->current_slot != slot) {
		OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00);
		if (host->pdata->switch_slot != NULL)
			host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id);
		host->current_slot = slot;
	}

	if (claimed) {
		mmc_omap_fclk_enable(host, 1);

		OMAP_MMC_READ(host, CON);

		OMAP_MMC_WRITE(host, CON, slot->saved_con);
	} else
		mmc_omap_fclk_enable(host, 0);
}
コード例 #6
0
ファイル: omap.c プロジェクト: A2109devs/lenovo_a2109a_kernel
static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
{
	struct mmc_omap_host *host = slot->host;
	unsigned long flags;
	int i;

	BUG_ON(slot == NULL || host->mmc == NULL);

	if (clk_enabled)
		/* Keeps clock running for at least 8 cycles on valid freq */
		mod_timer(&host->clk_timer, jiffies  + HZ/10);
	else {
		del_timer(&host->clk_timer);
		mmc_omap_fclk_offdelay(slot);
		mmc_omap_fclk_enable(host, 0);
	}

	spin_lock_irqsave(&host->slot_lock, flags);
	/* Check for any pending requests */
	for (i = 0; i < host->nr_slots; i++) {
		struct mmc_omap_slot *new_slot;

		if (host->slots[i] == NULL || host->slots[i]->mrq == NULL)
			continue;

		BUG_ON(host->next_slot != NULL);
		new_slot = host->slots[i];
		/* The current slot should not have a request in queue */
		BUG_ON(new_slot == host->current_slot);

		host->next_slot = new_slot;
		host->mmc = new_slot->mmc;
		spin_unlock_irqrestore(&host->slot_lock, flags);
		schedule_work(&host->slot_release_work);
		return;
	}

	host->mmc = NULL;
	wake_up(&host->slot_wq);
	spin_unlock_irqrestore(&host->slot_lock, flags);
}
コード例 #7
0
ファイル: omap.c プロジェクト: A2109devs/lenovo_a2109a_kernel
static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
	struct mmc_omap_slot *slot = mmc_priv(mmc);
	struct mmc_omap_host *host = slot->host;
	int i, dsor;
	int clk_enabled;

	mmc_omap_select_slot(slot, 0);

	dsor = mmc_omap_calc_divisor(mmc, ios);

	if (ios->vdd != slot->vdd)
		slot->vdd = ios->vdd;

	clk_enabled = 0;
	switch (ios->power_mode) {
	case MMC_POWER_OFF:
		mmc_omap_set_power(slot, 0, ios->vdd);
		break;
	case MMC_POWER_UP:
		/* Cannot touch dsor yet, just power up MMC */
		mmc_omap_set_power(slot, 1, ios->vdd);
		goto exit;
	case MMC_POWER_ON:
		mmc_omap_fclk_enable(host, 1);
		clk_enabled = 1;
		dsor |= 1 << 11;
		break;
	}

	if (slot->bus_mode != ios->bus_mode) {
		if (slot->pdata->set_bus_mode != NULL)
			slot->pdata->set_bus_mode(mmc_dev(mmc), slot->id,
						  ios->bus_mode);
		slot->bus_mode = ios->bus_mode;
	}

	/* On insanely high arm_per frequencies something sometimes
	 * goes somehow out of sync, and the POW bit is not being set,
	 * which results in the while loop below getting stuck.
	 * Writing to the CON register twice seems to do the trick. */
	for (i = 0; i < 2; i++)
		OMAP_MMC_WRITE(host, CON, dsor);
	slot->saved_con = dsor;
	if (ios->power_mode == MMC_POWER_ON) {
		/* worst case at 400kHz, 80 cycles makes 200 microsecs */
		int usecs = 250;

		/* Send clock cycles, poll completion */
		OMAP_MMC_WRITE(host, IE, 0);
		OMAP_MMC_WRITE(host, STAT, 0xffff);
		OMAP_MMC_WRITE(host, CMD, 1 << 7);
		while (usecs > 0 && (OMAP_MMC_READ(host, STAT) & 1) == 0) {
			udelay(1);
			usecs--;
		}
		OMAP_MMC_WRITE(host, STAT, 1);
	}

exit:
	mmc_omap_release_slot(slot, clk_enabled);
}