?? omap_mmc.c
字號:
*(buf + 2) = data & 0xff; data = inw(OMAP_MMC_RSP6); DEBUG(3, " %x \n", data); *(buf + 3) = data >> 8; *(buf + 4) = data & 0xff; break; case RESPONSE_R2_CID: case RESPONSE_R2_CSD: *(buf) = 0x3f; /* for mmc core */ data = inw(OMAP_MMC_RSP7); *(buf + 1) = data >> 8; *(buf + 2) = data & 0xff; data = inw(OMAP_MMC_RSP6); *(buf + 3) = data >> 8; *(buf + 4) = data & 0xff; data = inw(OMAP_MMC_RSP5); *(buf + 5) = data >> 8; *(buf + 6) = data & 0xff; data = inw(OMAP_MMC_RSP4); *(buf + 7) = data >> 8; *(buf + 8) = data & 0xff; data = inw(OMAP_MMC_RSP3); *(buf + 9) = data >> 8; *(buf + 10) = data & 0xff; data = inw(OMAP_MMC_RSP2); *(buf + 11) = data >> 8; *(buf + 12) = data & 0xff; data = inw(OMAP_MMC_RSP1); *(buf + 13) = data >> 8; *(buf + 14) = data & 0xff; data = inw(OMAP_MMC_RSP0); *(buf + 15) = data >> 8; *(buf + 16) = data & 0xff; case RESPONSE_NONE: default: break; }}static voidomap_mmc_handle_int(struct omap_mmc_data *sd, u16 status){ int retval = MMC_NO_ERROR; int flags; local_irq_save(flags); DEBUG(3, ": Interrupt. Status: %d\n", status); /* Data or Command time-out? */ if (status & (OMAP_MMC_CMD_TIMEOUT | OMAP_MMC_DATA_TIMEOUT)) { DEBUG(0, ": MMC/SD status: %d \n", inw(OMAP_MMC_STAT)); retval = MMC_ERROR_TIMEOUT; goto terminate_int; } /* CRC error? */ if ((status & (OMAP_MMC_CMD_CRC | OMAP_MMC_DATA_CRC)) && !(inw(OMAP_MMC_CON) & (1 << 15))) { DEBUG(0, ": MMC/SD status: %d \n", inw(OMAP_MMC_STAT)); retval = MMC_ERROR_CRC; goto terminate_int; } if (((status & OMAP_MMC_END_OF_CMD) && (sd->request->result == MMC_NO_RESPONSE)) || (status & 1 << 14)) omap_mmc_get_response(sd->request); switch (g_omap_mmc_data.type) { case RT_NO_RESPONSE: break; case RT_WRITE: if (sd->request->nob) { /* Start another transfer */ outw(0xffff, OMAP_MMC_STAT); omap_mmc_start_tx_dma_transfer(g_omap_mmc_data.request-> block_len); return; } break; case RT_READ: if (sd->request->nob) { /* Start another transfer */ outw(0xffff, OMAP_MMC_STAT); omap_mmc_start_rx_dma_transfer(g_omap_mmc_data.request-> block_len); return; } break; case RT_RESPONSE_ONLY: if (sd->request->result < 0) { printk(KERN_INFO "MMC/SD: Illegal interrupt - command hasn't finished\n"); retval = MMC_ERROR_TIMEOUT; } break; } terminate_int: outw(0, OMAP_MMC_IE); /* Clear all interrupts */ sd->request->result = retval; mmc_cmd_complete(sd->request); local_irq_restore(flags);}/* Handle IRQ */static voidomap_mmc_int(int irq, void *dev_id, struct pt_regs *regs){ struct omap_mmc_data *sd = (struct omap_mmc_data *) dev_id; u16 status = inw(OMAP_MMC_STAT); omap_mmc_handle_int(sd, status);}/* Detect Card */static voidomap_mmc_fix_sd_detect(unsigned long nr){#ifdef CONFIG_ARCH_OMAP1510 card_state = inb(INNOVATOR_FPGA_INFO) & (1 << 4); if (card_state == 0) { outw((1 << 11), OMAP_MMC_CON); mmc_insert(0); } else { mmc_eject(0); }#endif#ifdef CONFIG_ARCH_OMAP1610 u8 state; state = inb(MPUIO_INPUT_LATCH_REG) & (1 << 1); if (card_state == state) { if (card_state == 0) { outw((1 << 11), OMAP_MMC_CON); mmc_insert(0); omap1610_tune_irq(OMAP_MMC_CD, IFL_HIGHLEVEL); } else { mmc_eject(0); omap1610_tune_irq(OMAP_MMC_CD, IFL_LOWLEVEL); } }#endif#ifdef CONFIG_ARCH_OMAP730 u8 state; state = get_p2_mmc_cd_state() & 1; if(card_state == state) { if ( card_state == 0 ) { /* Slot now has a card */ outw(MMC_CON_POWER_UP, OMAP_MMC_CON); mmc_insert(0); omap730_tune_irq(OMAP_MMC_CD, IFL_HIGHLEVEL); } else { /* Slot is now empty */ mmc_eject(0); omap730_tune_irq(OMAP_MMC_CD, IFL_LOWLEVEL); } }#endif}static voidomap_mmc_sd_detect_int(int irq, void *dev_id, struct pt_regs *regs){ struct omap_mmc_data *sd = (struct omap_mmc_data *) dev_id;#ifdef CONFIG_ARCH_OMAP1510 u8 state; state = inb(INNOVATOR_FPGA_INFO) & (1 << 4); if (card_state != state) mod_timer(&sd->sd_detect_timer, jiffies + ((card_state ? 50 : 500) * HZ) / 1000);#endif#ifdef CONFIG_ARCH_OMAP1610 card_state = inb(MPUIO_INPUT_LATCH_REG) & (1 << 1); mod_timer(&sd->sd_detect_timer, jiffies + ((card_state ? 50 : 500) * HZ) / 1000);#endif#ifdef CONFIG_ARCH_OMAP730 card_state = get_p2_mmc_cd_state() & 1; mod_timer(&sd->sd_detect_timer, jiffies + ((card_state ? 50 : 500) * HZ) / 1000);#endif}static intomap_mmc_slot_is_empty(int slot){#ifdef CONFIG_ARCH_OMAP1510 card_state = inb(INNOVATOR_FPGA_INFO) & (1 << 4);#endif#ifdef CONFIG_ARCH_OMAP1610 card_state = inb(MPUIO_INPUT_LATCH_REG) & (1 << 1);#endif#ifdef CONFIG_ARCH_OMAP730 card_state = get_p2_mmc_cd_state();#endif return card_state != 0;}/************************************************************************** * * Hardware initialization * *************************************************************************/static voidomap_mmc_slot_up(void){ /* OMAP MMC slot hardware init */#ifdef CONFIG_ARCH_OMAP1510 outb(inb(OMAP1510P1_FPGA_POWER) | (1 << 3), OMAP1510P1_FPGA_POWER);#endif#if defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_ARCH_OMAP1610) /* Enable MMC/SD clock and disable HI-Z on the MMC.DAT2 pin */ outl(inl(MOD_CONF_CTRL_0) | (1 << 23) | (1 << 21), MOD_CONF_CTRL_0); /* Set up correct pin multiplexing (OMAP1510 mode) */ /* Configure MMC.DAT3 pin */ outl(inl(FUNC_MUX_CTRL_D) & ~((1 << 14) | (1 << 13) | (1 << 12)), FUNC_MUX_CTRL_D); /* Configure MMC.CLK pin */ outl(inl(FUNC_MUX_CTRL_A) & ~((1 << 23) | (1 << 22) | (1 << 21)), FUNC_MUX_CTRL_A); /* Configure MMC_DAT0_SPI.DI pin */ outl(inl(FUNC_MUX_CTRL_B) & ~((1 << 2) | (1 << 1) | (1 << 0)), FUNC_MUX_CTRL_B); /* Configure MMC.DAT2 pin */ outl(inl(FUNC_MUX_CTRL_A) & ~((1 << 20) | (1 << 19) | (1 << 18)), FUNC_MUX_CTRL_A); /* Configure MMC.DAT1 pin */ outl(inl(FUNC_MUX_CTRL_A) & ~((1 << 26) | (1 << 25) | (1 << 24)), FUNC_MUX_CTRL_A); /* Configure MMC.CMD_SPI.DO pin */ outl(inl(FUNC_MUX_CTRL_A) & ~((1 << 29) | (1 << 28) | (1 << 27)), FUNC_MUX_CTRL_A);#endif#ifdef CONFIG_ARCH_OMAP730 /* Pin MUX is set up for the OMAP730/P2 in perseus2.c */ set_p2_v_sdmmc_state(V_SDMMC_ENABLED); set_p2_mmc_wp_state(MMC_WP_DISABLED); /* Start up the 48MHz MMC Clock */ OMAP730_CONFIGURE(PCONF_MMC_DPLL_REQ, ACTIVE); *((volatile u32 *)ECO_SPARE1) = ECO_SPARE1_INITVALUE;#endif /* Configure MMC_CON register */ outw((1 << 11), OMAP_MMC_CON); /* Clear interrupts and status */ outw(0, OMAP_MMC_IE); /* Clear all interrupts */ outw(0xffff, OMAP_MMC_STAT); /* Clear status bits */}static voidomap_mmc_slot_down(void){ disable_irq(OMAP_MMC_CD); disable_irq(OMAP_MMC_INT); /* Power Off MMC through FPGA */#ifdef CONFIG_ARCH_OMAP1510 outb(inb(OMAP1510P1_FPGA_POWER) & ~(1 << 3), OMAP1510P1_FPGA_POWER);#endif#if defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_ARCH_OMAP1610) /* Disable MMC/SD clock and enable HI-Z on the MMC.DAT2 pin */ outl(inl(MOD_CONF_CTRL_0) & ~((1 << 23) | (1 << 21)), MOD_CONF_CTRL_0);#endif#ifdef CONFIG_ARCH_OMAP730 OMAP730_CONFIGURE(PCONF_MMC_DPLL_REQ, INACTIVE);#endif outw(0, OMAP_MMC_CON); del_timer_sync(&g_omap_mmc_data.sd_detect_timer);#ifdef CONFIG_ARCH_OMAP730 set_p2_v_sdmmc_state(V_SDMMC_DISABLED);#endif}/* Standard PM functions */static intomap_mmc_suspend(void){ omap_mmc_stop_clock(); omap_mmc_slot_down(); return 0;}static voidomap_mmc_resume(void){ omap_mmc_slot_up(); omap_mmc_set_clock(g_omap_mmc_data.clock); /* Set up timers */ g_omap_mmc_data.sd_detect_timer.function = omap_mmc_fix_sd_detect; g_omap_mmc_data.sd_detect_timer.data = (unsigned long) &g_omap_mmc_data; init_timer(&g_omap_mmc_data.sd_detect_timer); enable_irq(OMAP_MMC_INT); enable_irq(OMAP_MMC_CD); /* Enable card detect IRQ */}#ifdef CONFIG_PMstatic intomap_mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ switch (req) { case PM_SUSPEND: mmc_eject(0); omap_mmc_suspend(); break; case PM_RESUME: omap_mmc_resume(); omap_mmc_fix_sd_detect(0); break; } return 0;}#endif#ifdef CONFIG_CEE /* MVL-CEE */static intomap_mmc_dpm_suspend(struct device *dev, u32 state, u32 level){ switch (level) { case SUSPEND_POWER_DOWN: /* Turn off power to MMC/SD */ omap_mmc_suspend(); break; } return 0;}static intomap_mmc_dpm_resume(struct device *dev, u32 level){ switch (level) { case RESUME_POWER_ON: /* Turn on power to MMC/SD */ omap_mmc_resume(); mmc_eject(0); omap_mmc_fix_sd_detect(0); break; } return 0;}#endifstatic intomap_mmc_slot_init(void){ int retval; /* Set up timers */ g_omap_mmc_data.sd_detect_timer.function = omap_mmc_fix_sd_detect; g_omap_mmc_data.sd_detect_timer.data = (unsigned long) &g_omap_mmc_data; init_timer(&g_omap_mmc_data.sd_detect_timer); /* Basic service interrupt */ retval = request_irq(OMAP_MMC_INT, omap_mmc_int, SA_INTERRUPT, "omap_mmc_int", &g_omap_mmc_data); if (retval) { printk(KERN_CRIT "MMC/SD: unable to grab MMC IRQ\n"); return retval; } disable_irq(OMAP_MMC_INT); /* Card Detect interrupt */ retval = request_irq(OMAP_MMC_CD, omap_mmc_sd_detect_int, SA_INTERRUPT, "omap_mmc_cd", &g_omap_mmc_data);#ifdef CONFIG_ARCH_OMAP1610 if (omap_mmc_slot_is_empty(0) == 0) omap1610_tune_irq(OMAP_MMC_CD, IFL_HIGHLEVEL);#endif#ifdef CONFIG_ARCH_OMAP730 if (omap_mmc_slot_is_empty(0) == 0) omap730_tune_irq(OMAP_MMC_CD, IFL_HIGHLEVEL);#endif if (retval) { printk(KERN_CRIT "MMC/SD: unable to grab MMC_CD_IRQ\n"); goto err1; } disable_irq(OMAP_MMC_CD); if (omap_request_dma (eMMCRx, "MMC/SD Rx DMA", (dma_callback_t) omap_mmc_rx_dma_callback, &g_omap_mmc_data, &(g_omap_mmc_data.rx_dma_regs))) { printk(KERN_ERR "Failed to request MMC Rx DMA \n"); goto err2; } if (omap_request_dma (eMMCTx, "MMC/SD Tx DMA", (dma_callback_t) omap_mmc_tx_dma_callback, &g_omap_mmc_data, &(g_omap_mmc_data.tx_dma_regs))) { printk(KERN_ERR "Failed to request MMC Tx DMA \n"); goto err3; }#ifdef CONFIG_PM pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, omap_mmc_pm_callback);#endif omap_mmc_slot_up(); enable_irq(OMAP_MMC_CD); /* Enable IRQ to detect card */ goto noerr; err3:omap_free_dma(g_omap_mmc_data.tx_dma_regs); err2:omap_free_dma(g_omap_mmc_data.rx_dma_regs); err1:free_irq(OMAP_MMC_INT, &g_omap_mmc_data); noerr:return retval;}static voidomap_mmc_slot_cleanup(void){ long flags; local_irq_save(flags); omap_mmc_slot_down(); mmc_eject(0); omap_free_dma(g_omap_mmc_data.tx_dma_regs); omap_free_dma(g_omap_mmc_data.rx_dma_regs); free_irq(OMAP_MMC_CD, &g_omap_mmc_data); free_irq(OMAP_MMC_INT, &g_omap_mmc_data); local_irq_restore(flags);}/***********************************************************/static struct mmc_slot_driver dops = { .owner = THIS_MODULE, .name = "OMAP1510/1610/730 MMC", .ocr = OMAP_MMC_OCR, .flags = MMC_SDFLAG_MMC_MODE, .init = omap_mmc_slot_init, .cleanup = omap_mmc_slot_cleanup, .is_empty = omap_mmc_slot_is_empty, .send_cmd = omap_mmc_send_command, .set_clock = omap_mmc_set_clock,};static int __initomap_mmc_init(void){ int retval;#ifdef CONFIG_CEE /* MVL-CCE */ omap_mmc_ldm_device_register(); omap_mmc_ldm_driver_register();#endif /* MVL-CCE */ retval = mmc_register_slot_driver(&dops, 1); if (retval < 0) printk(KERN_INFO "MMC/SD: unable to register slot\n"); return retval;}static void __exitomap_mmc_cleanup(void){#ifdef CONFIG_CEE /* MVL-CCE */ omap_mmc_ldm_device_unregister(); omap_mmc_ldm_driver_unregister();#endif /* MVL-CCE */ mmc_unregister_slot_driver(&dops);}module_init(omap_mmc_init);module_exit(omap_mmc_cleanup);MODULE_AUTHOR("Alexey Lugovskoy");MODULE_DESCRIPTION("OMAP1510/1610/730 Innovator MMC/SD");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -