tifm_sd.c

来自「linux 内核源代码」· C语言 代码 · 共 1,096 行 · 第 1/2 页

C
1,096
字号
			} else				cmd->error = cmd_error;		} else {			if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {				if (!(host->cmd_flags & CMD_READY)) {					host->cmd_flags |= CMD_READY;					tifm_sd_fetch_resp(cmd, sock);				} else if (host->cmd_flags & SCMD_ACTIVE) {					host->cmd_flags |= SCMD_READY;					tifm_sd_fetch_resp(host->req->stop,							   sock);				}			}			if (host_status & TIFM_MMCSD_BRS)				host->cmd_flags |= BRS_READY;		}		if (host->no_dma && cmd->data) {			if (host_status & TIFM_MMCSD_AE)				writel(host_status & TIFM_MMCSD_AE,				       sock->addr + SOCK_MMCSD_STATUS);			if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF					   | TIFM_MMCSD_BRS)) {				local_irq_save(flags);				tifm_sd_transfer_data(host);				local_irq_restore(flags);				host_status &= ~TIFM_MMCSD_AE;			}		}		if (host_status & TIFM_MMCSD_EOFB)			host->cmd_flags &= ~CARD_BUSY;		else if (host_status & TIFM_MMCSD_CB)			host->cmd_flags |= CARD_BUSY;		tifm_sd_check_status(host);	}done:	writel(host_status, sock->addr + SOCK_MMCSD_STATUS);	spin_unlock(&sock->lock);}static void tifm_sd_set_data_timeout(struct tifm_sd *host,				     struct mmc_data *data){	struct tifm_dev *sock = host->dev;	unsigned int data_timeout = data->timeout_clks;	if (fixed_timeout)		return;	data_timeout += data->timeout_ns /			((1000000000UL / host->clk_freq) * host->clk_div);	if (data_timeout < 0xffff) {		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);		writel((~TIFM_MMCSD_DPE)		       & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);	} else {		data_timeout = (data_timeout >> 10) + 1;		if (data_timeout > 0xffff)			data_timeout = 0;	/* set to unlimited */		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);		writel(TIFM_MMCSD_DPE		       | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);	}}static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq){	struct tifm_sd *host = mmc_priv(mmc);	struct tifm_dev *sock = host->dev;	unsigned long flags;	struct mmc_data *r_data = mrq->cmd->data;	spin_lock_irqsave(&sock->lock, flags);	if (host->eject) {		mrq->cmd->error = -ENOMEDIUM;		goto err_out;	}	if (host->req) {		printk(KERN_ERR "%s : unfinished request detected\n",		       sock->dev.bus_id);		mrq->cmd->error = -ETIMEDOUT;		goto err_out;	}	host->cmd_flags = 0;	host->block_pos = 0;	host->sg_pos = 0;	if (mrq->data && !is_power_of_2(mrq->data->blksz))		host->no_dma = 1;	else		host->no_dma = no_dma ? 1 : 0;	if (r_data) {		tifm_sd_set_data_timeout(host, r_data);		if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)			 writel(TIFM_MMCSD_EOFB				| readl(sock->addr + SOCK_MMCSD_INT_ENABLE),				sock->addr + SOCK_MMCSD_INT_ENABLE);		if (host->no_dma) {			writel(TIFM_MMCSD_BUFINT			       | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),			       sock->addr + SOCK_MMCSD_INT_ENABLE);			writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)			       | (TIFM_MMCSD_FIFO_SIZE - 1),			       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);			host->sg_len = r_data->sg_len;		} else {			sg_init_one(&host->bounce_buf, host->bounce_buf_data,				    r_data->blksz);			if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,					    r_data->flags & MMC_DATA_WRITE					    ? PCI_DMA_TODEVICE					    : PCI_DMA_FROMDEVICE)) {				printk(KERN_ERR "%s : scatterlist map failed\n",				       sock->dev.bus_id);				mrq->cmd->error = -ENOMEM;				goto err_out;			}			host->sg_len = tifm_map_sg(sock, r_data->sg,						   r_data->sg_len,						   r_data->flags						   & MMC_DATA_WRITE						   ? PCI_DMA_TODEVICE						   : PCI_DMA_FROMDEVICE);			if (host->sg_len < 1) {				printk(KERN_ERR "%s : scatterlist map failed\n",				       sock->dev.bus_id);				tifm_unmap_sg(sock, &host->bounce_buf, 1,					      r_data->flags & MMC_DATA_WRITE					      ? PCI_DMA_TODEVICE					      : PCI_DMA_FROMDEVICE);				mrq->cmd->error = -ENOMEM;				goto err_out;			}			writel(TIFM_FIFO_INT_SETALL,			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);			writel(ilog2(r_data->blksz) - 2,			       sock->addr + SOCK_FIFO_PAGE_SIZE);			writel(TIFM_FIFO_ENABLE,			       sock->addr + SOCK_FIFO_CONTROL);			writel(TIFM_FIFO_INTMASK,			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);			if (r_data->flags & MMC_DATA_WRITE)				writel(TIFM_MMCSD_TXDE,				       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);			else				writel(TIFM_MMCSD_RXDE,				       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);			tifm_sd_set_dma_data(host, r_data);		}		writel(r_data->blocks - 1,		       sock->addr + SOCK_MMCSD_NUM_BLOCKS);		writel(r_data->blksz - 1,		       sock->addr + SOCK_MMCSD_BLOCK_LEN);	}	host->req = mrq;	mod_timer(&host->timer, jiffies + host->timeout_jiffies);	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),	       sock->addr + SOCK_CONTROL);	tifm_sd_exec(host, mrq->cmd);	spin_unlock_irqrestore(&sock->lock, flags);	return;err_out:	spin_unlock_irqrestore(&sock->lock, flags);	mmc_request_done(mmc, mrq);}static void tifm_sd_end_cmd(unsigned long data){	struct tifm_sd *host = (struct tifm_sd*)data;	struct tifm_dev *sock = host->dev;	struct mmc_host *mmc = tifm_get_drvdata(sock);	struct mmc_request *mrq;	struct mmc_data *r_data = NULL;	unsigned long flags;	spin_lock_irqsave(&sock->lock, flags);	del_timer(&host->timer);	mrq = host->req;	host->req = NULL;	if (!mrq) {		printk(KERN_ERR " %s : no request to complete?\n",		       sock->dev.bus_id);		spin_unlock_irqrestore(&sock->lock, flags);		return;	}	r_data = mrq->cmd->data;	if (r_data) {		if (host->no_dma) {			writel((~TIFM_MMCSD_BUFINT)			       & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),			       sock->addr + SOCK_MMCSD_INT_ENABLE);		} else {			tifm_unmap_sg(sock, &host->bounce_buf, 1,				      (r_data->flags & MMC_DATA_WRITE)				      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);			tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,				      (r_data->flags & MMC_DATA_WRITE)				      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);		}		r_data->bytes_xfered = r_data->blocks			- readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;		r_data->bytes_xfered *= r_data->blksz;		r_data->bytes_xfered += r_data->blksz			- readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;	}	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),	       sock->addr + SOCK_CONTROL);	spin_unlock_irqrestore(&sock->lock, flags);	mmc_request_done(mmc, mrq);}static void tifm_sd_abort(unsigned long data){	struct tifm_sd *host = (struct tifm_sd*)data;	printk(KERN_ERR	       "%s : card failed to respond for a long period of time "	       "(%x, %x)\n",	       host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags);	tifm_eject(host->dev);}static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios){	struct tifm_sd *host = mmc_priv(mmc);	struct tifm_dev *sock = host->dev;	unsigned int clk_div1, clk_div2;	unsigned long flags;	spin_lock_irqsave(&sock->lock, flags);	dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, "		"chip_select = %x, power_mode = %x, bus_width = %x\n",		ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,		ios->power_mode, ios->bus_width);	if (ios->bus_width == MMC_BUS_WIDTH_4) {		writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),		       sock->addr + SOCK_MMCSD_CONFIG);	} else {		writel((~TIFM_MMCSD_4BBUS)		       & readl(sock->addr + SOCK_MMCSD_CONFIG),		       sock->addr + SOCK_MMCSD_CONFIG);	}	if (ios->clock) {		clk_div1 = 20000000 / ios->clock;		if (!clk_div1)			clk_div1 = 1;		clk_div2 = 24000000 / ios->clock;		if (!clk_div2)			clk_div2 = 1;		if ((20000000 / clk_div1) > ios->clock)			clk_div1++;		if ((24000000 / clk_div2) > ios->clock)			clk_div2++;		if ((20000000 / clk_div1) > (24000000 / clk_div2)) {			host->clk_freq = 20000000;			host->clk_div = clk_div1;			writel((~TIFM_CTRL_FAST_CLK)			       & readl(sock->addr + SOCK_CONTROL),			       sock->addr + SOCK_CONTROL);		} else {			host->clk_freq = 24000000;			host->clk_div = clk_div2;			writel(TIFM_CTRL_FAST_CLK			       | readl(sock->addr + SOCK_CONTROL),			       sock->addr + SOCK_CONTROL);		}	} else {		host->clk_div = 0;	}	host->clk_div &= TIFM_MMCSD_CLKMASK;	writel(host->clk_div	       | ((~TIFM_MMCSD_CLKMASK)		  & readl(sock->addr + SOCK_MMCSD_CONFIG)),	       sock->addr + SOCK_MMCSD_CONFIG);	host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);	/* chip_select : maybe later */	//vdd	//power is set before probe / after remove	spin_unlock_irqrestore(&sock->lock, flags);}static int tifm_sd_ro(struct mmc_host *mmc){	int rc = 0;	struct tifm_sd *host = mmc_priv(mmc);	struct tifm_dev *sock = host->dev;	unsigned long flags;	spin_lock_irqsave(&sock->lock, flags);	if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))		rc = 1;	spin_unlock_irqrestore(&sock->lock, flags);	return rc;}static const struct mmc_host_ops tifm_sd_ops = {	.request = tifm_sd_request,	.set_ios = tifm_sd_ios,	.get_ro  = tifm_sd_ro};static int tifm_sd_initialize_host(struct tifm_sd *host){	int rc;	unsigned int host_status = 0;	struct tifm_dev *sock = host->dev;	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);	mmiowb();	host->clk_div = 61;	host->clk_freq = 20000000;	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);	writel(host->clk_div | TIFM_MMCSD_POWER,	       sock->addr + SOCK_MMCSD_CONFIG);	/* wait up to 0.51 sec for reset */	for (rc = 32; rc <= 256; rc <<= 1) {		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {			rc = 0;			break;		}		msleep(rc);	}	if (rc) {		printk(KERN_ERR "%s : controller failed to reset\n",		       sock->dev.bus_id);		return -ENODEV;	}	writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);	writel(host->clk_div | TIFM_MMCSD_POWER,	       sock->addr + SOCK_MMCSD_CONFIG);	writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);	// command timeout fixed to 64 clocks for now	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);	for (rc = 16; rc <= 64; rc <<= 1) {		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);		if (!(host_status & TIFM_MMCSD_ERRMASK)		    && (host_status & TIFM_MMCSD_EOC)) {			rc = 0;			break;		}		msleep(rc);	}	if (rc) {		printk(KERN_ERR		       "%s : card not ready - probe failed on initialization\n",		       sock->dev.bus_id);		return -ENODEV;	}	writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC	       | TIFM_MMCSD_ERRMASK,	       sock->addr + SOCK_MMCSD_INT_ENABLE);	mmiowb();	return 0;}static int tifm_sd_probe(struct tifm_dev *sock){	struct mmc_host *mmc;	struct tifm_sd *host;	int rc = -EIO;	if (!(TIFM_SOCK_STATE_OCCUPIED	      & readl(sock->addr + SOCK_PRESENT_STATE))) {		printk(KERN_WARNING "%s : card gone, unexpectedly\n",		       sock->dev.bus_id);		return rc;	}	mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);	if (!mmc)		return -ENOMEM;	host = mmc_priv(mmc);	tifm_set_drvdata(sock, mmc);	host->dev = sock;	host->timeout_jiffies = msecs_to_jiffies(1000);	tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,		     (unsigned long)host);	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);	mmc->ops = &tifm_sd_ops;	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;	mmc->f_min = 20000000 / 60;	mmc->f_max = 24000000;	mmc->max_blk_count = 2048;	mmc->max_hw_segs = mmc->max_blk_count;	mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);	mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;	mmc->max_req_size = mmc->max_seg_size;	mmc->max_phys_segs = mmc->max_hw_segs;	sock->card_event = tifm_sd_card_event;	sock->data_event = tifm_sd_data_event;	rc = tifm_sd_initialize_host(host);	if (!rc)		rc = mmc_add_host(mmc);	if (!rc)		return 0;	mmc_free_host(mmc);	return rc;}static void tifm_sd_remove(struct tifm_dev *sock){	struct mmc_host *mmc = tifm_get_drvdata(sock);	struct tifm_sd *host = mmc_priv(mmc);	unsigned long flags;	spin_lock_irqsave(&sock->lock, flags);	host->eject = 1;	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);	mmiowb();	spin_unlock_irqrestore(&sock->lock, flags);	tasklet_kill(&host->finish_tasklet);	spin_lock_irqsave(&sock->lock, flags);	if (host->req) {		writel(TIFM_FIFO_INT_SETALL,		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);		host->req->cmd->error = -ENOMEDIUM;		if (host->req->stop)			host->req->stop->error = -ENOMEDIUM;		tasklet_schedule(&host->finish_tasklet);	}	spin_unlock_irqrestore(&sock->lock, flags);	mmc_remove_host(mmc);	dev_dbg(&sock->dev, "after remove\n");	mmc_free_host(mmc);}#ifdef CONFIG_PMstatic int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state){	return mmc_suspend_host(tifm_get_drvdata(sock), state);}static int tifm_sd_resume(struct tifm_dev *sock){	struct mmc_host *mmc = tifm_get_drvdata(sock);	struct tifm_sd *host = mmc_priv(mmc);	int rc;	rc = tifm_sd_initialize_host(host);	dev_dbg(&sock->dev, "resume initialize %d\n", rc);	if (rc)		host->eject = 1;	else		rc = mmc_resume_host(mmc);	return rc;}#else#define tifm_sd_suspend NULL#define tifm_sd_resume NULL#endif /* CONFIG_PM */static struct tifm_device_id tifm_sd_id_tbl[] = {	{ TIFM_TYPE_SD }, { }};static struct tifm_driver tifm_sd_driver = {	.driver = {		.name  = DRIVER_NAME,		.owner = THIS_MODULE	},	.id_table = tifm_sd_id_tbl,	.probe    = tifm_sd_probe,	.remove   = tifm_sd_remove,	.suspend  = tifm_sd_suspend,	.resume   = tifm_sd_resume};static int __init tifm_sd_init(void){	return tifm_register_driver(&tifm_sd_driver);}static void __exit tifm_sd_exit(void){	tifm_unregister_driver(&tifm_sd_driver);}MODULE_AUTHOR("Alex Dubov");MODULE_DESCRIPTION("TI FlashMedia SD driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);MODULE_VERSION(DRIVER_VERSION);module_init(tifm_sd_init);module_exit(tifm_sd_exit);

⌨️ 快捷键说明

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