static int au1xmmc_probe()

in host/au1xmmc.c [932:1114]


static int au1xmmc_probe(struct platform_device *pdev)
{
	struct mmc_host *mmc;
	struct au1xmmc_host *host;
	struct resource *r;
	int ret, iflag;

	mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
	if (!mmc) {
		dev_err(&pdev->dev, "no memory for mmc_host\n");
		ret = -ENOMEM;
		goto out0;
	}

	host = mmc_priv(mmc);
	host->mmc = mmc;
	host->platdata = pdev->dev.platform_data;
	host->pdev = pdev;

	ret = -ENODEV;
	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!r) {
		dev_err(&pdev->dev, "no mmio defined\n");
		goto out1;
	}

	host->ioarea = request_mem_region(r->start, resource_size(r),
					   pdev->name);
	if (!host->ioarea) {
		dev_err(&pdev->dev, "mmio already in use\n");
		goto out1;
	}

	host->iobase = ioremap(r->start, 0x3c);
	if (!host->iobase) {
		dev_err(&pdev->dev, "cannot remap mmio\n");
		goto out2;
	}

	host->irq = platform_get_irq(pdev, 0);
	if (host->irq < 0) {
		ret = host->irq;
		goto out3;
	}

	mmc->ops = &au1xmmc_ops;

	mmc->f_min =   450000;
	mmc->f_max = 24000000;

	mmc->max_blk_size = 2048;
	mmc->max_blk_count = 512;

	mmc->ocr_avail = AU1XMMC_OCR;
	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
	mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;

	iflag = IRQF_SHARED;	/* Au1100/Au1200: one int for both ctrls */

	switch (alchemy_get_cputype()) {
	case ALCHEMY_CPU_AU1100:
		mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE;
		break;
	case ALCHEMY_CPU_AU1200:
		mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
		break;
	case ALCHEMY_CPU_AU1300:
		iflag = 0;	/* nothing is shared */
		mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
		mmc->f_max = 52000000;
		if (host->ioarea->start == AU1100_SD0_PHYS_ADDR)
			mmc->caps |= MMC_CAP_8_BIT_DATA;
		break;
	}

	ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host);
	if (ret) {
		dev_err(&pdev->dev, "cannot grab IRQ\n");
		goto out3;
	}

	host->clk = clk_get(&pdev->dev, ALCHEMY_PERIPH_CLK);
	if (IS_ERR(host->clk)) {
		dev_err(&pdev->dev, "cannot find clock\n");
		ret = PTR_ERR(host->clk);
		goto out_irq;
	}

	ret = clk_prepare_enable(host->clk);
	if (ret) {
		dev_err(&pdev->dev, "cannot enable clock\n");
		goto out_clk;
	}

	host->status = HOST_S_IDLE;

	/* board-specific carddetect setup, if any */
	if (host->platdata && host->platdata->cd_setup) {
		ret = host->platdata->cd_setup(mmc, 1);
		if (ret) {
			dev_warn(&pdev->dev, "board CD setup failed\n");
			mmc->caps |= MMC_CAP_NEEDS_POLL;
		}
	} else
		mmc->caps |= MMC_CAP_NEEDS_POLL;

	/* platform may not be able to use all advertised caps */
	if (host->platdata)
		mmc->caps &= ~(host->platdata->mask_host_caps);

	tasklet_setup(&host->data_task, au1xmmc_tasklet_data);

	tasklet_setup(&host->finish_task, au1xmmc_tasklet_finish);

	if (has_dbdma()) {
		ret = au1xmmc_dbdma_init(host);
		if (ret)
			pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n");
	}

#ifdef CONFIG_LEDS_CLASS
	if (host->platdata && host->platdata->led) {
		struct led_classdev *led = host->platdata->led;
		led->name = mmc_hostname(mmc);
		led->brightness = LED_OFF;
		led->default_trigger = mmc_hostname(mmc);
		ret = led_classdev_register(mmc_dev(mmc), led);
		if (ret)
			goto out5;
	}
#endif

	au1xmmc_reset_controller(host);

	ret = mmc_add_host(mmc);
	if (ret) {
		dev_err(&pdev->dev, "cannot add mmc host\n");
		goto out6;
	}

	platform_set_drvdata(pdev, host);

	pr_info(DRIVER_NAME ": MMC Controller %d set up at %p"
		" (mode=%s)\n", pdev->id, host->iobase,
		host->flags & HOST_F_DMA ? "dma" : "pio");

	return 0;	/* all ok */

out6:
#ifdef CONFIG_LEDS_CLASS
	if (host->platdata && host->platdata->led)
		led_classdev_unregister(host->platdata->led);
out5:
#endif
	__raw_writel(0, HOST_ENABLE(host));
	__raw_writel(0, HOST_CONFIG(host));
	__raw_writel(0, HOST_CONFIG2(host));
	wmb(); /* drain writebuffer */

	if (host->flags & HOST_F_DBDMA)
		au1xmmc_dbdma_shutdown(host);

	tasklet_kill(&host->data_task);
	tasklet_kill(&host->finish_task);

	if (host->platdata && host->platdata->cd_setup &&
	    !(mmc->caps & MMC_CAP_NEEDS_POLL))
		host->platdata->cd_setup(mmc, 0);
out_clk:
	clk_disable_unprepare(host->clk);
	clk_put(host->clk);
out_irq:
	free_irq(host->irq, host);
out3:
	iounmap((void *)host->iobase);
out2:
	release_resource(host->ioarea);
	kfree(host->ioarea);
out1:
	mmc_free_host(mmc);
out0:
	return ret;
}