static int arasan_cf_probe()

in pata_arasan_cf.c [794:917]


static int arasan_cf_probe(struct platform_device *pdev)
{
	struct arasan_cf_dev *acdev;
	struct arasan_cf_pdata *pdata = dev_get_platdata(&pdev->dev);
	struct ata_host *host;
	struct ata_port *ap;
	struct resource *res;
	u32 quirk;
	irq_handler_t irq_handler = NULL;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -EINVAL;

	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
				DRIVER_NAME)) {
		dev_warn(&pdev->dev, "Failed to get memory region resource\n");
		return -ENOENT;
	}

	acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL);
	if (!acdev)
		return -ENOMEM;

	if (pdata)
		quirk = pdata->quirk;
	else
		quirk = CF_BROKEN_UDMA; /* as it is on spear1340 */

	/*
	 * If there's an error getting IRQ (or we do get IRQ0),
	 * support only PIO
	 */
	ret = platform_get_irq(pdev, 0);
	if (ret > 0) {
		acdev->irq = ret;
		irq_handler = arasan_cf_interrupt;
	} else	if (ret == -EPROBE_DEFER) {
		return ret;
	} else	{
		quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA;
	}

	acdev->pbase = res->start;
	acdev->vbase = devm_ioremap(&pdev->dev, res->start,
			resource_size(res));
	if (!acdev->vbase) {
		dev_warn(&pdev->dev, "ioremap fail\n");
		return -ENOMEM;
	}

	acdev->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(acdev->clk)) {
		dev_warn(&pdev->dev, "Clock not found\n");
		return PTR_ERR(acdev->clk);
	}

	/* allocate host */
	host = ata_host_alloc(&pdev->dev, 1);
	if (!host) {
		dev_warn(&pdev->dev, "alloc host fail\n");
		return -ENOMEM;
	}

	ap = host->ports[0];
	host->private_data = acdev;
	acdev->host = host;
	ap->ops = &arasan_cf_ops;
	ap->pio_mask = ATA_PIO6;
	ap->mwdma_mask = ATA_MWDMA4;
	ap->udma_mask = ATA_UDMA6;

	init_completion(&acdev->cf_completion);
	init_completion(&acdev->dma_completion);
	INIT_WORK(&acdev->work, data_xfer);
	INIT_DELAYED_WORK(&acdev->dwork, delayed_finish);
	dma_cap_set(DMA_MEMCPY, acdev->mask);

	/* Handle platform specific quirks */
	if (quirk) {
		if (quirk & CF_BROKEN_PIO) {
			ap->ops->set_piomode = NULL;
			ap->pio_mask = 0;
		}
		if (quirk & CF_BROKEN_MWDMA)
			ap->mwdma_mask = 0;
		if (quirk & CF_BROKEN_UDMA)
			ap->udma_mask = 0;
	}
	ap->flags |= ATA_FLAG_PIO_POLLING | ATA_FLAG_NO_ATAPI;

	ap->ioaddr.cmd_addr = acdev->vbase + ATA_DATA_PORT;
	ap->ioaddr.data_addr = acdev->vbase + ATA_DATA_PORT;
	ap->ioaddr.error_addr = acdev->vbase + ATA_ERR_FTR;
	ap->ioaddr.feature_addr = acdev->vbase + ATA_ERR_FTR;
	ap->ioaddr.nsect_addr = acdev->vbase + ATA_SC;
	ap->ioaddr.lbal_addr = acdev->vbase + ATA_SN;
	ap->ioaddr.lbam_addr = acdev->vbase + ATA_CL;
	ap->ioaddr.lbah_addr = acdev->vbase + ATA_CH;
	ap->ioaddr.device_addr = acdev->vbase + ATA_SH;
	ap->ioaddr.status_addr = acdev->vbase + ATA_STS_CMD;
	ap->ioaddr.command_addr = acdev->vbase + ATA_STS_CMD;
	ap->ioaddr.altstatus_addr = acdev->vbase + ATA_ASTS_DCTR;
	ap->ioaddr.ctl_addr = acdev->vbase + ATA_ASTS_DCTR;

	ata_port_desc(ap, "phy_addr %llx virt_addr %p",
		      (unsigned long long) res->start, acdev->vbase);

	ret = cf_init(acdev);
	if (ret)
		return ret;

	cf_card_detect(acdev, 0);

	ret = ata_host_activate(host, acdev->irq, irq_handler, 0,
				&arasan_cf_sht);
	if (!ret)
		return 0;

	cf_exit(acdev);

	return ret;
}