📄 mmci.c
字号:
/* enable clock */ reg = mmc_inw(IO_MMC_MEM_CLK_CONTROL); outw(reg | 0x0100, IO_MMC_MEM_CLK_CONTROL); local_irq_enable(); enable_interrupt(); spin_unlock(&host->lock); host->data = NULL; return 0;}int src_read(struct mmc_host *mmc,struct mmc_request *mrq,unsigned int *relative,char* scr_reg){ u32 marg; u16 cmd1,reg; int read_count; struct mmc_command cmd; struct mmci_host *host = mmc_priv(mmc); short temp_data; spin_lock(&host->lock); disable_interrupt(); local_irq_disable(); memset(scr_reg,0,8*sizeof(char)); /* disable clock */ reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); outw(reg & 0xFEFF, IO_MMC_MEM_CLK_CONTROL); wmb(); #if 0 printk ("%s %d\n",__FUNCTION__,__LINE__); mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { mrq->cmd->data = mrq->data; mrq->data->error = 0; mrq->data->mrq = mrq; if (mrq->stop) { mrq->data->stop = mrq->stop; mrq->stop->error = 0; mrq->stop->mrq = mrq; } } it_mmcsd_get_status(&cmd); it_mmcsd_clear_response_reg(&cmd); current_add = mrq->cmd->arg; no_of_blks = mrq->data->blocks;// * host->sg_len; //To read more than segment#endif do{ char *buffer = NULL; short *buffer_short = NULL; int count = 0; buffer = scr_reg; it_mmcsd_clear_response_reg(&cmd); it_mmcsd_get_status(&cmd); //it_mmcsd_print_status(&cmd); outw(1,IO_MMC_NR_BLOCKS); outw(0x200,IO_MMC_BLOCK_LENGTH); buffer_short = (short*)buffer; marg = 0x200; cmd1 = 51 | 0x0200 | 0x2000 | 0x0080 | 0x0000 | 0x0000; outw(marg & 0xFFFF,IO_MMC_ARG_LOW); outw((marg >> 16),IO_MMC_ARG_HI); outw(cmd1,IO_MMC_COMMAND);#if 1 do { it_mmcsd_get_status(&cmd); //mdelay(10); }while( !((cmd.status0 & 0x4)==4));//checking for busy state and response of the command#endif //it_mmcsd_print_status(&cmd); read_count = 0; do{ it_mmcsd_get_status(&cmd); //it_mmcsd_print_status(&cmd); reg = cmd.status0; if (reg & 0x0040) { mmc_debug_msg ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Read CRC error\n"); mmc_debug_msg ("STATUS0 :%x\tSTATUS1 :%x\n",cmd.status0,cmd.status1); break; } if ((cmd.status0 & 0x400)) { temp_data = 0; temp_data = inw (IO_MMC_RX_DATA); mmc_debug_msg_rw ("%x\t",temp_data); if (read_count < 4){ *buffer = (temp_data >> 8) & 0xFF; buffer = buffer + 1; *buffer = temp_data & 0xFF; buffer = buffer + 1; } read_count++; if (read_count > 0x200) break; } else if (cmd.status0 & 0x10){ printk("Command Time OUT"); break; } } while (!(reg &0x0001)); do{ if (count ++ > 100) break; it_mmcsd_get_status(&cmd); }while((cmd.status1 & 0x1)); buffer_short = NULL ; break; }while(1); /* enable clock */ reg = mmc_inw(IO_MMC_MEM_CLK_CONTROL); outw(reg | 0x0100, IO_MMC_MEM_CLK_CONTROL); local_irq_enable(); enable_interrupt(); spin_unlock(&host->lock); return 0;}static volatile int plug_count = 0;static int dat3stat_new = 0;static int dat3stat_old = 0;static int dat3stat_count = 0;static void host_configuration(void){ short reg = 0; /*Erase past settings*/ outw(0x0,IO_MMC_CONTROL); outw(0x0,IO_MMC_MEM_CLK_CONTROL);// outw(0x0,IO_MEM_STICK_MODE);//MS mode /*HOST CONFIGURATION STARTS */ /* bring the controller to reset state */ reg = inw(IO_MMC_CONTROL); outw(reg | 0x03,IO_MMC_CONTROL); wmb(); reg = inw(IO_MMC_CONTROL); rmb(); /* configure mmc controller */ reg = inw(IO_MMC_CONTROL); outw(reg | 0x0200 | 0x0400 | 0x0000,IO_MMC_CONTROL); wmb(); reg = inw(IO_MMC_CONTROL); rmb(); /*Response timeout register */ outw(255,IO_MMC_RESPONSE_TIMEOUT); wmb(); /*Data timeout register*/ reg = inw (IO_MMC_RESPONSE_TIMEOUT); rmb(); outw(reg | 0x1F00,IO_MMC_RESPONSE_TIMEOUT); wmb(); outw(0xFFFF,IO_MMC_READ_TIMEOUT); wmb(); /* disable clock */ reg = inw(IO_MMC_MEM_CLK_CONTROL); outw(reg & 0xFEFF, IO_MMC_MEM_CLK_CONTROL); wmb(); reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); /* set clock */ outw(inw(IO_CLK_INV) | 0x1,IO_CLK_INV); wmb(); /* set function clock */ outw(( (mmc_inw(IO_CLK_DIV3) & 0xFF00) | (0x01)) ,IO_CLK_DIV3); wmb(); /* set mmc clock to ~ 400 kHz */ /* 338 KHZ */ outw((0),IO_MMC_MEM_CLK_CONTROL); wmb(); outw(((mmc_inw(IO_MMC_MEM_CLK_CONTROL) & 0xFF00) | (0x40)),IO_MMC_MEM_CLK_CONTROL); wmb(); outw((0x40),IO_MMC_MEM_CLK_CONTROL); wmb(); /* release controller reset state */ reg = inw(IO_MMC_CONTROL); rmb(); outw(reg & 0xFFFC,IO_MMC_CONTROL); wmb(); reg = inw(IO_MMC_CONTROL); rmb(); /* enable clock */ reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); outw(reg | 0x0100, IO_MMC_MEM_CLK_CONTROL); wmb(); reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); /*HOST CONFIGURATION ENDS*/}static void mmci_check_status(unsigned long data){ struct mmci_host *host = (struct mmci_host *)data; u16 status; status = gio_get_bitset(GIO_SD_CARDDETECT) & !(inw(IO_GIO_CARD_ST)); rmb(); if (status ^ host->oldstat){ host_configuration(); mmc_detect_change(host->mmc, 0); printk("card state changed\n"); goto detect_called; } if (inw (IO_MMC_STATUS1) & 0x10) dat3stat_new = 1; else dat3stat_new = 0; if ((dat3stat_old == 1) && (dat3stat_new == 1)){ if ((dat3stat_count == 0) && (plug_count == 0)){ host_configuration(); mmc_detect_change(host->mmc, 0); dat3stat_count = 1; } }detect_called: host->oldstat = status; dat3stat_old = dat3stat_new; mod_timer(&host->timer, jiffies + HZ); outw (0x0000,IO_GIO_CARD_SET); wmb(); plug_count = 0; }static int get_write_protect_status(struct mmc_host *mmc){ mmc_debug_msg("Write protect status : %x\n",gio_get_bitset(GIO_SDCARD_WP)); return gio_get_bitset(GIO_SDCARD_WP);} static struct mmc_host_ops mmci_ops = { .request = mmci_request, .set_ios = mmci_set_ios, .get_ro = get_write_protect_status,};static int mmci_probe(struct device *dev){ struct mmc_platform_data *plat = dev->platform_data; struct mmci_host *host = NULL; struct mmc_host *mmc = NULL; int ret; volatile u16 reg; #ifdef DMA_TRANSFER mmc_debug_msg("DMA TRANSFER ENABLED\n");#endif mmc = mmc_alloc_host(sizeof(struct mmci_host), dev); bCardInitialized = 0; if (!mmc) { ret = -ENOMEM; mmc_debug_msg(" mmc_alloc_host failed \n"); goto rel_regions; } host = mmc_priv(mmc); host->cmd = NULL; host->clk = clk_get(dev, "MCLK"); mmc->readdata = read_from_card;//used in calling the read system call mmc->writedata = write_to_card;//used in calling the write system call mmc->src_data = src_read;//used in calling src read function mmc->enable_interrupt = enable_interrupt; mmc->disable_interrupt = disable_interrupt; mmc->change_clk25m = change_clk25m; host_configuration();//Host controller configuration 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; mmc->ops = &mmci_ops; mmc->ocr_avail = 1 << 16;//Has to be done by platform data /* * We can do SGIO */ mmc->max_hw_segs = 16; mmc->max_phys_segs = NR_SG; /* * 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); reg = inw(IO_INTC_EINT1); rmb(); reg &= ~(3 << 0); outw(reg,IO_INTC_EINT1); wmb(); //ret = request_irq(IRQ_SD_MMC, mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host); //ret = request_irq(IRQ_SD_MMC, mmci_irq, SA_INTERRUPT, DRIVER_NAME " (cmd)", host); //ret = request_irq(IRQ_SD_MMC, mmci_irq,SA_PROBE, DRIVER_NAME " (cmd)", host); ret = request_irq(IRQ_SD_MMC, mmci_irq,0, DRIVER_NAME " (cmd)", host); if (ret){ printk ("Interrupt %d may be busy\n",IRQ_SD_MMC); free_irq(IRQ_SD_MMC,host); } outw((mmc_inw(IO_INTC_EINT1) & 0xFFFC),IO_INTC_EINT1); wmb(); outw(0x114,IO_MMC_INT_ENABLE); wmb(); outw((mmc_inw(IO_INTC_EINT1) | 0x3),IO_INTC_EINT1); wmb(); dev_set_drvdata(dev,mmc); mmc_add_host(mmc); 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); mmc_debug_msg ("Leaving mmci probe\n"); return 0; clk_unuse: clk_unuse(host->clk); clk_free: clk_put(host->clk); rel_regions: return ret;}static int mmci_remove(struct device *dev){ struct mmc_host *mmc = dev_get_drvdata(dev); mmc_debug_msg ("entering %s\n",__FUNCTION__); plug_count = 0; dat3stat_new = 0; dev_set_drvdata(dev, NULL); if (mmc) { struct mmci_host *host = mmc_priv(mmc); del_timer_sync(&host->timer); mmc_remove_host(mmc); mmc_free_host(mmc); free_irq(IRQ_SD_MMC,mmc_priv(mmc)); } mmc_debug_msg ("leaving %s\n",__FUNCTION__); return 0;}#define mmci_suspend NULL#define mmci_resume NULLstatic struct device_driver mmci_driver = { .name = DRIVER_NAME, .bus = &platform_bus_type, .probe = mmci_probe, .remove = mmci_remove, .suspend = mmci_suspend, .resume = mmci_resume,};static irqreturn_t it_mmcsd_detect_interrupt(int flags, void * data, struct pt_regs * regs){ int inserted = 0; if (!plug_count) { inserted = gio_get_bitset(GIO_SD_CARDDETECT); outw (0x0003,IO_GIO_CARD_SET); //inversion & card detect enable wmb(); if (inserted & !inw(IO_GIO_CARD_ST)){ mmc_debug_msg("Card pluged out\t\n"); } else{ mmc_debug_msg("Card pluged in\t\n"); } plug_count += 1; return IRQ_HANDLED; } else{ if (plug_count < 5){ //5 is debounce count plug_count += 1; return IRQ_HANDLED; } else{ plug_count = 0; return IRQ_HANDLED; } }}static void init_sd_mmc(void){ int status; status = request_gio(GIO_SD_CARDDETECT); if (status){ mmc_debug_msg("\tUnable to register gio1 %d\n",GIO_SD_CARDDETECT); } gio_enable_irq(GIO_SD_CARDDETECT,GIO_ANY_EDGE); mmc_debug_msg ("IRQ_GIO8 : %d\t\n",IRQ_GIO8); status = request_irq(IRQ_GIO8 /* GIO_SD_CARDDETECT */,it_mmcsd_detect_interrupt,0,"mmc/sd DMA controller",NULL); if (status){ mmc_debug_msg("\tUnable to register irq \t\n"); } status = request_gio(GIO_SDCARD_WP); if (status){ mmc_debug_msg("\tUnable to register gio2 %d\n",GIO_SDCARD_WP); } gio_set_dir(GIO_SDCARD_WP,bit_hi);}static int __init mmci_init(void){ int val = 0; val = driver_register(&mmci_driver); init_sd_mmc(); return val;}static void __exit mmci_exit(void){ unsigned short reg; plug_count = 0; dat3stat_new = 0; disable_interrupt(); reg = inw(IO_MMC_MEM_CLK_CONTROL); rmb(); outw(reg & 0xFEFF, IO_MMC_MEM_CLK_CONTROL); wmb(); unrequest_gio(GIO_SD_CARDDETECT); free_irq(IRQ_GIO8,NULL); unrequest_gio(GIO_SDCARD_WP); driver_unregister(&mmci_driver);}module_init(mmci_init);module_exit(mmci_exit);module_param(fmax, uint, 0444);#if defined(CONFIG_ARCH_NTDEV_DM320) || defined(CONFIG_ARCH_NTR3_DM320) || defined(CONFIG_ARCH_ITDM320_20)static struct clk *clk_get(struct device *dev, const char *id){ //mmc_debug_msg(" %s called \n",__FUNCTION__);}static void clk_put(struct clk *clk){ //mmc_debug_msg(" %s called \n",__FUNCTION__);}static int clk_enable(struct clk *clk){ //mmc_debug_msg(" %s called \n",__FUNCTION__); return 0;}static int clk_use(struct clk *clk){ //mmc_debug_msg(" %s called \n",__FUNCTION__); return 0;}static unsigned long clk_get_rate(struct clk *clk){ //mmc_debug_msg(" %s called \n",__FUNCTION__); //return clk->rate; return 0;}static void clk_unuse(struct clk *clk){ mmc_debug_msg(" %s called \n",__FUNCTION__);}#endifMODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -