📄 s3c2410mci.c
字号:
} if(mrq->data->flags & MMC_DATA_READ) { sdi_dcon |= S3C2410_SDIDCON_RXAFTERCMD; sdi_dcon |= S3C2410_SDIDCON_XFER_RXSTART; } s3c2410sdi_dma_setup(host, mrq->data->flags & MMC_DATA_WRITE ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); /* see DMA-API.txt */ dma_len = dma_map_sg(&pdev->dev, mrq->data->sg, \ mrq->data->sg_len, \ mrq->data->flags & MMC_DATA_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); DBG(PFX "dma_len: 0x%08x\n",dma_len); /* start DMA */ s3c2410_dma_enqueue(host->dma, (void *) host, sg_dma_address(&mrq->data->sg[0]), (mrq->data->blocks << mrq->data->blksz_bits) ); } host->mrq = mrq; init_completion(&host->complete_request); init_completion(&host->complete_dma); //Clear command and data status registers writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT); writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA); // Setup SDI controller writel(sdi_bsize,host->base + S3C2410_SDIBSIZE); writel(sdi_timer,host->base + S3C2410_SDITIMER); writel(sdi_imsk,host->base + S3C2410_SDIIMSK); // Setup SDI command argument and data control writel(sdi_carg, host->base + S3C2410_SDICMDARG); writel(sdi_dcon, host->base + S3C2410_SDIDCON); // This initiates transfer writel(sdi_ccon, host->base + S3C2410_SDICMDCON); // Wait for transfer to complete wait_for_completion(&host->complete_request); DBG("[CMD] request complete.\n"); if(mrq->data) { wait_for_completion(&host->complete_dma); DBG("[DAT] DMA complete.\n"); } //Cleanup controller writel(0, host->base + S3C2410_SDICMDARG); writel(0, host->base + S3C2410_SDIDCON); writel(0, host->base + S3C2410_SDICMDCON); writel(0, host->base + S3C2410_SDIIMSK); // Read response mrq->cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0); mrq->cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1); mrq->cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2); mrq->cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3); host->mrq = NULL; DBG(PFX "mrq->cmd->resp[0]: 0x%08x\n",mrq->cmd->resp[0]); DBG(PFX "mrq->cmd->resp[1]: 0x%08x\n",mrq->cmd->resp[1]); DBG(PFX "mrq->cmd->resp[2]: 0x%08x\n",mrq->cmd->resp[2]); DBG(PFX "mrq->cmd->resp[3]: 0x%08x\n",mrq->cmd->resp[3]); // If we have no data transfer we are finished here if (!mrq->data) goto request_done; // Calulate the amout of bytes transfer, but only if there was // no error dma_unmap_sg(&pdev->dev,mrq->data->sg,dma_len,\ mrq->data->flags & MMC_DATA_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); if(mrq->data->error == MMC_ERR_NONE) { mrq->data->bytes_xfered = (mrq->data->blocks << mrq->data->blksz_bits); if(mrq->data->flags & MMC_DATA_READ); } else { mrq->data->bytes_xfered = 0; } // If we had an error while transfering data we flush the // DMA channel to clear out any garbage if(mrq->data->error != MMC_ERR_NONE) { s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); DBG(PFX "flushing DMA.\n"); } // Issue stop command if(mrq->data->stop) mmc_wait_for_cmd(mmc, mrq->data->stop, 3);request_done: mrq->done(mrq);}static void s3c2410sdi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct s3c2410sdi_host *host = mmc_priv(mmc); u32 sdi_psc, sdi_con; //Set power sdi_con = readl(host->base + S3C2410_SDICON); DBG(PFX "s3c2410sdi_set_ios\n"); DBG(PFX "S3C2410_SDICON :%08x\n",sdi_con); switch(ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: //s3c2410_gpio_setpin(S3C2410_GPA17, 1); // card power on s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK); s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD); s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0); s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1); s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2); s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3); if (host->pdata->set_power) (host->pdata->set_power)(1); sdi_con|= S3C2410_SDICON_FIFORESET; break; case MMC_POWER_OFF: default: if (host->pdata->set_power) (host->pdata->set_power)(0); break; } //Set clock for(sdi_psc=0;sdi_psc<255;sdi_psc++) { if( (clk_get_rate(host->clk) / (2*(sdi_psc+1))) <= ios->clock) break; } if(sdi_psc > 255) sdi_psc = 255; //sdi_psc =1; writel(sdi_psc, host->base + S3C2410_SDIPRE); //Set CLOCK_ENABLE if(ios->clock) sdi_con |= S3C2410_SDICON_CLOCKTYPE; else sdi_con &=~S3C2410_SDICON_CLOCKTYPE; writel(sdi_con, host->base + S3C2410_SDICON); DBG(PFX "S3C2410_SDICON :%08x\n",readl(host->base + S3C2410_SDICON)); DBG(PFX "S3C2410_SDICON :%08x\n",readl(host->base + S3C2410_SDIPRE)); host->bus_width = ios->bus_width;}static struct mmc_host_ops s3c2410sdi_ops = { .request = s3c2410sdi_request, .set_ios = s3c2410sdi_set_ios,};static void s3c2410_mmc_def_setpower(unsigned int to){ //s3c2410_gpio_cfgpin(S3C2410_GPA17, S3C2410_GPA17_OUT); //s3c2410_gpio_setpin(S3C2410_GPA17, to);}static struct s3c24xx_mmc_platdata s3c2410_mmc_defplat = { .gpio_detect = S3C2410_GPG10, .set_power = s3c2410_mmc_def_setpower, .f_max = 3000000, .ocr_avail = MMC_VDD_32_33,};static int s3c2410sdi_probe(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct mmc_host *mmc; s3c24xx_mmc_pdata_t *pdata; struct s3c2410sdi_host *host; int ret; mmc = mmc_alloc_host(sizeof(struct s3c2410sdi_host), dev); if (!mmc) { ret = -ENOMEM; goto probe_out; } host = mmc_priv(mmc); spin_lock_init( &host->complete_lock ); host->complete_what = COMPLETION_NONE; host->mmc = mmc; host->dma = S3C2410SDI_DMA; pdata = dev->platform_data; if (!pdata) { dev->platform_data = &s3c2410_mmc_defplat; pdata = &s3c2410_mmc_defplat; } host->pdata = pdata; host->irq_cd = s3c2410_gpio_getirq(pdata->gpio_detect); printk("host->irq_cd=%d\n",host->irq_cd); s3c2410_gpio_cfgpin(pdata->gpio_detect, S3C2410_GPG10_EINT18); host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!host->mem) { printk(KERN_INFO PFX "failed to get io memory region resouce.\n"); ret = -ENOENT; goto probe_free_host; } host->mem = request_mem_region(host->mem->start, RESSIZE(host->mem), pdev->name); if (!host->mem) { printk(KERN_INFO PFX "failed to request io memory region.\n"); ret = -ENOENT; goto probe_free_host; } host->base = ioremap(host->mem->start, RESSIZE(host->mem)); if (host->base == 0) { printk(KERN_INFO PFX "failed to ioremap() io memory region.\n"); ret = -EINVAL; goto probe_free_mem_region; } host->irq = platform_get_irq(pdev, 0); if (host->irq == 0) { printk(KERN_INFO PFX "failed to get interrupt resouce.\n"); ret = -EINVAL; goto probe_iounmap; } if(request_irq(host->irq, s3c2410sdi_irq, 0, DRIVER_NAME, host)) { printk(KERN_INFO PFX "failed to request sdi interrupt.\n"); ret = -ENOENT; goto probe_iounmap; } //s3c2410_gpio_cfgpin(S3C2410_GPG10, S3C2410_GPG10_EINT18); //GPG10 for sd detect; set_irq_type(host->irq_cd, IRQT_BOTHEDGE); if(request_irq(host->irq_cd, s3c2410sdi_irq_cd, 0, DRIVER_NAME, host)) { printk(KERN_WARNING PFX "failed to request card detect interrupt.\n" ); ret = -ENOENT; goto probe_free_irq; } if(s3c2410_dma_request(S3C2410SDI_DMA, &s3c2410sdi_dma_client, NULL)) { printk(KERN_WARNING PFX "unable to get DMA channel.\n" ); ret = -EBUSY; goto probe_free_irq_cd; } host->clk = clk_get(dev, "sdi"); if (IS_ERR(host->clk)) { printk(KERN_INFO PFX "failed to find clock source.\n"); ret = PTR_ERR(host->clk); host->clk = NULL; goto probe_free_host; } if((ret = clk_use(host->clk))) { printk(KERN_INFO PFX "failed to use clock source.\n"); goto clk_unuse; } if((ret = clk_enable(host->clk))) { printk(KERN_INFO PFX "failed to enable clock source.\n"); goto clk_free; } mmc->ops = &s3c2410sdi_ops; mmc->ocr_avail = MMC_VDD_32_33; mmc->f_min = clk_get_rate(host->clk) / 512; mmc->f_max = clk_get_rate(host->clk) / 2; mmc->caps = MMC_CAP_4_BIT_DATA; //HACK: There seems to be a hardware bug in TomTom GO. if(mmc->f_max>3000000) mmc->f_max=3000000; /* * 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; printk(KERN_INFO PFX "probe: mapped sdi_base=%p irq=%u irq_cd=%u dma=%u.\n", host->base, host->irq, host->irq_cd, host->dma);// if (host->pdata && host->pdata->init)// host->pdata->init(dev, s3c2410sdi_irq_cd, mmc); if((ret = mmc_add_host(mmc))) { printk(KERN_INFO PFX "failed to add mmc host.\n"); goto clk_disable; } dev_set_drvdata(dev, mmc); printk(KERN_INFO PFX "initialisation done.\n"); return 0; clk_disable: clk_disable(host->clk); clk_unuse: clk_unuse(host->clk); clk_free: clk_put(host->clk); probe_free_irq_cd: free_irq(host->irq_cd, host); probe_free_irq: free_irq(host->irq, host); probe_iounmap: iounmap(host->base); probe_free_mem_region: release_mem_region(host->mem->start, RESSIZE(host->mem)); probe_free_host: mmc_free_host(mmc); probe_out: return ret;}static int s3c2410sdi_remove(struct device *dev){ struct mmc_host *mmc = dev_get_drvdata(dev); struct s3c2410sdi_host *host = mmc_priv(mmc); mmc_remove_host(mmc); clk_disable(host->clk); clk_unuse(host->clk); clk_put(host->clk); free_irq(host->irq_cd, host); free_irq(host->irq, host); iounmap(host->base); release_mem_region(host->mem->start, RESSIZE(host->mem)); mmc_free_host(mmc); return 0;}static struct device_driver s3c2410sdi_driver ={ .name = "s3c2410-sdi", .bus = &platform_bus_type, .probe = s3c2410sdi_probe, .remove = s3c2410sdi_remove,};static int __init s3c2410sdi_init(void){ return driver_register(&s3c2410sdi_driver);}static void __exit s3c2410sdi_exit(void){ driver_unregister(&s3c2410sdi_driver);}module_init(s3c2410sdi_init);module_exit(s3c2410sdi_exit);MODULE_DESCRIPTION("Samsung S3C2410 Multimedia Card Interface driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -