?? mx2_mmc.c
字號(hào):
int i; u16 rs; u32 temp; request->result = MMC_NO_ERROR; /* Mark this as having a request result of some kind */ DEBUG(3, ": Get response \n"); switch (request->rtype) { case RESPONSE_R1: case RESPONSE_R1B: request->response[0] = request->cmd; temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[1] = (u8) (rs & 0x00FF); temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[2] = (u8) (rs >> 8); if (request->cmd == 3 && request->response[1] == 0 && request->response[2] == 0x40) { request->response[2] &= request->response[2] & ~(1 << 6); } /* mmc device does not clear this bit after APP_CMD command for some mmc cards */ request->response[3] = (u8) (rs & 0x00FF); temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[4] = (u8) (rs >> 8); break; case RESPONSE_R3: case RESPONSE_R4: case RESPONSE_R5: request->response[0] = 0x3f; temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[1] = (u8) (rs & 0x00FF); temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[2] = (u8) (rs >> 8); request->response[3] = (u8) (rs & 0x00FF); temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[4] = (u8) (rs >> 8); break; case RESPONSE_R2_CID: case RESPONSE_R2_CSD: request->response[0] = 0x3f; /* for mmc core */ for (i = 0; i < 8; i++) { temp = SDHC_RES_FIFO(MMC_BASE); rs = (u16) temp; request->response[2 * i + 1] = (u8) (rs >> 8); request->response[2 * i + 2] = (u8) (rs & 0x00FF); } case RESPONSE_NONE: default: break; }}static voidmx2_mmc_handle_int(struct mx2_mmc_data *sd){ int retval = MMC_NO_ERROR; u16 status = SDHC_STATUS(MMC_BASE); mx2_mmc_stop_clock(); /* Clear status bits */ SDHC_INT_MASK(MMC_BASE) = MX2_AUTO_CARD_DETECT_MASK & 0x7f; /* mask and clear all interrupts */ /* Data or Command time-out? */ if (status & (MX2STAT_TIME_OUT_RESP | MX2STAT_TIME_OUT_READ)) { DEBUG(1, " TIMEOUT: MMC status: %x \n", status); retval = MMC_ERROR_TIMEOUT; sd->request->result = MMC_ERROR_TIMEOUT; mx2_mmc_get_response(sd->request); goto terminate_int; } /* CRC error? */ if ((status & (MX2STAT_RESP_CRC_ERR /* | MX2STAT_CRC_READ_ERR */ ))) { DEBUG(1, " MMCSD_RESP_CRC_ERR: MMC status: %x \n", status); retval = MMC_ERROR_CRC; goto terminate_int; } if (((status & MX2STAT_END_CMD_RESP) || (status & MX2STAT_DATA_TRANS_DONE) || (status & MX2STAT_WRITE_OP_DONE)) && (sd->request->result == MMC_NO_RESPONSE)) { mx2_mmc_get_response(sd->request); } switch (g_mx2_mmc_data.type) { case RT_NO_RESPONSE: break; case RT_WRITE: if (sd->request->nob) { /* Start another transfer */ } break; case RT_READ: if (sd->request->nob) { /* Start another transfer */ } break; case RT_RESPONSE_ONLY: if (sd->request->result < 0) { printk(KERN_INFO "MMC: Illegal interrupt - command hasn't finished\n"); retval = MMC_ERROR_TIMEOUT; } break; } terminate_int: sd->request->result = retval; mmc_cmd_complete(sd->request);}/* Handle IRQ */static voidmx2_mmc_int(int irq, void *dev_id, struct pt_regs *regs){ struct mx2_mmc_data *sd = (struct mx2_mmc_data *) dev_id; u32 status = SDHC_STATUS(MMC_BASE) & 0xFFFF; DEBUG(4, " 0x%x\n", SDHC_STATUS(MMC_BASE)); if ((sd->request->cmd == MMC_READ_SINGLE_BLOCK || sd->request->cmd == MMC_READ_MULTIPLE_BLOCK)) { if (status & MX2STAT_APPL_BUFF_FF) { mx2_mmc_rx(); } else if ((status & MX2STAT_DATA_TRANS_DONE) || ((status & MX2STAT_END_CMD_RESP) && rx_counter >= g_mx2_mmc_data.request->block_len)) { mx2_mmc_handle_int(sd); } } else if ((sd->request->cmd == MMC_WRITE_BLOCK || sd->request->cmd == MMC_WRITE_MULTIPLE_BLOCK)) { if (status & MX2STAT_WRITE_OP_DONE) { mx2_mmc_handle_int(sd); } else if (status & MX2STAT_DATA_TRANS_DONE) { } else if (status & MX2STAT_APPL_BUFF_FE) { mx2_mmc_tx(); } } else { mx2_mmc_handle_int(sd); }}static intmx2_mmc_slot_is_empty(int slot){ card_state = SDHC_STATUS(MMC_BASE) & MX2STAT_CARD_PRESENCE; return card_state == 0;}/************************************************************************** * * Hardware initialization * *************************************************************************/static intmx2_mmc_slot_up(void){ int retval; /* MX2 MMC slot hardware init */ mx_module_clk_open(IPG_MODULE_SDHC1); /* Perclock 2 */ /* GPIO */ retval = mx2_register_gpios(PORT_E, (1 << 22) | /* MMC: SD_CMD */ (1 << 23) | /* MMC: SD_CLK */ (1 << 21) | /* MMC: SD_DAT */ (1 << 20) | /* MMC: SD_DAT */ (1 << 19) | /* MMC: SD_DAT */ (1 << 18), /* MMC: SD_DAT */ PRIMARY | NOINTERRUPT); if (retval < 0) goto error; return retval; error: mx2_unregister_gpios(PORT_E, (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) | (1 << 23)); return retval;}static voidmx2_mmc_slot_down(void){ disable_irq(INT_SDHC1); /* Power Off MMC through FPGA */ /* Disable MMC clock and enable HI-Z on the MMC.DAT2 pin */}/* Standard PM functions */static intmx2_mmc_suspend(void){ mx2_gpio_mask_intr(PORT_D, 25); if (mx2_mmc_inserted) { mmc_eject(0); /*set it to be negative level trigger detect card withdraw */ mx2_gpio_config_intr(PORT_D, 25, NEGATIVE_LEVEL, mmcsd_socket1_irq_handler); mx2_mmc_inserted = 0; } mx2_mmc_slot_down(); /*disable MMC IRQ*/ mx2_mmc_stop_clock(); mx_module_clk_close(IPG_MODULE_SDHC1); return 0;}static voidmx2_mmc_resume(void){ mx_module_clk_open(IPG_MODULE_SDHC1); mx2_mmc_set_clock(g_mx2_mmc_data.clock); enable_irq(INT_SDHC1); mx2_gpio_unmask_intr(PORT_D, 25);}#ifdef CONFIG_PMstatic intmx2_mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ switch (req) { case PM_SUSPEND: mx2_mmc_suspend(); break; case PM_RESUME: mx2_mmc_resume(); break; } return 0;}#endif#if 1 /*CEE LDM*/static int__ldm_suspend(struct device *dev, u32 state, u32 level){ switch (level) { case SUSPEND_POWER_DOWN: mx2_mmc_suspend(); break; } return 0;}static int__ldm_resume(struct device *dev, u32 level){ switch (level) { case RESUME_POWER_ON: mx2_mmc_resume(); break; } return 0;}#endifvoidmmcsd_socket1_irq_handler(int irq, void *dev_id, struct pt_regs *regs){ u32 trigger; trigger = mx2_gpio_get_intr_config(PORT_D, 25); if (mx2_gpio_intr_status_bit(PORT_D, 25)) { if (trigger == 2) /* it is positive level now */ { if (mx2_mmc_inserted) { mmc_eject(0); /*set it to be negative level trigger detect card withdraw */ mx2_gpio_config_intr(PORT_D, 25, NEGATIVE_LEVEL, mmcsd_socket1_irq_handler); mx2_mmc_inserted = 0; } } if (trigger == 3) /* it is negative level now */ { if (!mx2_mmc_inserted) { mmc_insert(0); /*set it to be positive level trigger detect card insert */ mx2_gpio_config_intr(PORT_D, 25, POSITIVE_LEVEL, mmcsd_socket1_irq_handler); mx2_mmc_inserted = 1; } } mx2_gpio_clear_intr(PORT_D, 25); }}#define MX2ADS_MMC_MIN_HCLK 33000static intmx2_mmc_slot_init(void){ int retval; long flags;#if 1 /*CEE LDM*/ if (MX2ADS_MMC_MIN_HCLK > mx_module_get_clk(HCLK) / 1000) { printk(KERN_ERR "cannot initialize MMC - HCLK too slow\n"); return -EPERM; }#endif /* Basic service interrupt */ local_irq_save(flags); mx2_mmc_slot_up(); mx2_mmc_softreset(); /* check hardware revision */ if ((SDHC_REV_NO(MMC_BASE) & 0xFFFF) != 0x0400) { printk(KERN_ERR "MMC Hardware revision = 0x%x", SDHC_REV_NO(MMC_BASE)); } mx2_register_gpio(PORT_D, 25, GPIO | INPUT | TRISTATE); mx2_gpio_unmask_intr(PORT_D, 25); /* enable */ mx2_gpio_config_intr(PORT_D, 25, NEGATIVE_LEVEL, mmcsd_socket1_irq_handler); mx2_mmc_inserted = 0; SDHC_INT_MASK(MMC_BASE) = MX2_AUTO_CARD_DETECT_MASK & 0x7f; /* Clear all interrupts */ retval = request_irq(INT_SDHC1, mx2_mmc_int, SA_INTERRUPT, "mx2_mmc_int", &g_mx2_mmc_data); if (retval) { printk(KERN_CRIT "MMC: unable to grab MMC IRQ\n"); return retval; }#ifdef CONFIG_PM pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, mx2_mmc_pm_callback);#endif#if 1 /*CEE LDM*/#ifdef CONFIG_DPM mx2mmc_constraints.param[0].min = MX2ADS_MMC_MIN_HCLK; /*in KHz */ mx2mmc_constraints.param[0].max = mx_module_get_clk(MPLL) / 1000; /* unlimited */#endif mx21_ldm_bus_register(&__device_ldm, &__driver_ldm);#endif local_irq_restore(flags); return retval;}static voidmx2_mmc_slot_cleanup(void){ long flags; local_irq_save(flags); mx2_mmc_slot_down(); free_irq(INT_SDHC1, &g_mx2_mmc_data); mx_module_clk_close(IPG_MODULE_SDHC1); local_irq_restore(flags); mx2_unregister_gpio(PORT_D, 25);#ifdef CONFIG_PM pm_unregister_all(mx2_mmc_pm_callback);#endif#if 1 /*CEE LDM*/ mx21_ldm_bus_unregister(&__device_ldm, &__driver_ldm);#endif}/***********************************************************/static struct mmc_slot_driver dops = { .owner = THIS_MODULE, .name = "MX2 MMC", .ocr = 0x00ffc000, .flags = MMC_SDFLAG_MMC_MODE, .init = mx2_mmc_slot_init, .cleanup = mx2_mmc_slot_cleanup, .is_empty = mx2_mmc_slot_is_empty, .send_cmd = mx2_mmc_send_command, .set_clock = mx2_mmc_set_clock};int __initmx2_mmc_init(void){ int retval; retval = mmc_register_slot_driver(&dops, 1); if (retval < 0) printk(KERN_INFO "MMC: unable to register slot\n"); return retval;}void __exitmx2_mmc_cleanup(void){ mmc_unregister_slot_driver(&dops); mx2_unregister_gpios(PORT_E, (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) | (1 << 23));}module_init(mx2_mmc_init);module_exit(mx2_mmc_cleanup);MODULE_DESCRIPTION("MX2 MMC");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -