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

📄 au1550_spi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		au1550_spi_mask_ack_all(hw);		hw->rx_count = hw->len;		hw->tx_count = hw->len;		complete(&hw->master_done);	}	return IRQ_HANDLED;}/* routines to handle different word sizes in pio mode */#define AU1550_SPI_RX_WORD(size, mask)					\static void au1550_spi_rx_word_##size(struct au1550_spi *hw)		\{									\	u32 fifoword = hw->regs->psc_spitxrx & (u32)(mask);		\	au_sync();							\	if (hw->rx) {							\		*(u##size *)hw->rx = (u##size)fifoword;			\		hw->rx += (size) / 8;					\	}								\	hw->rx_count += (size) / 8;					\}#define AU1550_SPI_TX_WORD(size, mask)					\static void au1550_spi_tx_word_##size(struct au1550_spi *hw)		\{									\	u32 fifoword = 0;						\	if (hw->tx) {							\		fifoword = *(u##size *)hw->tx & (u32)(mask);		\		hw->tx += (size) / 8;					\	}								\	hw->tx_count += (size) / 8;					\	if (hw->tx_count >= hw->len)					\		fifoword |= PSC_SPITXRX_LC;				\	hw->regs->psc_spitxrx = fifoword;				\	au_sync();							\}AU1550_SPI_RX_WORD(8,0xff)AU1550_SPI_RX_WORD(16,0xffff)AU1550_SPI_RX_WORD(32,0xffffff)AU1550_SPI_TX_WORD(8,0xff)AU1550_SPI_TX_WORD(16,0xffff)AU1550_SPI_TX_WORD(32,0xffffff)static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t){	u32 stat, mask;	struct au1550_spi *hw = spi_master_get_devdata(spi->master);	hw->tx = t->tx_buf;	hw->rx = t->rx_buf;	hw->len = t->len;	hw->tx_count = 0;	hw->rx_count = 0;	/* by default enable nearly all events after filling tx fifo */	mask = PSC_SPIMSK_SD;	/* fill the transmit FIFO */	while (hw->tx_count < hw->len) {		hw->tx_word(hw);		if (hw->tx_count >= hw->len) {			/* mask tx fifo request interrupt as we are done */			mask |= PSC_SPIMSK_TR;		}		stat = hw->regs->psc_spistat;		au_sync();		if (stat & PSC_SPISTAT_TF)			break;	}	/* enable event interrupts */	hw->regs->psc_spimsk = mask;	au_sync();	/* start the transfer */	hw->regs->psc_spipcr = PSC_SPIPCR_MS;	au_sync();	wait_for_completion(&hw->master_done);	return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;}static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw){	int busy;	u32 stat, evnt;	stat = hw->regs->psc_spistat;	evnt = hw->regs->psc_spievent;	au_sync();	if ((stat & PSC_SPISTAT_DI) == 0) {		dev_err(hw->dev, "Unexpected IRQ!\n");		return IRQ_NONE;	}	if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO				| PSC_SPIEVNT_RU | PSC_SPIEVNT_TO				| PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))			!= 0) {		dev_err(hw->dev,			"Unexpected SPI error: event=0x%x stat=0x%x!\n",			evnt, stat);		/*		 * due to an error we consider transfer as done,		 * so mask all events until before next transfer start		 */		au1550_spi_mask_ack_all(hw);		au1550_spi_reset_fifos(hw);		complete(&hw->master_done);		return IRQ_HANDLED;	}	/*	 * while there is something to read from rx fifo	 * or there is a space to write to tx fifo:	 */	do {		busy = 0;		stat = hw->regs->psc_spistat;		au_sync();		if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) {			hw->rx_word(hw);			/* ack the receive request event */			hw->regs->psc_spievent = PSC_SPIEVNT_RR;			au_sync();			busy = 1;		}		if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) {			hw->tx_word(hw);			/* ack the transmit request event */			hw->regs->psc_spievent = PSC_SPIEVNT_TR;			au_sync();			busy = 1;		}	} while (busy);	evnt = hw->regs->psc_spievent;	au_sync();	if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) {		/* transfer completed successfully */		au1550_spi_mask_ack_all(hw);		complete(&hw->master_done);	}	return IRQ_HANDLED;}static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t){	struct au1550_spi *hw = spi_master_get_devdata(spi->master);	return hw->txrx_bufs(spi, t);}static irqreturn_t au1550_spi_irq(int irq, void *dev, struct pt_regs *regs){	struct au1550_spi *hw = dev;	return hw->irq_callback(hw);}static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw){	if (bpw <= 8) {		if (hw->usedma) {			hw->txrx_bufs = &au1550_spi_dma_txrxb;			hw->irq_callback = &au1550_spi_dma_irq_callback;		} else {			hw->rx_word = &au1550_spi_rx_word_8;			hw->tx_word = &au1550_spi_tx_word_8;			hw->txrx_bufs = &au1550_spi_pio_txrxb;			hw->irq_callback = &au1550_spi_pio_irq_callback;		}	} else if (bpw <= 16) {		hw->rx_word = &au1550_spi_rx_word_16;		hw->tx_word = &au1550_spi_tx_word_16;		hw->txrx_bufs = &au1550_spi_pio_txrxb;		hw->irq_callback = &au1550_spi_pio_irq_callback;	} else {		hw->rx_word = &au1550_spi_rx_word_32;		hw->tx_word = &au1550_spi_tx_word_32;		hw->txrx_bufs = &au1550_spi_pio_txrxb;		hw->irq_callback = &au1550_spi_pio_irq_callback;	}}static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw){	u32 stat, cfg;	/* set up the PSC for SPI mode */	hw->regs->psc_ctrl = PSC_CTRL_DISABLE;	au_sync();	hw->regs->psc_sel = PSC_SEL_PS_SPIMODE;	au_sync();	hw->regs->psc_spicfg = 0;	au_sync();	hw->regs->psc_ctrl = PSC_CTRL_ENABLE;	au_sync();	do {		stat = hw->regs->psc_spistat;		au_sync();	} while ((stat & PSC_SPISTAT_SR) == 0);	cfg = hw->usedma ? 0 : PSC_SPICFG_DD_DISABLE;	cfg |= PSC_SPICFG_SET_LEN(8);	cfg |= PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8;	/* use minimal allowed brg and div values as initial setting: */	cfg |= PSC_SPICFG_SET_BAUD(4) | PSC_SPICFG_SET_DIV(0);#ifdef AU1550_SPI_DEBUG_LOOPBACK	cfg |= PSC_SPICFG_LB;#endif	hw->regs->psc_spicfg = cfg;	au_sync();	au1550_spi_mask_ack_all(hw);	hw->regs->psc_spicfg |= PSC_SPICFG_DE_ENABLE;	au_sync();	do {		stat = hw->regs->psc_spistat;		au_sync();	} while ((stat & PSC_SPISTAT_DR) == 0);}static int __init au1550_spi_probe(struct platform_device *pdev){	struct au1550_spi *hw;	struct spi_master *master;	int err = 0;	master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi));	if (master == NULL) {		dev_err(&pdev->dev, "No memory for spi_master\n");		err = -ENOMEM;		goto err_nomem;	}	hw = spi_master_get_devdata(master);	hw->master = spi_master_get(master);	hw->pdata = pdev->dev.platform_data;	hw->dev = &pdev->dev;	if (hw->pdata == NULL) {		dev_err(&pdev->dev, "No platform data supplied\n");		err = -ENOENT;		goto err_no_pdata;	}	platform_set_drvdata(pdev, hw);	init_completion(&hw->master_done);	hw->bitbang.master = hw->master;	hw->bitbang.setup_transfer = au1550_spi_setupxfer;	hw->bitbang.chipselect = au1550_spi_chipsel;	hw->bitbang.master->setup = au1550_spi_setup;	hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;	switch (hw->pdata->bus_num) {	case 0:		hw->irq = AU1550_PSC0_INT;		hw->regs = (volatile psc_spi_t *)PSC0_BASE_ADDR;		hw->dma_rx_id = DSCR_CMD0_PSC0_RX;		hw->dma_tx_id = DSCR_CMD0_PSC0_TX;		break;	case 1:		hw->irq = AU1550_PSC1_INT;		hw->regs = (volatile psc_spi_t *)PSC1_BASE_ADDR;		hw->dma_rx_id = DSCR_CMD0_PSC1_RX;		hw->dma_tx_id = DSCR_CMD0_PSC1_TX;		break;	case 2:		hw->irq = AU1550_PSC2_INT;		hw->regs = (volatile psc_spi_t *)PSC2_BASE_ADDR;		hw->dma_rx_id = DSCR_CMD0_PSC2_RX;		hw->dma_tx_id = DSCR_CMD0_PSC2_TX;		break;	case 3:		hw->irq = AU1550_PSC3_INT;		hw->regs = (volatile psc_spi_t *)PSC3_BASE_ADDR;		hw->dma_rx_id = DSCR_CMD0_PSC3_RX;		hw->dma_tx_id = DSCR_CMD0_PSC3_TX;		break;	default:		dev_err(&pdev->dev, "Wrong bus_num of SPI\n");		err = -ENOENT;		goto err_no_pdata;	}	if (request_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t),			pdev->name) == NULL) {		dev_err(&pdev->dev, "Cannot reserve iomem region\n");		err = -ENXIO;		goto err_no_iores;	}	if (usedma) {		if (pdev->dev.dma_mask == NULL)			dev_warn(&pdev->dev, "no dma mask\n");		else			hw->usedma = 1;	}	if (hw->usedma) {		/*		 * create memory device with 8 bits dev_devwidth		 * needed for proper byte ordering to spi fifo		 */		int memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);		if (!memid) {			dev_err(&pdev->dev,				"Cannot create dma 8 bit mem device\n");			err = -ENXIO;			goto err_dma_add_dev;		}		hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(memid,			hw->dma_tx_id, NULL, (void *)hw);		if (hw->dma_tx_ch == 0) {			dev_err(&pdev->dev,				"Cannot allocate tx dma channel\n");			err = -ENXIO;			goto err_no_txdma;		}		au1xxx_dbdma_set_devwidth(hw->dma_tx_ch, 8);		if (au1xxx_dbdma_ring_alloc(hw->dma_tx_ch,			AU1550_SPI_DBDMA_DESCRIPTORS) == 0) {			dev_err(&pdev->dev,				"Cannot allocate tx dma descriptors\n");			err = -ENXIO;			goto err_no_txdma_descr;		}		hw->dma_rx_ch = au1xxx_dbdma_chan_alloc(hw->dma_rx_id,			memid, NULL, (void *)hw);		if (hw->dma_rx_ch == 0) {			dev_err(&pdev->dev,				"Cannot allocate rx dma channel\n");			err = -ENXIO;			goto err_no_rxdma;		}		au1xxx_dbdma_set_devwidth(hw->dma_rx_ch, 8);		if (au1xxx_dbdma_ring_alloc(hw->dma_rx_ch,			AU1550_SPI_DBDMA_DESCRIPTORS) == 0) {			dev_err(&pdev->dev,				"Cannot allocate rx dma descriptors\n");			err = -ENXIO;			goto err_no_rxdma_descr;		}		err = au1550_spi_dma_rxtmp_alloc(hw,			AU1550_SPI_DMA_RXTMP_MINSIZE);		if (err < 0) {			dev_err(&pdev->dev,				"Cannot allocate initial rx dma tmp buffer\n");			goto err_dma_rxtmp_alloc;		}	}	au1550_spi_bits_handlers_set(hw, 8);	err = request_irq(hw->irq, au1550_spi_irq, 0, pdev->name, hw);	if (err) {		dev_err(&pdev->dev, "Cannot claim IRQ\n");		goto err_no_irq;	}	master->bus_num = hw->pdata->bus_num;	master->num_chipselect = hw->pdata->num_chipselect;	/*	 *  precompute valid range for spi freq - from au1550 datasheet:	 *    psc_tempclk = psc_mainclk / (2 << DIV)	 *    spiclk = psc_tempclk / (2 * (BRG + 1))	 *    BRG valid range is 4..63	 *    DIV valid range is 0..3	 *  round the min and max frequencies to values that would still	 *  produce valid brg and div	 */	{		int min_div = (2 << 0) * (2 * (4 + 1));		int max_div = (2 << 3) * (2 * (63 + 1));		hw->freq_max = hw->pdata->mainclk_hz / min_div;		hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;	}	au1550_spi_setup_psc_as_spi(hw);	err = spi_bitbang_start(&hw->bitbang);	if (err) {		dev_err(&pdev->dev, "Failed to register SPI master\n");		goto err_register;	}	dev_info(&pdev->dev,		"spi master registered: bus_num=%d num_chipselect=%d\n",		master->bus_num, master->num_chipselect);	return 0;err_register:	free_irq(hw->irq, hw);err_no_irq:	au1550_spi_dma_rxtmp_free(hw);err_dma_rxtmp_alloc:err_no_rxdma_descr:	if (hw->usedma)		au1xxx_dbdma_chan_free(hw->dma_rx_ch);err_no_rxdma:err_no_txdma_descr:	if (hw->usedma)		au1xxx_dbdma_chan_free(hw->dma_tx_ch);err_no_txdma:err_dma_add_dev:	release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));err_no_iores:err_no_pdata:	spi_master_put(hw->master);err_nomem:	return err;}static int __exit au1550_spi_remove(struct platform_device *pdev){	struct au1550_spi *hw = platform_get_drvdata(pdev);	dev_info(&pdev->dev, "spi master remove: bus_num=%d\n",		hw->master->bus_num);	spi_bitbang_stop(&hw->bitbang);	free_irq(hw->irq, hw);	release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));	if (hw->usedma) {		au1550_spi_dma_rxtmp_free(hw);		au1xxx_dbdma_chan_free(hw->dma_rx_ch);		au1xxx_dbdma_chan_free(hw->dma_tx_ch);	}	platform_set_drvdata(pdev, NULL);	spi_master_put(hw->master);	return 0;}static struct platform_driver au1550_spi_drv = {	.remove = __exit_p(au1550_spi_remove),	.driver = {		.name = "au1550-spi",		.owner = THIS_MODULE,	},};static int __init au1550_spi_init(void){	return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe);}module_init(au1550_spi_init);static void __exit au1550_spi_exit(void){	platform_driver_unregister(&au1550_spi_drv);}module_exit(au1550_spi_exit);MODULE_DESCRIPTION("Au1550 PSC SPI Driver");MODULE_AUTHOR("Jan Nikitenko <jan.nikitenko@gmail.com>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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