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