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

📄 at91_mci.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		else			at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);	}	return ier;}/* * Wait for a command to complete */static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd){	unsigned int ier;	ier = at91_mci_send_command(host, cmd);	pr_debug("setting ier to %08X\n", ier);	/* Stop on errors or the required value */	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);}/* * Process the next step in the request */static void at91mci_process_next(struct at91mci_host *host){	if (!(host->flags & FL_SENT_COMMAND)) {		host->flags |= FL_SENT_COMMAND;		at91mci_process_command(host, host->request->cmd);	}	else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {		host->flags |= FL_SENT_STOP;		at91mci_process_command(host, host->request->stop);	}	else		mmc_request_done(host->mmc, host->request);}/* * Handle a command that has been completed */static void at91mci_completed_command(struct at91mci_host *host){	struct mmc_command *cmd = host->cmd;	unsigned int status;	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);	cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));	cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));	cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));	cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));	if (host->buffer) {		dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);		host->buffer = NULL;	}	status = at91_mci_read(host, AT91_MCI_SR);	pr_debug("Status = %08X [%08X %08X %08X %08X]\n",		 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);	if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |			AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |			AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {		if ((status & AT91_MCI_RCRCE) &&			((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {			cmd->error = MMC_ERR_NONE;		}		else {			if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))				cmd->error = MMC_ERR_TIMEOUT;			else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))				cmd->error = MMC_ERR_BADCRC;			else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))				cmd->error = MMC_ERR_FIFO;			else				cmd->error = MMC_ERR_FAILED;			pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",				 cmd->error, cmd->opcode, cmd->retries);		}	}	else		cmd->error = MMC_ERR_NONE;	at91mci_process_next(host);}/* * Handle an MMC request */static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq){	struct at91mci_host *host = mmc_priv(mmc);	host->request = mrq;	host->flags = 0;	at91mci_process_next(host);}/* * Set the IOS */static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios){	int clkdiv;	struct at91mci_host *host = mmc_priv(mmc);	unsigned long at91_master_clock = clk_get_rate(host->mci_clk);	host->bus_mode = ios->bus_mode;	if (ios->clock == 0) {		/* Disable the MCI controller */		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);		clkdiv = 0;	}	else {		/* Enable the MCI controller */		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);		if ((at91_master_clock % (ios->clock * 2)) == 0)			clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;		else			clkdiv = (at91_master_clock / ios->clock) / 2;		pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,			at91_master_clock / (2 * (clkdiv + 1)));	}	if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {		pr_debug("MMC: Setting controller bus width to 4\n");		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);	}	else {		pr_debug("MMC: Setting controller bus width to 1\n");		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);	}	/* Set the clock divider */	at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);	/* maybe switch power to the card */	if (host->board->vcc_pin) {		switch (ios->power_mode) {			case MMC_POWER_OFF:				at91_set_gpio_value(host->board->vcc_pin, 0);				break;			case MMC_POWER_UP:			case MMC_POWER_ON:				at91_set_gpio_value(host->board->vcc_pin, 1);				break;		}	}}/* * Handle an interrupt */static irqreturn_t at91_mci_irq(int irq, void *devid){	struct at91mci_host *host = devid;	int completed = 0;	unsigned int int_status, int_mask;	int_status = at91_mci_read(host, AT91_MCI_SR);	int_mask = at91_mci_read(host, AT91_MCI_IMR);		pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,		int_status & int_mask);		int_status = int_status & int_mask;	if (int_status & AT91_MCI_ERRORS) {		completed = 1;				if (int_status & AT91_MCI_UNRE)			pr_debug("MMC: Underrun error\n");		if (int_status & AT91_MCI_OVRE)			pr_debug("MMC: Overrun error\n");		if (int_status & AT91_MCI_DTOE)			pr_debug("MMC: Data timeout\n");		if (int_status & AT91_MCI_DCRCE)			pr_debug("MMC: CRC error in data\n");		if (int_status & AT91_MCI_RTOE)			pr_debug("MMC: Response timeout\n");		if (int_status & AT91_MCI_RENDE)			pr_debug("MMC: Response end bit error\n");		if (int_status & AT91_MCI_RCRCE)			pr_debug("MMC: Response CRC error\n");		if (int_status & AT91_MCI_RDIRE)			pr_debug("MMC: Response direction error\n");		if (int_status & AT91_MCI_RINDE)			pr_debug("MMC: Response index error\n");	} else {		/* Only continue processing if no errors */		if (int_status & AT91_MCI_TXBUFE) {			pr_debug("TX buffer empty\n");			at91_mci_handle_transmitted(host);		}		if (int_status & AT91_MCI_RXBUFF) {			pr_debug("RX buffer full\n");			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);		}		if (int_status & AT91_MCI_ENDTX)			pr_debug("Transmit has ended\n");		if (int_status & AT91_MCI_ENDRX) {			pr_debug("Receive has ended\n");			at91mci_post_dma_read(host);		}		if (int_status & AT91_MCI_NOTBUSY) {			pr_debug("Card is ready\n");			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);		}		if (int_status & AT91_MCI_DTIP)			pr_debug("Data transfer in progress\n");		if (int_status & AT91_MCI_BLKE)			pr_debug("Block transfer has ended\n");		if (int_status & AT91_MCI_TXRDY)			pr_debug("Ready to transmit\n");		if (int_status & AT91_MCI_RXRDY)			pr_debug("Ready to receive\n");		if (int_status & AT91_MCI_CMDRDY) {			pr_debug("Command ready\n");			completed = 1;		}	}	if (completed) {		pr_debug("Completed command\n");		at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);		at91mci_completed_command(host);	} else		at91_mci_write(host, AT91_MCI_IDR, int_status);	return IRQ_HANDLED;}static irqreturn_t at91_mmc_det_irq(int irq, void *_host){	struct at91mci_host *host = _host;	int present = !at91_get_gpio_value(irq);	/*	 * we expect this irq on both insert and remove,	 * and use a short delay to debounce.	 */	if (present != host->present) {		host->present = present;		pr_debug("%s: card %s\n", mmc_hostname(host->mmc),			present ? "insert" : "remove");		if (!present) {			pr_debug("****** Resetting SD-card bus width ******\n");			at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);		}		mmc_detect_change(host->mmc, msecs_to_jiffies(100));	}	return IRQ_HANDLED;}static int at91_mci_get_ro(struct mmc_host *mmc){	int read_only = 0;	struct at91mci_host *host = mmc_priv(mmc);	if (host->board->wp_pin) {		read_only = at91_get_gpio_value(host->board->wp_pin);		printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),				(read_only ? "read-only" : "read-write") );	}	else {		printk(KERN_WARNING "%s: host does not support reading read-only "				"switch.  Assuming write-enable.\n", mmc_hostname(mmc));	}	return read_only;}static const struct mmc_host_ops at91_mci_ops = {	.request	= at91_mci_request,	.set_ios	= at91_mci_set_ios,	.get_ro		= at91_mci_get_ro,};/* * Probe for the device */static int __init at91_mci_probe(struct platform_device *pdev){	struct mmc_host *mmc;	struct at91mci_host *host;	struct resource *res;	int ret;	pr_debug("Probe MCI devices\n");	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (!res)		return -ENXIO;	if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))		return -EBUSY;	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);	if (!mmc) {		pr_debug("Failed to allocate mmc host\n");		release_mem_region(res->start, res->end - res->start + 1);		return -ENOMEM;	}	mmc->ops = &at91_mci_ops;	mmc->f_min = 375000;	mmc->f_max = 25000000;	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;	mmc->caps = MMC_CAP_BYTEBLOCK;	host = mmc_priv(mmc);	host->mmc = mmc;	host->buffer = NULL;	host->bus_mode = 0;	host->board = pdev->dev.platform_data;	if (host->board->wire4) {#ifdef SUPPORT_4WIRE		mmc->caps |= MMC_CAP_4_BIT_DATA;#else		printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");#endif	}	/*	 * Get Clock	 */	host->mci_clk = clk_get(&pdev->dev, "mci_clk");	if (IS_ERR(host->mci_clk)) {		printk(KERN_ERR "AT91 MMC: no clock defined.\n");		mmc_free_host(mmc);		release_mem_region(res->start, res->end - res->start + 1);		return -ENODEV;	}	/*	 * Map I/O region	 */	host->baseaddr = ioremap(res->start, res->end - res->start + 1);	if (!host->baseaddr) {		clk_put(host->mci_clk);		mmc_free_host(mmc);		release_mem_region(res->start, res->end - res->start + 1);		return -ENOMEM;	}	/*	 * Reset hardware	 */	clk_enable(host->mci_clk);		/* Enable the peripheral clock */	at91_mci_disable(host);	at91_mci_enable(host);	/*	 * Allocate the MCI interrupt	 */	host->irq = platform_get_irq(pdev, 0);	ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);	if (ret) {		printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");		clk_disable(host->mci_clk);		clk_put(host->mci_clk);		mmc_free_host(mmc);		iounmap(host->baseaddr);		release_mem_region(res->start, res->end - res->start + 1);		return ret;	}	platform_set_drvdata(pdev, mmc);	/*	 * Add host to MMC layer	 */	if (host->board->det_pin)		host->present = !at91_get_gpio_value(host->board->det_pin);	else		host->present = -1;	mmc_add_host(mmc);	/*	 * monitor card insertion/removal if we can	 */	if (host->board->det_pin) {		ret = request_irq(host->board->det_pin, at91_mmc_det_irq,				0, DRIVER_NAME, host);		if (ret)			printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");	}	pr_debug("Added MCI driver\n");	return 0;}/* * Remove a device */static int __exit at91_mci_remove(struct platform_device *pdev){	struct mmc_host *mmc = platform_get_drvdata(pdev);	struct at91mci_host *host;	struct resource *res;	if (!mmc)		return -1;	host = mmc_priv(mmc);	if (host->present != -1) {		free_irq(host->board->det_pin, host);		cancel_delayed_work(&host->mmc->detect);	}	at91_mci_disable(host);	mmc_remove_host(mmc);	free_irq(host->irq, host);	clk_disable(host->mci_clk);			/* Disable the peripheral clock */	clk_put(host->mci_clk);	iounmap(host->baseaddr);	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	release_mem_region(res->start, res->end - res->start + 1);	mmc_free_host(mmc);	platform_set_drvdata(pdev, NULL);	pr_debug("MCI Removed\n");	return 0;}#ifdef CONFIG_PMstatic int at91_mci_suspend(struct platform_device *pdev, pm_message_t state){	struct mmc_host *mmc = platform_get_drvdata(pdev);	int ret = 0;	if (mmc)		ret = mmc_suspend_host(mmc, state);	return ret;}static int at91_mci_resume(struct platform_device *pdev){	struct mmc_host *mmc = platform_get_drvdata(pdev);	int ret = 0;	if (mmc)		ret = mmc_resume_host(mmc);	return ret;}#else#define at91_mci_suspend	NULL#define at91_mci_resume		NULL#endifstatic struct platform_driver at91_mci_driver = {	.remove		= __exit_p(at91_mci_remove),	.suspend	= at91_mci_suspend,	.resume		= at91_mci_resume,	.driver		= {		.name	= DRIVER_NAME,		.owner	= THIS_MODULE,	},};static int __init at91_mci_init(void){	return platform_driver_probe(&at91_mci_driver, at91_mci_probe);}static void __exit at91_mci_exit(void){	platform_driver_unregister(&at91_mci_driver);}module_init(at91_mci_init);module_exit(at91_mci_exit);MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");MODULE_AUTHOR("Nick Randell");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -