📄 jademmc1.c.svn-base
字号:
status = readl(base + MMCISTATUS); } while (status & MCI_TXFIFOHALFEMPTY); return ptr - buffer;}/* * Handle completion of command and data transfers. */static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs){ struct jademmci_host *host = dev_id; u32 status; int ret = 0; spin_lock(&host->lock); do { struct mmc_command *cmd; struct mmc_data *data; status = readl(host->base + MMCISTATUS); status &= readl(host->base + MMCIMASK0); writel(status, host->base + MMCICLEAR); DBG(host, "irq0 %08x\n", status); data = host->data; if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) mmci_data_irq(host, data, status); cmd = host->cmd; if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) { mmci_cmd_irq(host, cmd, status); } ret = 1; } while (status); spin_unlock(&host->lock); return IRQ_RETVAL(ret);}static void mmci_data_transfer(struct jademmci_host *host,unsigned int read){ void __iomem *base = host->base; unsigned int status; unsigned long flags; unsigned int remain, len; char *buffer; status = readl( base + MMCISTATUS); do{ /* * Map the current scatter buffer. */ buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; remain = host->sg_ptr->length - host->sg_off; len = 0; if (read) len = mmci_pio_read(host, buffer, remain); else len = mmci_pio_write(host, buffer, remain, status); /* * Unmap the buffer. */ mmci_kunmap_atomic(host, &flags); host->sg_off += len; host->size -= len; remain -= len; if (!remain) break; if (!mmci_next_sg(host)) break; } while (1); }static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq){ struct jademmci_host *host = mmc_priv(mmc); unsigned int timeout=0xffffffff, status; unsigned int flag; unsigned int tmp; WARN_ON(host->mrq != NULL); spin_lock_irq(&host->lock); writel(0, host->base + MMCIDATACTRL); host->mrq = mrq; if (mrq->data && mrq->data->flags & MMC_DATA_READ) mmci_start_data(host, mrq->data); mmci_start_command(host, mrq->cmd, 0); if ((mrq->data != NULL ) && (host->size <=32)) { flag = mrq->data->flags & MMC_DATA_READ; if ( !flag ) { tmp = readl(host->base+MMCIDATACTRL); while ( !(tmp & MCI_DPSM_ENABLE)) ; } do{ status = readl(host->base + MMCISTATUS); if(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)) break; timeout--; }while(timeout); mmci_data_transfer(host,flag); mmci_data_end(host); } spin_unlock_irq(&host->lock);}static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios){ struct jademmci_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); if (ios->clock) { if (ios->clock >= host->mclk) { clk = MCI_CLK_BYPASS; host->cclk = host->mclk; } else { clk = host->mclk / (2 * ios->clock) - 1; if (clk > 256) clk = 255; host->cclk = host->mclk / (2 * (clk + 1)); } clk |= MCI_CLK_ENABLE; } if (host->plat->translate_vdd) pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); switch (ios->power_mode) { case MMC_POWER_OFF: break; case MMC_POWER_UP: pwr |= MCI_PWR_UP; break; case MMC_POWER_ON: pwr |= MCI_PWR_ON; break; } if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) pwr |= MCI_OD; if (ios->bus_mode == MMC_BUSMODE_PUSHPULL){ if (ios->bus_width == MMC_BUS_WIDTH_4){ clk &=0xf00; clk |= (1<<11)| 0x1; } } writel(clk, host->base + MMCICLOCK); if (host->pwr != pwr) { host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); }}static struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios,};static void mmci_check_status(unsigned long data){ struct jademmci_host *host = (struct jademmci_host *)data; unsigned int status; status = host->plat->status(mmc_dev(host->mmc)); if (status ^ host->oldstat) mmc_detect_change(host->mmc, 0); host->oldstat = status; mod_timer(&host->timer, jiffies + HZ);}static irqreturn_t jademci_detect_irq(int irq, void *devid, struct pt_regs *regs){ unsigned int detect_delay = msecs_to_jiffies(250); mmc_detect_change(devid, detect_delay); return IRQ_HANDLED;}static int mmci_probe(struct amba_device *dev, void *id){ struct jademmc_platform_data *plat = dev->dev.platform_data; struct jademmci_host *host; struct mmc_host *mmc; int ret; /* must have platform data */ if (!plat) { ret = -EINVAL; goto out; } ret = amba_request_regions(dev, DRIVER_NAME); if (ret) goto out; mmc = mmc_alloc_host(sizeof(struct jademmci_host), &dev->dev); if (!mmc) { ret = -ENOMEM; goto rel_regions; } host = mmc_priv(mmc); host->clk = clk_get(&dev->dev, "MCLK"); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); host->clk = NULL; goto host_free; } ret = clk_use(host->clk); if (ret) goto clk_free; ret = clk_enable(host->clk); if (ret) goto clk_unuse; host->plat = plat; host->mclk = clk_get_rate(host->clk); host->mmc = mmc; host->base = ioremap(dev->res.start, SZ_4K); if (!host->base) { ret = -ENOMEM; goto clk_disable; } mmc->ops = &mmci_ops; mmc->f_min = host->mclk / 512; mmc->f_max = host->mclk; mmc->ocr_avail = plat->ocr_mask; /* * We can do SGIO */ mmc->max_hw_segs = 16; mmc->max_phys_segs = 16; /* * Since we only have a 16-bit data length register, we must * ensure that we don't exceed 2^16-1 bytes in a single request. * Choose 64 (512-byte) sectors as the limit. */ mmc->max_sectors = 64; /* * Set the maximum segment size. Since we aren't doing DMA * (yet) we are only limited by the data length register. */ mmc->max_seg_size = mmc->max_sectors << 9; spin_lock_init(&host->lock); writel(0, host->base + MMCIMASK0); writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host); if (ret) goto unmap; if((ret=sd_request_dma()) < 0){ printk("JADE_SD dma_request error!\n"); goto irq0_free; } mmc->caps = MMC_CAP_4_BIT_DATA;#ifdef CONFIG_ARCH_X900 if (host->plat && host->plat->init) host->plat->init(&dev->dev, jademci_detect_irq, mmc);#endif writel(MCI_IRQENABLE1, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); mmc_add_host(mmc); printk(KERN_INFO "%s: MMCI rev in jademmci.c %x cfg %02x at 0x%08lx irq %d,%d\n", mmc_hostname(mmc), amba_rev(dev), amba_config(dev), dev->res.start, dev->irq[0], dev->irq[1]); init_timer(&host->timer); host->timer.data = (unsigned long)host; host->timer.function = mmci_check_status; host->timer.expires = jiffies + HZ; add_timer(&host->timer); return 0; irq0_free: free_irq(dev->irq[0], host); unmap: iounmap(host->base); clk_disable: clk_disable(host->clk); clk_unuse: clk_unuse(host->clk); clk_free: clk_put(host->clk); host_free: mmc_free_host(mmc); rel_regions: amba_release_regions(dev); out: return ret;}static int mmci_remove(struct amba_device *dev){ struct mmc_host *mmc = amba_get_drvdata(dev); amba_set_drvdata(dev, NULL); if (mmc) { struct jademmci_host *host = mmc_priv(mmc); del_timer_sync(&host->timer); mmc_remove_host(mmc); writel(0, host->base + MMCIMASK0); writel(0, host->base + MMCIMASK1); writel(0, host->base + MMCICOMMAND); writel(0, host->base + MMCIDATACTRL); free_irq(dev->irq[0], host); iounmap(host->base); clk_disable(host->clk); clk_unuse(host->clk); clk_put(host->clk); mmc_free_host(mmc); amba_release_regions(dev); } return 0;}#ifdef CONFIG_PMstatic int mmci_suspend(struct amba_device *dev, pm_message_t state){ struct mmc_host *mmc = amba_get_drvdata(dev); int ret = 0; if (mmc) { struct jademmci_host *host = mmc_priv(mmc); ret = mmc_suspend_host(mmc, state); if (ret == 0) writel(0, host->base + MMCIMASK0); } return ret;}static int mmci_resume(struct amba_device *dev){ struct mmc_host *mmc = amba_get_drvdata(dev); int ret = 0; if (mmc) { struct jademmci_host *host = mmc_priv(mmc); writel(MCI_IRQENABLE, host->base + MMCIMASK0); ret = mmc_resume_host(mmc); } return ret;}#else#define mmci_suspend NULL#define mmci_resume NULL#endifstatic struct amba_id mmci_ids[] = { { .id = 0x00041180, .mask = 0x000fffff, }, { .id = 0x00041181, .mask = 0x000fffff, }, { 0, 0 },};static struct amba_driver mmci_driver = { .drv = { .name = DRIVER_NAME, }, .probe = mmci_probe, .remove = mmci_remove, .suspend = mmci_suspend, .resume = mmci_resume, .id_table = mmci_ids,};static int __init mmci_init(void){ void *r; unsigned long tmp; #ifdef CONFIG_ARCH_X900 r=ioremap(SYSTEM_REGISTER_BASE,SZ_4K); if(r==NULL){ printk(" error for mmc-system remap\n"); return -ENODEV; } tmp = readl(r+PINCFG); tmp &= 0xF8FFFFFF; writel(tmp,r+PINCFG);#else r=ioremap(Z228_NEWSCTL_BASE,SZ_4K); tmp = readl(r+PINCFG); tmp &= ~(1<<9); writel(tmp,r+PINCFG); DBG("PINCONFIG = 0x%x\n",readl(r +0x10c )); #endif iounmap(r); return amba_driver_register(&mmci_driver);}static void __exit mmci_exit(void){ amba_driver_unregister(&mmci_driver);}module_init(mmci_init);module_exit(mmci_exit);module_param(fmax, uint, 0444);MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -