📄 au1550_spi.c
字号:
/* * 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 + -