欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

spi_imx.c

linux 内核源代码
C
第 1 页 / 共 4 页
字号:
/* * drivers/spi/spi_imx.c * * Copyright (C) 2006 SWAPP *	Andrea Paterniani <a.paterniani@swapp-eng.it> * * Initial version inspired by: *	linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c * * 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. */#include <linux/init.h>#include <linux/module.h>#include <linux/device.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/spi/spi.h>#include <linux/workqueue.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/hardware.h>#include <asm/delay.h>#include <asm/arch/hardware.h>#include <asm/arch/imx-dma.h>#include <asm/arch/spi_imx.h>/*-------------------------------------------------------------------------*//* SPI Registers offsets from peripheral base address */#define SPI_RXDATA		(0x00)#define SPI_TXDATA		(0x04)#define SPI_CONTROL		(0x08)#define SPI_INT_STATUS		(0x0C)#define SPI_TEST		(0x10)#define SPI_PERIOD		(0x14)#define SPI_DMA			(0x18)#define SPI_RESET		(0x1C)/* SPI Control Register Bit Fields & Masks */#define SPI_CONTROL_BITCOUNT_MASK	(0xF)		/* Bit Count Mask */#define SPI_CONTROL_BITCOUNT(n)		(((n) - 1) & SPI_CONTROL_BITCOUNT_MASK)#define SPI_CONTROL_POL			(0x1 << 4)      /* Clock Polarity Mask */#define SPI_CONTROL_POL_ACT_HIGH	(0x0 << 4)      /* Active high pol. (0=idle) */#define SPI_CONTROL_POL_ACT_LOW		(0x1 << 4)      /* Active low pol. (1=idle) */#define SPI_CONTROL_PHA			(0x1 << 5)      /* Clock Phase Mask */#define SPI_CONTROL_PHA_0		(0x0 << 5)      /* Clock Phase 0 */#define SPI_CONTROL_PHA_1		(0x1 << 5)      /* Clock Phase 1 */#define SPI_CONTROL_SSCTL		(0x1 << 6)      /* /SS Waveform Select Mask */#define SPI_CONTROL_SSCTL_0		(0x0 << 6)      /* Master: /SS stays low between SPI burst							   Slave: RXFIFO advanced by BIT_COUNT */#define SPI_CONTROL_SSCTL_1		(0x1 << 6)      /* Master: /SS insert pulse between SPI burst							   Slave: RXFIFO advanced by /SS rising edge */#define SPI_CONTROL_SSPOL		(0x1 << 7)      /* /SS Polarity Select Mask */#define SPI_CONTROL_SSPOL_ACT_LOW	(0x0 << 7)      /* /SS Active low */#define SPI_CONTROL_SSPOL_ACT_HIGH	(0x1 << 7)      /* /SS Active high */#define SPI_CONTROL_XCH			(0x1 << 8)      /* Exchange */#define SPI_CONTROL_SPIEN		(0x1 << 9)      /* SPI Module Enable */#define SPI_CONTROL_MODE		(0x1 << 10)     /* SPI Mode Select Mask */#define SPI_CONTROL_MODE_SLAVE		(0x0 << 10)     /* SPI Mode Slave */#define SPI_CONTROL_MODE_MASTER		(0x1 << 10)     /* SPI Mode Master */#define SPI_CONTROL_DRCTL		(0x3 << 11)     /* /SPI_RDY Control Mask */#define SPI_CONTROL_DRCTL_0		(0x0 << 11)     /* Ignore /SPI_RDY */#define SPI_CONTROL_DRCTL_1		(0x1 << 11)     /* /SPI_RDY falling edge triggers input */#define SPI_CONTROL_DRCTL_2		(0x2 << 11)     /* /SPI_RDY active low level triggers input */#define SPI_CONTROL_DATARATE		(0x7 << 13)     /* Data Rate Mask */#define SPI_PERCLK2_DIV_MIN		(0)		/* PERCLK2:4 */#define SPI_PERCLK2_DIV_MAX		(7)		/* PERCLK2:512 */#define SPI_CONTROL_DATARATE_MIN	(SPI_PERCLK2_DIV_MAX << 13)#define SPI_CONTROL_DATARATE_MAX	(SPI_PERCLK2_DIV_MIN << 13)#define SPI_CONTROL_DATARATE_BAD	(SPI_CONTROL_DATARATE_MIN + 1)/* SPI Interrupt/Status Register Bit Fields & Masks */#define SPI_STATUS_TE	(0x1 << 0)	/* TXFIFO Empty Status */#define SPI_STATUS_TH	(0x1 << 1)      /* TXFIFO Half Status */#define SPI_STATUS_TF	(0x1 << 2)      /* TXFIFO Full Status */#define SPI_STATUS_RR	(0x1 << 3)      /* RXFIFO Data Ready Status */#define SPI_STATUS_RH	(0x1 << 4)      /* RXFIFO Half Status */#define SPI_STATUS_RF	(0x1 << 5)      /* RXFIFO Full Status */#define SPI_STATUS_RO	(0x1 << 6)      /* RXFIFO Overflow */#define SPI_STATUS_BO	(0x1 << 7)      /* Bit Count Overflow */#define SPI_STATUS	(0xFF)		/* SPI Status Mask */#define SPI_INTEN_TE	(0x1 << 8)      /* TXFIFO Empty Interrupt Enable */#define SPI_INTEN_TH	(0x1 << 9)      /* TXFIFO Half Interrupt Enable */#define SPI_INTEN_TF	(0x1 << 10)     /* TXFIFO Full Interrupt Enable */#define SPI_INTEN_RE	(0x1 << 11)     /* RXFIFO Data Ready Interrupt Enable */#define SPI_INTEN_RH	(0x1 << 12)     /* RXFIFO Half Interrupt Enable */#define SPI_INTEN_RF	(0x1 << 13)     /* RXFIFO Full Interrupt Enable */#define SPI_INTEN_RO	(0x1 << 14)     /* RXFIFO Overflow Interrupt Enable */#define SPI_INTEN_BO	(0x1 << 15)     /* Bit Count Overflow Interrupt Enable */#define SPI_INTEN	(0xFF << 8)	/* SPI Interrupt Enable Mask *//* SPI Test Register Bit Fields & Masks */#define SPI_TEST_TXCNT		(0xF << 0)	/* TXFIFO Counter */#define SPI_TEST_RXCNT_LSB	(4)		/* RXFIFO Counter LSB */#define SPI_TEST_RXCNT		(0xF << 4)	/* RXFIFO Counter */#define SPI_TEST_SSTATUS	(0xF << 8)	/* State Machine Status */#define SPI_TEST_LBC		(0x1 << 14)	/* Loop Back Control *//* SPI Period Register Bit Fields & Masks */#define SPI_PERIOD_WAIT		(0x7FFF << 0)	/* Wait Between Transactions */#define SPI_PERIOD_MAX_WAIT	(0x7FFF)	/* Max Wait Between							Transactions */#define SPI_PERIOD_CSRC		(0x1 << 15)	/* Period Clock Source Mask */#define SPI_PERIOD_CSRC_BCLK	(0x0 << 15)	/* Period Clock Source is							Bit Clock */#define SPI_PERIOD_CSRC_32768	(0x1 << 15)	/* Period Clock Source is							32.768 KHz Clock *//* SPI DMA Register Bit Fields & Masks */#define SPI_DMA_RHDMA	(0x1 << 4)	/* RXFIFO Half Status */#define SPI_DMA_RFDMA	(0x1 << 5)      /* RXFIFO Full Status */#define SPI_DMA_TEDMA	(0x1 << 6)      /* TXFIFO Empty Status */#define SPI_DMA_THDMA	(0x1 << 7)      /* TXFIFO Half Status */#define SPI_DMA_RHDEN	(0x1 << 12)	/* RXFIFO Half DMA Request Enable */#define SPI_DMA_RFDEN	(0x1 << 13)     /* RXFIFO Full DMA Request Enable */#define SPI_DMA_TEDEN	(0x1 << 14)     /* TXFIFO Empty DMA Request Enable */#define SPI_DMA_THDEN	(0x1 << 15)     /* TXFIFO Half DMA Request Enable *//* SPI Soft Reset Register Bit Fields & Masks */#define SPI_RESET_START	(0x1)		/* Start *//* Default SPI configuration values */#define SPI_DEFAULT_CONTROL		\(					\	SPI_CONTROL_BITCOUNT(16) | 	\	SPI_CONTROL_POL_ACT_HIGH |	\	SPI_CONTROL_PHA_0 |		\	SPI_CONTROL_SPIEN |		\	SPI_CONTROL_SSCTL_1 |		\	SPI_CONTROL_MODE_MASTER |	\	SPI_CONTROL_DRCTL_0 |		\	SPI_CONTROL_DATARATE_MIN	\)#define SPI_DEFAULT_ENABLE_LOOPBACK	(0)#define SPI_DEFAULT_ENABLE_DMA		(0)#define SPI_DEFAULT_PERIOD_WAIT		(8)/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------*//* TX/RX SPI FIFO size */#define SPI_FIFO_DEPTH			(8)#define SPI_FIFO_BYTE_WIDTH		(2)#define SPI_FIFO_OVERFLOW_MARGIN	(2)/* DMA burst lenght for half full/empty request trigger */#define SPI_DMA_BLR			(SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)/* Dummy char output to achieve reads.   Choosing something different from all zeroes may help pattern recogition   for oscilloscope analysis, but may break some drivers. */#define SPI_DUMMY_u8			0#define SPI_DUMMY_u16			((SPI_DUMMY_u8 << 8) | SPI_DUMMY_u8)#define SPI_DUMMY_u32			((SPI_DUMMY_u16 << 16) | SPI_DUMMY_u16)/** * Macro to change a u32 field: * @r : register to edit * @m : bit mask * @v : new value for the field correctly bit-alligned*/#define u32_EDIT(r, m, v)		r = (r & ~(m)) | (v)/* Message state */#define START_STATE			((void*)0)#define RUNNING_STATE			((void*)1)#define DONE_STATE			((void*)2)#define ERROR_STATE			((void*)-1)/* Queue state */#define QUEUE_RUNNING			(0)#define QUEUE_STOPPED			(1)#define IS_DMA_ALIGNED(x) 		(((u32)(x) & 0x03) == 0)/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------*//* Driver data structs *//* Context */struct driver_data {	/* Driver model hookup */	struct platform_device *pdev;	/* SPI framework hookup */	struct spi_master *master;	/* IMX hookup */	struct spi_imx_master *master_info;	/* Memory resources and SPI regs virtual address */	struct resource *ioarea;	void __iomem *regs;	/* SPI RX_DATA physical address */	dma_addr_t rd_data_phys;	/* Driver message queue */	struct workqueue_struct	*workqueue;	struct work_struct work;	spinlock_t lock;	struct list_head queue;	int busy;	int run;	/* Message Transfer pump */	struct tasklet_struct pump_transfers;	/* Current message, transfer and state */	struct spi_message *cur_msg;	struct spi_transfer *cur_transfer;	struct chip_data *cur_chip;	/* Rd / Wr buffers pointers */	size_t len;	void *tx;	void *tx_end;	void *rx;	void *rx_end;	u8 rd_only;	u8 n_bytes;	int cs_change;	/* Function pointers */	irqreturn_t (*transfer_handler)(struct driver_data *drv_data);	void (*cs_control)(u32 command);	/* DMA setup */	int rx_channel;	int tx_channel;	dma_addr_t rx_dma;	dma_addr_t tx_dma;	int rx_dma_needs_unmap;	int tx_dma_needs_unmap;	size_t tx_map_len;	u32 dummy_dma_buf ____cacheline_aligned;};/* Runtime state */struct chip_data {	u32 control;	u32 period;	u32 test;	u8 enable_dma:1;	u8 bits_per_word;	u8 n_bytes;	u32 max_speed_hz;	void (*cs_control)(u32 command);};/*-------------------------------------------------------------------------*/static void pump_messages(struct work_struct *work);static int flush(struct driver_data *drv_data){	unsigned long limit = loops_per_jiffy << 1;	void __iomem *regs = drv_data->regs;	volatile u32 d;	dev_dbg(&drv_data->pdev->dev, "flush\n");	do {		while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR)			d = readl(regs + SPI_RXDATA);	} while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--);	return limit;}static void restore_state(struct driver_data *drv_data){	void __iomem *regs = drv_data->regs;	struct chip_data *chip = drv_data->cur_chip;	/* Load chip registers */	dev_dbg(&drv_data->pdev->dev,		"restore_state\n"		"    test    = 0x%08X\n"		"    control = 0x%08X\n",		chip->test,		chip->control);	writel(chip->test, regs + SPI_TEST);	writel(chip->period, regs + SPI_PERIOD);	writel(0, regs + SPI_INT_STATUS);	writel(chip->control, regs + SPI_CONTROL);}static void null_cs_control(u32 command){}static inline u32 data_to_write(struct driver_data *drv_data){	return ((u32)(drv_data->tx_end - drv_data->tx)) / drv_data->n_bytes;}static inline u32 data_to_read(struct driver_data *drv_data){	return ((u32)(drv_data->rx_end - drv_data->rx)) / drv_data->n_bytes;}static int write(struct driver_data *drv_data){	void __iomem *regs = drv_data->regs;	void *tx = drv_data->tx;	void *tx_end = drv_data->tx_end;	u8 n_bytes = drv_data->n_bytes;	u32 remaining_writes;	u32 fifo_avail_space;	u32 n;	u16 d;	/* Compute how many fifo writes to do */	remaining_writes = (u32)(tx_end - tx) / n_bytes;	fifo_avail_space = SPI_FIFO_DEPTH -				(readl(regs + SPI_TEST) & SPI_TEST_TXCNT);	if (drv_data->rx && (fifo_avail_space > SPI_FIFO_OVERFLOW_MARGIN))		/* Fix misunderstood receive overflow */		fifo_avail_space -= SPI_FIFO_OVERFLOW_MARGIN;	n = min(remaining_writes, fifo_avail_space);	dev_dbg(&drv_data->pdev->dev,		"write type %s\n"		"    remaining writes = %d\n"		"    fifo avail space = %d\n"		"    fifo writes      = %d\n",		(n_bytes == 1) ? "u8" : "u16",		remaining_writes,		fifo_avail_space,		n);	if (n > 0) {		/* Fill SPI TXFIFO */		if (drv_data->rd_only) {			tx += n * n_bytes;			while (n--)				writel(SPI_DUMMY_u16, regs + SPI_TXDATA);		} else {			if (n_bytes == 1) {				while (n--) {					d = *(u8*)tx;					writel(d, regs + SPI_TXDATA);					tx += 1;				}			} else {				while (n--) {					d = *(u16*)tx;					writel(d, regs + SPI_TXDATA);					tx += 2;				}			}		}		/* Trigger transfer */		writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,			regs + SPI_CONTROL);		/* Update tx pointer */		drv_data->tx = tx;	}	return (tx >= tx_end);}static int read(struct driver_data *drv_data){	void __iomem *regs = drv_data->regs;	void *rx = drv_data->rx;	void *rx_end = drv_data->rx_end;	u8 n_bytes = drv_data->n_bytes;	u32 remaining_reads;	u32 fifo_rxcnt;	u32 n;	u16 d;	/* Compute how many fifo reads to do */	remaining_reads = (u32)(rx_end - rx) / n_bytes;	fifo_rxcnt = (readl(regs + SPI_TEST) & SPI_TEST_RXCNT) >>			SPI_TEST_RXCNT_LSB;	n = min(remaining_reads, fifo_rxcnt);	dev_dbg(&drv_data->pdev->dev,		"read type %s\n"		"    remaining reads = %d\n"		"    fifo rx count   = %d\n"		"    fifo reads      = %d\n",		(n_bytes == 1) ? "u8" : "u16",		remaining_reads,		fifo_rxcnt,		n);	if (n > 0) {		/* Read SPI RXFIFO */		if (n_bytes == 1) {			while (n--) {				d = readl(regs + SPI_RXDATA);				*((u8*)rx) = d;				rx += 1;			}		} else {			while (n--) {				d = readl(regs + SPI_RXDATA);				*((u16*)rx) = d;				rx += 2;			}		}		/* Update rx pointer */		drv_data->rx = rx;	}	return (rx >= rx_end);}static void *next_transfer(struct driver_data *drv_data){	struct spi_message *msg = drv_data->cur_msg;	struct spi_transfer *trans = drv_data->cur_transfer;	/* Move to next transfer */	if (trans->transfer_list.next != &msg->transfers) {		drv_data->cur_transfer =			list_entry(trans->transfer_list.next,

⌨️ 快捷键说明

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