📄 pxa3xx_controller.c
字号:
queue_delayed_work(pxa_host->work_queue, &pxa_slot->card_change, 20); return IRQ_HANDLED; }#if 0static int pxa_slot_work_thread(void *data){ struct mss_slot *slot = data; struct pxa_slot *pxa_slot = slot->private; DECLARE_WAITQUEUE(wait, current); current->flags |= PF_MEMALLOC; daemonize("pxaslot%d.%d", slot->host->id, slot->id); complete(&pxa_slot->thread_complete); down(&pxa_slot->thread_sem); add_wait_queue(&pxa_slot->thread_wq, &wait); do { try_to_freeze(); if (pxa_slot->flags & PXA_SLOT_SCAN) { pxa_slot->flags &= ~PXA_SLOT_SCAN; mss_scan_slot(slot); } set_current_state(TASK_INTERRUPTIBLE); if (pxa_slot->flags & PXA_SLOT_EXIT) break; up(&pxa_slot->thread_sem); schedule(); down(&pxa_slot->thread_sem); set_current_state(TASK_RUNNING); } while(1); remove_wait_queue(&pxa_slot->thread_wq, &wait); up(&pxa_slot->thread_sem); complete_and_exit(&pxa_slot->thread_complete, 0);}#endifstatic void pxa_slot_card_change(struct work_struct *work){ struct pxa_slot *pxa_slot = container_of(work, struct pxa_slot, card_change.work); struct mss_slot *slot = pxa_slot->slot; struct mss_card *card = slot->card; while (card && card->state == MSS_CARD_SUSPENDED) schedule_timeout(20); mss_scan_slot(slot);}/* init slot, request IRQ for slot, register mss_slot to core, initialize card * if inserted */static int pxa_slot_init(struct pxa_mss_host *pxa_host, int slotid){ struct mss_slot *slot; struct pxa_slot *pxa_slot; struct mss_host *host = pxa_host->host; int ret = 0; int irq; slot = &host->slots[slotid]; pxa_slot = slot->private; pxa_slot->slot = slot; INIT_DELAYED_WORK(&pxa_slot->card_change, (void (*)(void *))pxa_slot_card_change); irq = get_slot_cd_irq(slot);// printk("%s:+++++irq %d\n", __FUNCTION__, irq); if (!irq) { printk(KERN_INFO "no card detect IRQ for MMC%d, slot:%d.\n", host->id + 1, slotid); goto skip_cd_irq; } ret = request_irq(irq, pxa_slot_gpio_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "MMC card detection", (void *)slot); if (ret) { printk(KERN_ERR "MMC:%d, slot%d, request irq %d fails," " ret: %d\n", host->id, slotid, irq, ret); goto exit; } dbg("request IRQ %d for host%d, slot%d", irq, host->id, slot->id);skip_cd_irq: mss_scan_slot(slot); return 0;exit: return ret;}/** * cleanup a slot, unregister mss_slot form core, free IRQ of slot, * free mss_slot */static void pxa_slot_exit(struct mss_slot *slot){/* pxa_slot->flags = PXA_SLOT_EXIT; wake_up(&pxa_slot->thread_wq); wait_for_completion(&pxa_slot->thread_complete);*/ if (slot->card) mss_force_card_remove(slot->card); free_irq(get_slot_cd_irq(slot), slot);}#ifdef CONFIG_MACH_ZYLONITEstatic void pxa_mss_host_init(struct pxa_mss_host *pxa_host){ struct mss_host *host = pxa_host->host; pxa_host->base = PXA_HOST_BASE[pxa_host->host->id]; pxa_host->phybase = PXA_HOST_PHYBASE[pxa_host->host->id]; pxa_host->cken = PXA_HOST_CKEN[pxa_host->host->id]; pxa_set_cken(pxa_host->cken, 1); if (pxa_host->host->id == PXA_MMC_1) { pxa3xx_gpio_set_direction(MFP_MMC_CMD_0, GPIO_DIR_OUT); pxa3xx_gpio_set_level(MFP_MMC_CMD_0, GPIO_LEVEL_HIGH);// pxa3xx_gpio_set_direction(MFP_MMC_CMD_1, GPIO_DIR_OUT);// pxa3xx_gpio_set_level(MFP_MMC_CMD_1, GPIO_LEVEL_HIGH); /* set direction of CD/WP to IN */ pxa3xx_gpio_set_direction(MFP_MMC_CD, GPIO_DIR_IN); pxa3xx_gpio_set_direction(MFP_MMC_WP, GPIO_DIR_IN); set_slot_cd_irq(&host->slots[0], MMC_CD0); set_slot_cd_gpio(&host->slots[0], MFP_MMC_CD); set_slot_wp_gpio(&host->slots[0], MFP_MMC_WP);/****************************************************************** if (PXA_HOST_SLOTS[PXA_MMC_1] > 1) { pxa3xx_gpio_set_direction(MFP_MMC_CD_1_GPIO, GPIO_DIR_IN); pxa3xx_gpio_set_direction(MFP_MMC_WP_1_N_GPIO,GPIO_DIR_IN); set_slot_cd_irq(&host->slots[1], MMC_CD1); set_slot_cd_gpio(&host->slots[1], MFP_MMC_CD_1_GPIO); set_slot_wp_gpio(&host->slots[1], MFP_MMC_WP_1_N_GPIO); }******************************************************************/ } else if (pxa_host->host->id == PXA_MMC_2) {// pxa3xx_gpio_set_direction(MFP_MMC2_CMD, GPIO_DIR_OUT);// pxa3xx_gpio_set_level(MFP_MMC2_CMD, GPIO_LEVEL_HIGH);// // set_slot_cd_irq(&host->slots[0], 0);// set_slot_cd_gpio(&host->slots[0], 0);// set_slot_wp_gpio(&host->slots[0], 0); }#ifdef CONFIG_CPU_PXA310 else if (pxa_host->host->id == PXA_MMC_3) { pxa3xx_gpio_set_direction(MFP_MMC3_CMD, GPIO_DIR_OUT); pxa3xx_gpio_set_level(MFP_MMC3_CMD, GPIO_LEVEL_HIGH); /* set direction of CD/WP to IN */ pxa3xx_gpio_set_direction(MFP_MMC_CD_3_GPIO, GPIO_DIR_IN); pxa3xx_gpio_set_direction(MFP_MMC_WP_3_N_GPIO, GPIO_DIR_IN); set_slot_cd_irq(&host->slots[0], MMC_CD3); set_slot_cd_gpio(&host->slots[0], MFP_MMC_CD_3_GPIO); set_slot_wp_gpio(&host->slots[0], MFP_MMC_WP_3_N_GPIO); }#endif writel(CLKRT_0_304MHZ, pxa_host->base + MMC_CLKRT); writel(RES_TIMEOUT_MAX, pxa_host->base + MMC_RESTO); writel(RD_TIMEOUT_MAX, pxa_host->base + MMC_RDTO); writel(MMC_MASK_ALL, pxa_host->base + MMC_I_MASK); writel(0, pxa_host->base + MMC_SPI); pxa_host_start_busclock(pxa_host);}#elif defined(CONFIG_MACH_LITTLETON)static void pxa_mss_host_init(struct pxa_mss_host *pxa_host){ struct mss_host *host = pxa_host->host; pxa_host->base = PXA_HOST_BASE[pxa_host->host->id]; pxa_host->phybase = PXA_HOST_PHYBASE[pxa_host->host->id]; pxa_host->cken = PXA_HOST_CKEN[pxa_host->host->id]; pxa_set_cken(pxa_host->cken, 1);// printk(KERN_INFO"entering %s host->id 0x%d\n", __FUNCTION__, pxa_host->host->id); if (pxa_host->host->id == PXA_MMC_1) { // pxa3xx_gpio_set_direction(MFP_MMC_CMD_0, GPIO_DIR_OUT);// pxa3xx_gpio_set_level(MFP_MMC_CMD_0, GPIO_LEVEL_HIGH); /* set direction of CD to IN */ pxa3xx_gpio_set_direction(MFP_MMC_CD, GPIO_DIR_IN); pxa3xx_gpio_set_direction(MFP_MMC_WP, GPIO_DIR_IN); set_slot_cd_irq(&host->slots[0], MMC_CD0); set_slot_cd_gpio(&host->slots[0], MFP_MMC_CD); set_slot_wp_gpio(&host->slots[0], MFP_MMC_WP); } else if (pxa_host->host->id == PXA_MMC_2) { pxa3xx_gpio_set_direction(MFP_MMC2_CMD, GPIO_DIR_OUT); pxa3xx_gpio_set_level(MFP_MMC2_CMD, GPIO_LEVEL_HIGH); set_slot_cd_irq(&host->slots[0], 0); set_slot_cd_gpio(&host->slots[0], 0); set_slot_wp_gpio(&host->slots[0], 0); }#ifdef CONFIG_CPU_PXA310 else if (pxa_host->host->id == PXA_MMC_3) { pxa3xx_gpio_set_direction(MFP_MMC3_CMD, GPIO_DIR_OUT); pxa3xx_gpio_set_level(MFP_MMC3_CMD, GPIO_LEVEL_HIGH); }#endif writel(CLKRT_0_304MHZ, pxa_host->base + MMC_CLKRT); writel(RES_TIMEOUT_MAX, pxa_host->base + MMC_RESTO); writel(RD_TIMEOUT_MAX, pxa_host->base + MMC_RDTO); writel(MMC_MASK_ALL, pxa_host->base + MMC_I_MASK); writel(0, pxa_host->base + MMC_SPI); pxa_host_start_busclock(pxa_host);}#else#error "Please select correct platform for build"#endifstatic struct mss_host_ops pxa_mss_host_ops = { .enable_sdio_int= pxa_mss_enable_sdio_int, .request = pxa_mss_handle_request, .set_ios = pxa_mss_set_ios, .is_slot_empty = pxa_mss_slot_is_empty, .is_slot_wp = pxa_mss_slot_is_wp,};/** * pxa_mss_controller_probe * @dev: device * * init controller, request CTROLLER IRQ, request DMA IRQ, create controller * threads, invoke slot_init */#ifdef CONFIG_MACH_ZYLONITE#define PXA_IOS_VDD MSS_VDD_32_33#elif defined (CONFIG_MACH_LITTLETON)#define PXA_IOS_VDD MSS_VDD_28_29#else#error "Please select correct platform for build"#endifstatic int pxa_mss_host_probe(struct device *dev){ int ret = 0, i = 0; struct platform_device *pdev; struct pxa_mss_host *pxa_host; struct mss_host *host; pdev = to_platform_device(dev); printk(KERN_INFO"%s pdev_id %d name:%s\n", __FUNCTION__, pdev->id, pdev->name); if (pdev->id > PXA_MMC_MAX) return -ENODEV; host = mss_alloc_host(PXA_HOST_SLOTS[pdev->id], \ pdev->id, sizeof(struct pxa_mss_host) + \ PXA_HOST_SLOTS[pdev->id] * sizeof(struct pxa_slot)); if (NULL == host) return -ENOMEM; pxa_host = (struct pxa_mss_host *)host->private; pxa_host->host = host; pxa_host->irq = PXA_HOST_IRQ[pdev->id]; pxa_host->dat1_gpio_irq = 0; pxa_host->drcmrtx = PXA_HOST_DRCMRTX[pdev->id]; pxa_host->drcmrrx = PXA_HOST_DRCMRRX[pdev->id]; pxa_host->dma_run = 0;// printk(KERN_INFO"%s irq: %d\n", __FUNCTION__, pxa_host->irq); /* Set host to be 3.2V */#ifdef CONFIG_MACH_ZYLONITE pxa3xx_pmic_set_voltage(VCC_SDIO, 3200);#endif host->dev = dev; host->ops = &pxa_mss_host_ops; host->vdd = host->ios.vdd = PXA_IOS_VDD; host->bus_width = MSS_BUSWIDTH_4BIT; host->ios.bus_width = MSS_BUSWIDTH_1BIT; host->f_min = 304000; host->f_max = 26000000; host->sd_spec = MSS_SD_SPEC_20; host->mmc_spec = MSS_MMC_SPEC_40_42; host->sdio_spec = MSS_SDIO_SPEC_11; host->high_capacity = 1; host->max_phys_segs = 32; host->max_hw_segs = 32; host->max_sectors = 256; host->max_seg_size = 0x1000; for (i = 0; i < PXA_HOST_SLOTS[pdev->id]; i++) { host->slots[i].private = (void *)((unsigned int)(&pxa_host[1]) + i * sizeof(struct pxa_slot)); dbg("host:%d, slot%d, private:0x%x", host->id, host->slots[i].id, host->slots[i].private); } pxa_mss_host_init(pxa_host);#ifdef CONFIG_PXA_MWB_12 if (pxa_host->host->id == PXA_MMC_2) { pxa3xx_enable_pxa_mwb_wifi(); }#endif ret = register_mss_host(host); if (ret) { printk(KERN_ERR "register_mss_host error! ret: %d.\n", ret); goto free_host; } /* request controller IRQ */ ret = request_irq(pxa_host->irq, pxa_host_irq, 0, \ "Monahans-P MMC/SD/SDIO Controller", (void *)pxa_host); if (ret < 0) { printk(KERN_ERR "MMC%d request_irq error! ret: %d.\n", pdev->id, ret); goto unregister_host; } /* request DMA IRQ */ pxa_host->dma = pxa_request_dma("Monahans mmc", DMA_PRIO_LOW, pxa_host_dma_irq, (void *)pxa_host); dbg("DMA channel : %d, %x\n", pxa_host->dma, (u32)&pxa_host->dma); if (pxa_host->dma < 0) { ret = -EBUSY; printk(KERN_ERR "MMC%d request_dma error! ret: %d.\n", pdev->id, ret); goto free_host_irq; } pxa_host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &pxa_host->sg_dma, GFP_KERNEL); if (!pxa_host->sg_cpu) { ret = -ENOMEM; goto free_dma_irq; } sprintf(pxa_host->name, "PXA HOST %d", host->id); sprintf(pxa_host->name2, "SDIO INT PXA HOST %d", host->id); pxa_host->work_queue = create_workqueue(pxa_host->name); pxa_host->sdio_work_queue = create_workqueue(pxa_host->name2); for(i = 0; i < PXA_HOST_SLOTS[pdev->id]; i++) { ret = pxa_slot_init(pxa_host, i); if (ret) goto free_slot; } #ifdef CONFIG_DVFM pxa_host->dvfm_notifier.name = pxa_host->name; pxa_host->dvfm_notifier.priority = 0, pxa_host->dvfm_notifier.notifier_call = pxa3xx_mmc_dvfm_notifier; pxa_host->dvfm_notifier.client_data = pxa_host; pxa3xx_fv_register_notifier(&(pxa_host->dvfm_notifier));#endif// printk(KERN_ERR "%s: over.\n", __FUNCTION__); return 0;free_slot: while (--i >= 0) { pxa_slot_exit(&host->slots[i]); }free_dma_irq: /* release DMA IRQ */ pxa_free_dma(pxa_host->dma);free_host_irq: /* release controller IRQ */ free_irq(pxa_host->irq, pxa_host);unregister_host: unregister_mss_host(host);free_host: mss_free_host(host); return ret;}/** * pxa_mss_controller_remove * @dev: device * * cleanup controller, free CTROLLER IRQ, free DMA IRQ, destroy controller * threads, invoke slot_exit */static int pxa_mss_host_remove(struct device *dev){ int ret = 0, i; struct platform_device *pdev; struct mss_host *host; struct pxa_mss_host *pxa_host; pdev = to_platform_device(dev); host = mss_find_host(pdev->id); if (!host) return -ENODEV; pxa_host = (struct pxa_mss_host *)host->private;#ifdef CONFIG_DVFM pxa3xx_fv_unregister_notifier(&(pxa_host->dvfm_notifier));#endif destroy_workqueue(pxa_host->work_queue); destroy_workqueue(pxa_host->sdio_work_queue); free_irq(pxa_host->irq, pxa_host); pxa_free_dma(pxa_host->dma); dma_free_coherent(dev, PAGE_SIZE, pxa_host->sg_cpu, pxa_host->sg_dma); for (i = 0; i < host->slot_num; i++) { pxa_slot_exit(&host->slots[i]); } unregister_mss_host(host); mss_free_host(host); return ret;}static void pxa_mss_host_shutdown(struct device *dev){ return;}/** * pxa_mss_controller_suspend * @dev: device * @state: suspend state * @level: suspend level */static int pxa_mss_host_suspend(struct device *dev, pm_message_t state){ struct platform_device *pdev; struct pxa_mss_host *pxa_host; struct mss_host *host; pdev = to_platform_device(dev); host = mss_find_host(pdev->id); pxa_host = host->private; pxa_set_cken(pxa_host->cken, 0); return 0;}/** * pxa_mss_controller_resume * @dev: device */extern int mss_init_card(struct mss_card *card);static int pxa_mss_host_resume(struct device *dev){ struct platform_device *pdev; struct pxa_mss_host *pxa_host; struct mss_host *host; int i, ret; struct mss_ios ios; pdev = to_platform_device(dev); host = mss_find_host(pdev->id); pxa_host = host->private; pxa_mss_host_init(pxa_host); memcpy(&ios, &host->ios, sizeof(struct mss_ios)); memset(&host->ios, 0x0, sizeof(struct mss_ios)); pxa_mss_set_ios(host, &ios); if (host->sdio_int) { writel(0x0, pxa_host->base + MMC_CMD); writel(MMC_CMDAT_SDIO_INT, pxa_host->base + MMC_CMDAT); } pxa_mss_enable_sdio_int(host, host->sdio_int); for (i = 0; i < host->slot_num; i++) { struct mss_slot *slot = &host->slots[i]; if (slot->card && slot->card->card_type == MSS_SDIO_CARD) {#ifdef CONFIG_PXA_MWB_12 int retry = 0;#define MAX_RETRY 5 pxa3xx_enable_pxa_mwb_wifi(); do { ret = mss_init_card(slot->card); } while(ret && MAX_RETRY > retry++); if (!ret) slot->card->state |= MSS_CARD_INITED;#endif return 0; } ret = mss_scan_slot(slot); if (ret) { /* == MSS_ERROR_MISMATCH_CARD) { */ struct pxa_slot *pxa_slot = slot->private; queue_delayed_work(pxa_host->work_queue, &pxa_slot->card_change, 20); } } return 0;}/***************************************************************************** * * object instances * ****************************************************************************/static struct device_driver pxa_mss_host_driver = { .name = "mmc_controller", .bus = &platform_bus_type, .probe = pxa_mss_host_probe, .remove = pxa_mss_host_remove, .shutdown = pxa_mss_host_shutdown, .suspend = pxa_mss_host_suspend, .resume = pxa_mss_host_resume,};static int pxa_mss_host_driver_init(void){ int ret; /* register controller driver to PLATFORM bus */ ret = driver_register(&pxa_mss_host_driver); if (ret) return ret; return ret; }static void pxa_mss_host_driver_exit(void){ driver_unregister(&pxa_mss_host_driver);}module_init(pxa_mss_host_driver_init);module_exit(pxa_mss_host_driver_exit);MODULE_AUTHOR("Bridge Wu");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Controller driver for MMC/SD/SDIO card");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -