📄 pxamci.c
字号:
DBG("PXAMCI: stat %08x\n", stat); if (ireg & END_CMD_RES) handled |= pxamci_cmd_done(host, stat); if (ireg & DATA_TRAN_DONE) handled |= pxamci_data_done(host, stat); } return IRQ_RETVAL(handled);}static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq){ struct pxamci_host *host = mmc_priv(mmc); unsigned int cmdat; WARN_ON(host->mrq != NULL); host->mrq = mrq;#ifndef CONFIG_CPU_MONAHANS pxamci_stop_clock(host);#endif cmdat = host->cmdat; host->cmdat &= ~CMDAT_INIT; if (mrq->data) { pxamci_setup_data(host, mrq->data); cmdat &= ~CMDAT_BUSY; cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; if (mrq->data->flags & MMC_DATA_WRITE) cmdat |= CMDAT_WRITE; if (mrq->data->flags & MMC_DATA_STREAM) cmdat |= CMDAT_STREAM; } pxamci_start_cmd(host, mrq->cmd, cmdat);}static int pxamci_get_ro(struct mmc_host *mmc){ struct pxamci_host *host = mmc_priv(mmc); if (host->pdata && host->pdata->get_ro) return host->pdata->get_ro(mmc->dev); /* Host doesn't support read only detection so assume writeable */ return 0;}static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios){ struct pxamci_host *host = mmc_priv(mmc);#ifdef CONFIG_CPU_MONAHANS struct platform_device *pdev = to_platform_device(mmc->dev);#endif DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", ios->clock, ios->power_mode, ios->vdd / 100, ios->vdd % 100); if (ios->clock) { unsigned int clk = CLOCKRATE / ios->clock; if (CLOCKRATE / clk > ios->clock) clk <<= 1; host->clkrt = fls(clk) - 1;#ifndef CONFIG_CPU_MONAHANS pxa_set_cken(CKEN12_MMC, 1);#else if (pdev->id == 0) pxa_set_cken(CKEN_MMC1, 1); else if (pdev->id == 1) pxa_set_cken(CKEN_MMC2, 1); pxamci_stop_clock(host); writel(host->clkrt, host->base + MMC_CLKRT); writel(START_CLOCK, host->base + MMC_STRPCL);#endif /* * we write clkrt on the next command */ } else { pxamci_stop_clock(host);#ifndef CONFIG_CPU_MONAHANS pxa_set_cken(CKEN12_MMC, 0);#else if (pdev->id == 0) pxa_set_cken(CKEN_MMC1, 0); else if (pdev->id == 1) pxa_set_cken(CKEN_MMC2, 0);#endif } if (host->power_mode != ios->power_mode) { host->power_mode = ios->power_mode; if (host->pdata && host->pdata->setpower) host->pdata->setpower(mmc->dev, ios->vdd); if (ios->power_mode == MMC_POWER_ON) host->cmdat |= CMDAT_INIT; } DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n", host->clkrt, host->cmdat);}static struct mmc_host_ops pxamci_ops = { .request = pxamci_request, .get_ro = pxamci_get_ro, .set_ios = pxamci_set_ios,};static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs){ DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;}static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs){ struct pxamci_host *host = mmc_priv(devid); mmc_detect_change(devid, host->pdata->detect_delay); return IRQ_HANDLED;}static int pxamci_probe(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct mmc_host *mmc; struct pxamci_host *host = NULL; struct resource *r; int ret, irq; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!r || irq == NO_IRQ) return -ENXIO; r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); if (!r) return -EBUSY; mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev); if (!mmc) { ret = -ENOMEM; goto out; } mmc->ops = &pxamci_ops; mmc->f_min = CLOCKRATE_MIN; mmc->f_max = CLOCKRATE_MAX; /* * We can do SG-DMA, but we don't because we never know how much * data we successfully wrote to the card. */ mmc->max_hw_segs = 32; mmc->max_phys_segs = 32; mmc->max_sectors = 256; /* * Our hardware DMA can handle a maximum of one page per SG entry. */ mmc->max_seg_size = PAGE_SIZE; host = mmc_priv(mmc); host->mmc = mmc; host->dma = -1; host->pdata = pdev->dev.platform_data; mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : MMC_VDD_32_33|MMC_VDD_33_34; host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { ret = -ENOMEM; goto out; } spin_lock_init(&host->lock); host->res = r; host->irq = irq; host->imask = MMC_I_MASK_ALL; if (pdev->id == 0) host->base = (u32)&(__REG(0x41100000)); else if (pdev->id == 1) host->base = (u32)&(__REG_2(0x42000000)); /* * Ensure that the host controller is shut down, and setup * with our defaults. */ pxa_set_cken(CKEN_MMC1, 1);#ifdef CONFIG_MMC2 pxa_set_cken(CKEN_MMC2, 1); #endif pxamci_stop_clock(host);#ifdef CONFIG_CPU_MONAHANS writel(0x6, host->base + MMC_CLKRT); writel(START_CLOCK, host->base + MMC_STRPCL);#endif writel(0, host->base + MMC_SPI); writel(64, host->base + MMC_RESTO); writel(host->imask, host->base + MMC_I_MASK); host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, pxamci_dma_irq, host); if (host->dma < 0) { ret = -EBUSY; goto out; } ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); if (ret) goto out; dev_set_drvdata(dev, mmc); if (host->pdata && host->pdata->init) host->pdata->init(dev, pxamci_detect_irq, mmc); mmc_add_host(mmc); return 0; out: if (host) { if (host->dma >= 0) pxa_free_dma(host->dma); if (host->base) iounmap(host->base); if (host->sg_cpu) dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); } if (mmc) mmc_free_host(mmc); release_resource(r); return ret;}static int pxamci_remove(struct device *dev){ struct mmc_host *mmc = dev_get_drvdata(dev); dev_set_drvdata(dev, NULL); if (mmc) { struct pxamci_host *host = mmc_priv(mmc); if (host->pdata && host->pdata->exit) host->pdata->exit(dev, mmc); mmc_remove_host(mmc); pxamci_stop_clock(host); writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, host->base + MMC_I_MASK); DRCMRRXMMC = 0; DRCMRTXMMC = 0; free_irq(host->irq, host); pxa_free_dma(host->dma); iounmap(host->base); dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); release_resource(host->res); mmc_free_host(mmc); } return 0;}#ifdef CONFIG_PMstatic int pxamci_suspend(struct device *dev, pm_message_t state, u32 level){ struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; if (mmc && level == SUSPEND_DISABLE) ret = mmc_suspend_host(mmc, state); return ret;}static int pxamci_resume(struct device *dev, u32 level){ struct mmc_host *mmc = dev_get_drvdata(dev); int ret = 0; if (mmc && level == RESUME_ENABLE) ret = mmc_resume_host(mmc); return ret;}#else#define pxamci_suspend NULL#define pxamci_resume NULL#endifstatic struct device_driver pxamci_driver = { .name = DRIVER_NAME, .bus = &platform_bus_type, .probe = pxamci_probe, .remove = pxamci_remove, .suspend = pxamci_suspend, .resume = pxamci_resume,};static int __init pxamci_init(void){ return driver_register(&pxamci_driver);}static void __exit pxamci_exit(void){ driver_unregister(&pxamci_driver);}module_init(pxamci_init);module_exit(pxamci_exit);MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -