⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pxa3xx_controller.c

📁 基于PXA3XX的SD驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -