Exemplo n.º 1
0
static int __devinit mshci_s3c_probe(struct platform_device *pdev)
{
	struct s3c_mshci_platdata *pdata = pdev->dev.platform_data;
	struct device *dev = &pdev->dev;
	struct mshci_host *host;
	struct mshci_s3c *sc;
	struct resource *res;
	int ret, irq, ptr, clks;

	if (!pdata) {
		dev_err(dev, "no device data specified\n");
		return -ENOENT;
	}

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(dev, "no irq specified\n");
		return irq;
	}
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "no memory specified\n");
		return -ENOENT;
	}
	host = mshci_alloc_host(dev, sizeof(struct mshci_s3c));
	if (IS_ERR(host)) {
		dev_err(dev, "mshci_alloc_host() failed\n");
		return PTR_ERR(host);
	}
	sc = mshci_priv(host);

	sc->host = host;
	sc->pdev = pdev;
	sc->pdata = pdata;
	sc->ext_cd_gpio = -1;

#ifndef CONFIG_S5PV310_FPGA
	platform_set_drvdata(pdev, host);

	sc->clk_io = clk_get(dev, "mshc");
	if (IS_ERR(sc->clk_io)) {
		dev_err(dev, "failed to get io clock\n");
		ret = PTR_ERR(sc->clk_io);
		goto err_io_clk;
	}
	/* enable the local io clock and keep it running for the moment. */
	clk_enable(sc->clk_io);

	for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
		struct clk *clk;
		char *name = pdata->clocks[ptr];
		if (name == NULL)
			continue;
		clk = clk_get(dev, name);
		if (IS_ERR(clk)) {
			dev_err(dev, "failed to get clock %s\n", name);
			continue;
		}

#if defined (CONFIG_S5PV310_MSHC_VPLL_46MHZ) || \
	defined (CONFIG_S5PV310_MSHC_EPLL_45MHZ)
	if (!strcmp("sclk_mshc",name)) {
		struct clk *parent_clk;

		if (!(parent_clk = clk_get_parent(clk))) {
			dev_err(dev, "failed to get parent clock %s\n"
			, (char *)(clk->name));
		} else {
			for ( ; ; ) {
				parent_clk = clk_get_parent(parent_clk);
				if ( parent_clk ) {
#ifdef CONFIG_S5PV310_MSHC_EPLL_45MHZ
					if (!strcmp("fout_epll", \
							parent_clk->name)) {
#if defined(CONFIG_MACH_C1Q1_REV02) || defined(CONFIG_MACH_P6_REV02)
						clk_set_rate \
							(parent_clk, 144000000);
#else
						clk_set_rate \
							(parent_clk, 180633600);
#endif
						pdata->cfg_ddr(pdev, 0);
#elif defined (CONFIG_S5PV310_MSHC_VPLL_46MHZ)
					if (!strcmp("fout_vpll", \
							parent_clk->name)) {
						clk_set_rate \
							(parent_clk, 370882812);
						pdata->cfg_ddr(pdev, 0);
#endif
						clk_enable(parent_clk);
						break;
					}
					else
						continue;
				} else {
					dev_err(dev, "failed to"
								"get parent"
								"clock %s\n"
								, clk->name);
					break;
				}
			}
		}
	}
#endif
		clks++;
		sc->clk_bus[ptr] = clk;
		clk_enable(clk);


		dev_info(dev, "clock source %d: %s (%ld Hz)\n",
			 ptr, name, clk_get_rate(clk));
	}


	if (clks == 0) {
		dev_err(dev, "failed to find any bus clocks\n");
		ret = -ENOENT;
		goto err_no_busclks;
	}
#endif

	sc->ioarea = request_mem_region(res->start, resource_size(res),
					mmc_hostname(host->mmc));
	if (!sc->ioarea) {
		dev_err(dev, "failed to reserve register area\n");
		ret = -ENXIO;
		goto err_req_regs;
	}

	host->ioaddr = ioremap_nocache(res->start, resource_size(res));
	if (!host->ioaddr) {
		dev_err(dev, "failed to map registers\n");
		ret = -ENXIO;
		goto err_req_regs;
	}

	/* Ensure we have minimal gpio selected CMD/CLK/Detect */
	if (pdata->cfg_gpio) {
		pdata->cfg_gpio(pdev, pdata->max_width);
	} else {
		dev_err(dev, "cfg_gpio dose not exist.!\n");
	}

	host->hw_name = "samsung-mshci";
	host->ops = &mshci_s3c_ops;
	host->quirks = 0;
	host->irq = irq;

	if (pdata->host_caps)
		host->mmc->caps = pdata->host_caps;
	else
		host->mmc->caps = 0;

	if (pdata->cd_type == S3C_MSHCI_CD_PERMANENT){
		host->quirks |= MSHCI_QUIRK_BROKEN_PRESENT_BIT;
		host->mmc->caps |= MMC_CAP_NONREMOVABLE;
	}

	/* IF SD controller's WP pin donsn't connected with SD card and there
	 * is an allocated GPIO for getting WP data form SD card,
	 * use this quirk and send the GPIO number in pdata->wp_gpio. */
	if (pdata->has_wp_gpio && gpio_is_valid(pdata->wp_gpio)) {
		mshci_s3c_ops.get_ro = mshci_s3c_get_ro;
		host->quirks |= MSHCI_QUIRK_NO_WP_BIT;
		mshci_s3c_cfg_wp(pdata->wp_gpio);
	}

	ret = mshci_add_host(host);

	if (pdata->cd_type == S3C_MSHCI_CD_GPIO &&
		gpio_is_valid(pdata->ext_cd_gpio)) {

		gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD");
		sc->ext_cd_gpio = pdata->ext_cd_gpio;

		sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
		if (sc->ext_cd_irq &&
			request_irq(sc->ext_cd_irq, mshci_s3c_gpio_card_detect_isr,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
				dev_name(&pdev->dev), sc)) {
			dev_err(&pdev->dev, "cannot request irq for card detect\n");
			sc->ext_cd_irq = 0;
		}
		dev_dbg(&pdev->dev, "mshci detects a card insertion/removal"
							"by EINT\n");
	}

	if (ret) {
		dev_err(dev, "mshci_add_host() failed\n");
		goto err_add_host;
	}

	return 0;

 err_add_host:
	release_resource(sc->ioarea);
	kfree(sc->ioarea);

 err_req_regs:
	for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
		clk_disable(sc->clk_bus[ptr]);
		clk_put(sc->clk_bus[ptr]);
	}

 err_no_busclks:
	clk_disable(sc->clk_io);
	clk_put(sc->clk_io);

 err_io_clk:
	mshci_free_host(host);
	return ret;
}

static int __devexit mshci_s3c_remove(struct platform_device *pdev)
{
	return 0;
}

#ifdef CONFIG_PM

static int mshci_s3c_suspend(struct platform_device *dev, pm_message_t pm)
{
	struct mshci_host *host = platform_get_drvdata(dev);

	mshci_suspend_host(host, pm);
	return 0;
}

static int mshci_s3c_resume(struct platform_device *dev)
{
	struct mshci_host *host = platform_get_drvdata(dev);

	mshci_resume_host(host);
	return 0;
}

static void mshci_s3c_shutdown(struct platform_device *dev)
{
	struct mshci_host *host = platform_get_drvdata(dev);
	struct s3c_mshci_platdata *pdata = dev->dev.platform_data;
	pm_message_t dummy = {0}; // mshci_suspend_host func is pm not used.

	mshci_suspend_host(host, dummy);

	if (pdata->shutdown)
		pdata->shutdown();
}

#else

static int mshci_s3c_suspend(struct platform_device *dev, pm_message_t pm)
{
	pr_info("%s : is DUMMY\n", __func__);
	return 0;
}
Exemplo n.º 2
0
static int hi_mci_suspend(struct platform_device *dev, pm_message_t pm)
{

	struct mshci_host *ms_host = NULL;
	struct himci_host *hi_host = NULL;
	int ret = 0;
	unsigned long flags;
	int cbp_flag = 0;
	int cbp_ret = 0;

	ms_host = platform_get_drvdata(dev);
	if (!ms_host) {
		printk(KERN_ERR "get drvdata failed !\n");
		return -1;
	}
	hi_host = mshci_priv(ms_host);

    if(0 == hi_host->pdev->id)
    {
        g_ulmmc_suspend_flag = true;
        printk("hi_mci_suspend,set g_ulmmc_suspend_flag.");
    }

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

	if ((1 == hi_host->pdev->id)&&(cbp_flag)){
		if (ms_host->mmc->ios.power_mode != MMC_POWER_OFF) {
			pr_info("%s cbp ext suspend sdio\n", __func__);
			if (cbp_in_sdio_tras){
				pr_info("%s cbp_in_sdio_tras %d\n", __func__, cbp_in_sdio_tras);
				return -EAGAIN;
			}
			cbp_clock_enabled = 0;
			cbp_host_waked = 0;
			cbp_notifier_call_chain(0, NULL);

			ms_host->mmc->ios.power_mode = MMC_POWER_UP;
			ms_host->mmc->ios.clock = 0;
			ms_host->mmc->ops->set_ios(ms_host->mmc, &ms_host->mmc->ios);
		}
		ret = blockmux_set(hi_host->piomux_block, hi_host->pblock_config, LOWPOWER);
		if (ret) {
			himci_error("failed to blockmux_set");
		}
	}


	if (ms_host->quirks & MSHCI_QUIRK_WLAN_DETECTION) {
		/* sdio power off */
		if (ms_host->mmc->ios.power_mode != MMC_POWER_OFF) {
			ret = mmc_sdio_suspend_ext(ms_host->mmc);
			if (ret) {
				printk("%s, sdio suspend error\n", __func__);
				return ret;
			}

			ms_host->mmc->ios.power_mode = MMC_POWER_UP;
			hi_host->old_timing = 0;
			hi_host->old_sig_voltage = 0;
		}
	}

    /*sd and emmc share the same suspend and resume*/
    mshci_suspend_host(ms_host, pm);

	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);


	return 0;
}