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

📄 au1550_spi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * au1550_spi.c - au1550 psc spi controller driver * may work also with au1200, au1210, au1250 * will not work on au1000, au1100 and au1500 (no full spi controller there) * * Copyright (c) 2006 ATRON electronic GmbH * Author: Jan Nikitenko <jan.nikitenko@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <linux/init.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/spi/spi.h>#include <linux/spi/spi_bitbang.h>#include <linux/dma-mapping.h>#include <linux/completion.h>#include <asm/mach-au1x00/au1000.h>#include <asm/mach-au1x00/au1xxx_psc.h>#include <asm/mach-au1x00/au1xxx_dbdma.h>#include <asm/mach-au1x00/au1550_spi.h>static unsigned usedma = 1;module_param(usedma, uint, 0644);/*#define AU1550_SPI_DEBUG_LOOPBACK*/#define AU1550_SPI_DBDMA_DESCRIPTORS 1#define AU1550_SPI_DMA_RXTMP_MINSIZE 2048Ustruct au1550_spi {	struct spi_bitbang bitbang;	volatile psc_spi_t __iomem *regs;	int irq;	unsigned freq_max;	unsigned freq_min;	unsigned len;	unsigned tx_count;	unsigned rx_count;	const u8 *tx;	u8 *rx;	void (*rx_word)(struct au1550_spi *hw);	void (*tx_word)(struct au1550_spi *hw);	int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);	irqreturn_t (*irq_callback)(struct au1550_spi *hw);	struct completion master_done;	unsigned usedma;	u32 dma_tx_id;	u32 dma_rx_id;	u32 dma_tx_ch;	u32 dma_rx_ch;	u8 *dma_rx_tmpbuf;	unsigned dma_rx_tmpbuf_size;	u32 dma_rx_tmpbuf_addr;	struct spi_master *master;	struct device *dev;	struct au1550_spi_info *pdata;};/* we use an 8-bit memory device for dma transfers to/from spi fifo */static dbdev_tab_t au1550_spi_mem_dbdev ={	.dev_id			= DBDMA_MEM_CHAN,	.dev_flags		= DEV_FLAGS_ANYUSE|DEV_FLAGS_SYNC,	.dev_tsize		= 0,	.dev_devwidth		= 8,	.dev_physaddr		= 0x00000000,	.dev_intlevel		= 0,	.dev_intpolarity	= 0};static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw);/** *  compute BRG and DIV bits to setup spi clock based on main input clock rate *  that was specified in platform data structure *  according to 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 */static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned speed_hz){	u32 mainclk_hz = hw->pdata->mainclk_hz;	u32 div, brg;	for (div = 0; div < 4; div++) {		brg = mainclk_hz / speed_hz / (4 << div);		/* now we have BRG+1 in brg, so count with that */		if (brg < (4 + 1)) {			brg = (4 + 1);	/* speed_hz too big */			break;		/* set lowest brg (div is == 0) */		}		if (brg <= (63 + 1))			break;		/* we have valid brg and div */	}	if (div == 4) {		div = 3;		/* speed_hz too small */		brg = (63 + 1);		/* set highest brg and div */	}	brg--;	return PSC_SPICFG_SET_BAUD(brg) | PSC_SPICFG_SET_DIV(div);}static inline void au1550_spi_mask_ack_all(struct au1550_spi *hw){	hw->regs->psc_spimsk =		  PSC_SPIMSK_MM | PSC_SPIMSK_RR | PSC_SPIMSK_RO		| PSC_SPIMSK_RU | PSC_SPIMSK_TR | PSC_SPIMSK_TO		| PSC_SPIMSK_TU | PSC_SPIMSK_SD | PSC_SPIMSK_MD;	au_sync();	hw->regs->psc_spievent =		  PSC_SPIEVNT_MM | PSC_SPIEVNT_RR | PSC_SPIEVNT_RO		| PSC_SPIEVNT_RU | PSC_SPIEVNT_TR | PSC_SPIEVNT_TO		| PSC_SPIEVNT_TU | PSC_SPIEVNT_SD | PSC_SPIEVNT_MD;	au_sync();}static void au1550_spi_reset_fifos(struct au1550_spi *hw){	u32 pcr;	hw->regs->psc_spipcr = PSC_SPIPCR_RC | PSC_SPIPCR_TC;	au_sync();	do {		pcr = hw->regs->psc_spipcr;		au_sync();	} while (pcr != 0);}/* * dma transfers are used for the most common spi word size of 8-bits * we cannot easily change already set up dma channels' width, so if we wanted * dma support for more than 8-bit words (up to 24 bits), we would need to * setup dma channels from scratch on each spi transfer, based on bits_per_word * instead we have pre set up 8 bit dma channels supporting spi 4 to 8 bits * transfers, and 9 to 24 bits spi transfers will be done in pio irq based mode * callbacks to handle dma or pio are set up in au1550_spi_bits_handlers_set() */static void au1550_spi_chipsel(struct spi_device *spi, int value){	struct au1550_spi *hw = spi_master_get_devdata(spi->master);	unsigned cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;	u32 cfg, stat;	switch (value) {	case BITBANG_CS_INACTIVE:		if (hw->pdata->deactivate_cs)			hw->pdata->deactivate_cs(hw->pdata, spi->chip_select,					cspol);		break;	case BITBANG_CS_ACTIVE:		au1550_spi_bits_handlers_set(hw, spi->bits_per_word);		cfg = hw->regs->psc_spicfg;		au_sync();		hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE;		au_sync();		if (spi->mode & SPI_CPOL)			cfg |= PSC_SPICFG_BI;		else			cfg &= ~PSC_SPICFG_BI;		if (spi->mode & SPI_CPHA)			cfg &= ~PSC_SPICFG_CDE;		else			cfg |= PSC_SPICFG_CDE;		if (spi->mode & SPI_LSB_FIRST)			cfg |= PSC_SPICFG_MLF;		else			cfg &= ~PSC_SPICFG_MLF;		if (hw->usedma && spi->bits_per_word <= 8)			cfg &= ~PSC_SPICFG_DD_DISABLE;		else			cfg |= PSC_SPICFG_DD_DISABLE;		cfg = PSC_SPICFG_CLR_LEN(cfg);		cfg |= PSC_SPICFG_SET_LEN(spi->bits_per_word);		cfg = PSC_SPICFG_CLR_BAUD(cfg);		cfg &= ~PSC_SPICFG_SET_DIV(3);		cfg |= au1550_spi_baudcfg(hw, spi->max_speed_hz);		hw->regs->psc_spicfg = cfg | PSC_SPICFG_DE_ENABLE;		au_sync();		do {			stat = hw->regs->psc_spistat;			au_sync();		} while ((stat & PSC_SPISTAT_DR) == 0);		if (hw->pdata->activate_cs)			hw->pdata->activate_cs(hw->pdata, spi->chip_select,					cspol);		break;	}}static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t){	struct au1550_spi *hw = spi_master_get_devdata(spi->master);	unsigned bpw, hz;	u32 cfg, stat;	bpw = t ? t->bits_per_word : spi->bits_per_word;	hz = t ? t->speed_hz : spi->max_speed_hz;	if (bpw < 4 || bpw > 24) {		dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",			bpw);		return -EINVAL;	}	if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {		dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",			hz);		return -EINVAL;	}	au1550_spi_bits_handlers_set(hw, spi->bits_per_word);	cfg = hw->regs->psc_spicfg;	au_sync();	hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE;	au_sync();	if (hw->usedma && bpw <= 8)		cfg &= ~PSC_SPICFG_DD_DISABLE;	else		cfg |= PSC_SPICFG_DD_DISABLE;	cfg = PSC_SPICFG_CLR_LEN(cfg);	cfg |= PSC_SPICFG_SET_LEN(bpw);	cfg = PSC_SPICFG_CLR_BAUD(cfg);	cfg &= ~PSC_SPICFG_SET_DIV(3);	cfg |= au1550_spi_baudcfg(hw, hz);	hw->regs->psc_spicfg = cfg;	au_sync();	if (cfg & PSC_SPICFG_DE_ENABLE) {		do {			stat = hw->regs->psc_spistat;			au_sync();		} while ((stat & PSC_SPISTAT_DR) == 0);	}	au1550_spi_reset_fifos(hw);	au1550_spi_mask_ack_all(hw);	return 0;}/* the spi->mode bits understood by this driver: */#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)static int au1550_spi_setup(struct spi_device *spi){	struct au1550_spi *hw = spi_master_get_devdata(spi->master);	if (spi->bits_per_word == 0)		spi->bits_per_word = 8;	if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {		dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",			spi->bits_per_word);		return -EINVAL;	}	if (spi->mode & ~MODEBITS) {		dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",			spi->mode & ~MODEBITS);		return -EINVAL;	}	if (spi->max_speed_hz == 0)		spi->max_speed_hz = hw->freq_max;	if (spi->max_speed_hz > hw->freq_max			|| spi->max_speed_hz < hw->freq_min)		return -EINVAL;	/*	 * NOTE: cannot change speed and other hw settings immediately,	 *       otherwise sharing of spi bus is not possible,	 *       so do not call setupxfer(spi, NULL) here	 */	return 0;}/* * for dma spi transfers, we have to setup rx channel, otherwise there is * no reliable way how to recognize that spi transfer is done * dma complete callbacks are called before real spi transfer is finished * and if only tx dma channel is set up (and rx fifo overflow event masked) * spi master done event irq is not generated unless rx fifo is empty (emptied) * so we need rx tmp buffer to use for rx dma if user does not provide one */static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size){	hw->dma_rx_tmpbuf = kmalloc(size, GFP_KERNEL);	if (!hw->dma_rx_tmpbuf)		return -ENOMEM;	hw->dma_rx_tmpbuf_size = size;	hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf,			size, DMA_FROM_DEVICE);	if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) {		kfree(hw->dma_rx_tmpbuf);		hw->dma_rx_tmpbuf = 0;		hw->dma_rx_tmpbuf_size = 0;		return -EFAULT;	}	return 0;}static void au1550_spi_dma_rxtmp_free(struct au1550_spi *hw){	dma_unmap_single(hw->dev, hw->dma_rx_tmpbuf_addr,			hw->dma_rx_tmpbuf_size, DMA_FROM_DEVICE);	kfree(hw->dma_rx_tmpbuf);	hw->dma_rx_tmpbuf = 0;	hw->dma_rx_tmpbuf_size = 0;}static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t){	struct au1550_spi *hw = spi_master_get_devdata(spi->master);	dma_addr_t dma_tx_addr;	dma_addr_t dma_rx_addr;	u32 res;	hw->len = t->len;	hw->tx_count = 0;	hw->rx_count = 0;	hw->tx = t->tx_buf;	hw->rx = t->rx_buf;	dma_tx_addr = t->tx_dma;	dma_rx_addr = t->rx_dma;	/*	 * check if buffers are already dma mapped, map them otherwise	 * use rx buffer in place of tx if tx buffer was not provided	 * use temp rx buffer (preallocated or realloc to fit) for rx dma	 */	if (t->rx_buf) {		if (t->rx_dma == 0) {	/* if DMA_ADDR_INVALID, map it */			dma_rx_addr = dma_map_single(hw->dev,					(void *)t->rx_buf,					t->len, DMA_FROM_DEVICE);			if (dma_mapping_error(dma_rx_addr))				dev_err(hw->dev, "rx dma map error\n");		}	} else {		if (t->len > hw->dma_rx_tmpbuf_size) {			int ret;			au1550_spi_dma_rxtmp_free(hw);			ret = au1550_spi_dma_rxtmp_alloc(hw, max(t->len,					AU1550_SPI_DMA_RXTMP_MINSIZE));			if (ret < 0)				return ret;		}		hw->rx = hw->dma_rx_tmpbuf;		dma_rx_addr = hw->dma_rx_tmpbuf_addr;		dma_sync_single_for_device(hw->dev, dma_rx_addr,			t->len, DMA_FROM_DEVICE);	}	if (t->tx_buf) {		if (t->tx_dma == 0) {	/* if DMA_ADDR_INVALID, map it */			dma_tx_addr = dma_map_single(hw->dev,					(void *)t->tx_buf,					t->len, DMA_TO_DEVICE);			if (dma_mapping_error(dma_tx_addr))				dev_err(hw->dev, "tx dma map error\n");		}	} else {		dma_sync_single_for_device(hw->dev, dma_rx_addr,				t->len, DMA_BIDIRECTIONAL);		hw->tx = hw->rx;	}	/* put buffers on the ring */	res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, hw->rx, t->len);	if (!res)		dev_err(hw->dev, "rx dma put dest error\n");	res = au1xxx_dbdma_put_source(hw->dma_tx_ch, (void *)hw->tx, t->len);	if (!res)		dev_err(hw->dev, "tx dma put source error\n");	au1xxx_dbdma_start(hw->dma_rx_ch);	au1xxx_dbdma_start(hw->dma_tx_ch);	/* by default enable nearly all events interrupt */	hw->regs->psc_spimsk = PSC_SPIMSK_SD;	au_sync();	/* start the transfer */	hw->regs->psc_spipcr = PSC_SPIPCR_MS;	au_sync();	wait_for_completion(&hw->master_done);	au1xxx_dbdma_stop(hw->dma_tx_ch);	au1xxx_dbdma_stop(hw->dma_rx_ch);	if (!t->rx_buf) {		/* using the temporal preallocated and premapped buffer */		dma_sync_single_for_cpu(hw->dev, dma_rx_addr, t->len,			DMA_FROM_DEVICE);	}	/* unmap buffers if mapped above */	if (t->rx_buf && t->rx_dma == 0 )		dma_unmap_single(hw->dev, dma_rx_addr, t->len,			DMA_FROM_DEVICE);	if (t->tx_buf && t->tx_dma == 0 )		dma_unmap_single(hw->dev, dma_tx_addr, t->len,			DMA_TO_DEVICE);	return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;}static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw){	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) {		/*		 * due to an spi error we consider transfer as done,		 * so mask all events until before next transfer start		 * and stop the possibly running dma immediatelly		 */		au1550_spi_mask_ack_all(hw);		au1xxx_dbdma_stop(hw->dma_rx_ch);		au1xxx_dbdma_stop(hw->dma_tx_ch);		/* get number of transfered bytes */		hw->rx_count = hw->len - au1xxx_get_dma_residue(hw->dma_rx_ch);		hw->tx_count = hw->len - au1xxx_get_dma_residue(hw->dma_tx_ch);		au1xxx_dbdma_reset(hw->dma_rx_ch);		au1xxx_dbdma_reset(hw->dma_tx_ch);		au1550_spi_reset_fifos(hw);		dev_err(hw->dev,			"Unexpected SPI error: event=0x%x stat=0x%x!\n",			evnt, stat);		complete(&hw->master_done);		return IRQ_HANDLED;	}	if ((evnt & PSC_SPIEVNT_MD) != 0) {		/* transfer completed successfully */

⌨️ 快捷键说明

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