diff options
| -rw-r--r-- | README | 5 | ||||
| -rw-r--r-- | drivers/spi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/spi/mxc_spi.c | 166 | ||||
| -rw-r--r-- | include/asm-arm/arch-mx31/mx31-regs.h | 7 | ||||
| -rw-r--r-- | include/spi.h | 16 | 
5 files changed, 193 insertions, 2 deletions
| @@ -1414,6 +1414,11 @@ The following options need to be configured:  		Currently supported on some MPC8xxx processors.  For an  		example, see include/configs/mpc8349emds.h. +		CONFIG_MXC_SPI + +		Enables the driver for the SPI controllers on i.MX and MXC +		SoCs. Currently only i.MX31 is supported. +  - FPGA Support: CONFIG_FPGA  		Enables FPGA subsystem. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 0b7a2dfd3..bc8a10412 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk  LIB	:= $(obj)libspi.a  COBJS-y += mpc8xxx_spi.o +COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c new file mode 100644 index 000000000..b2e3ab9b6 --- /dev/null +++ b/drivers/spi/mxc_spi.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de> + * + * 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 <common.h> +#include <spi.h> +#include <asm/io.h> + +#ifdef CONFIG_MX27 +/* i.MX27 has a completely wrong register layout and register definitions in the + * datasheet, the correct one is in the Freescale's Linux driver */ + +#error "i.MX27 CSPI not supported due to drastic differences in register definisions" \ +"See linux mxc_spi driver from Freescale for details." + +#else + +#define MXC_CSPIRXDATA		0x00 +#define MXC_CSPITXDATA		0x04 +#define MXC_CSPICTRL		0x08 +#define MXC_CSPIINT		0x0C +#define MXC_CSPIDMA		0x10 +#define MXC_CSPISTAT		0x14 +#define MXC_CSPIPERIOD		0x18 +#define MXC_CSPITEST		0x1C +#define MXC_CSPIRESET		0x00 + +#define MXC_CSPICTRL_EN		(1 << 0) +#define MXC_CSPICTRL_MODE	(1 << 1) +#define MXC_CSPICTRL_XCH	(1 << 2) +#define MXC_CSPICTRL_SMC	(1 << 3) +#define MXC_CSPICTRL_POL	(1 << 4) +#define MXC_CSPICTRL_PHA	(1 << 5) +#define MXC_CSPICTRL_SSCTL	(1 << 6) +#define MXC_CSPICTRL_SSPOL 	(1 << 7) +#define MXC_CSPICTRL_CHIPSELECT(x)	(((x) & 0x3) << 24) +#define MXC_CSPICTRL_BITCOUNT(x)	(((x) & 0x1f) << 8) +#define MXC_CSPICTRL_DATARATE(x)	(((x) & 0x7) << 16) + +#define MXC_CSPIPERIOD_32KHZ	(1 << 15) + +static unsigned long spi_bases[] = { +	0x43fa4000, +	0x50010000, +	0x53f84000, +}; + +static unsigned long spi_base; + +#endif + +spi_chipsel_type spi_chipsel[] = { +	(spi_chipsel_type)0, +	(spi_chipsel_type)1, +	(spi_chipsel_type)2, +	(spi_chipsel_type)3, +}; +int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline u32 reg_read(unsigned long addr) +{ +	return *(volatile unsigned long*)addr; +} + +static inline void reg_write(unsigned long addr, u32 val) +{ +	*(volatile unsigned long*)addr = val; +} + +static u32 spi_xchg_single(u32 data, int bitlen) +{ + +	unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); + +	if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) { +		cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) | +			MXC_CSPICTRL_BITCOUNT(bitlen - 1); +		reg_write(spi_base + MXC_CSPICTRL, cfg_reg); +	} + +	reg_write(spi_base + MXC_CSPITXDATA, data); + +	cfg_reg |= MXC_CSPICTRL_XCH; + +	reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + +	while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) +		; + +	return reg_read(spi_base + MXC_CSPIRXDATA); +} + +int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +{ +	int n_blks = (bitlen + 31) / 32; +	u32 *out_l, *in_l; +	int i; + +	if ((int)dout & 3 || (int)din & 3) { +		printf("Error: unaligned buffers in: %p, out: %p\n", din, dout); +		return 1; +	} + +	if (!spi_base) +		spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); + +	for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; +	     i < n_blks; +	     i++, in_l++, out_l++, bitlen -= 32) +		*in_l = spi_xchg_single(*out_l, bitlen); + +	return 0; +} + +void spi_init(void) +{ +} + +int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +{ +	unsigned int ctrl_reg; + +	if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || +	    dev > 3) +		return 1; + +	spi_base = spi_bases[bus]; + +	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | +		MXC_CSPICTRL_BITCOUNT(31) | +		MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ +		MXC_CSPICTRL_EN | +		MXC_CSPICTRL_MODE; + +	if (mode & SPI_CPHA) +		ctrl_reg |= MXC_CSPICTRL_PHA; +	if (!(mode & SPI_CPOL)) +		ctrl_reg |= MXC_CSPICTRL_POL; +	if (mode & SPI_CS_HIGH) +		ctrl_reg |= MXC_CSPICTRL_SSPOL; + +	reg_write(spi_base + MXC_CSPIRESET, 1); +	udelay(1); +	reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); +	reg_write(spi_base + MXC_CSPIPERIOD, +		  MXC_CSPIPERIOD_32KHZ); +	reg_write(spi_base + MXC_CSPIINT, 0); + +	return 0; +} diff --git a/include/asm-arm/arch-mx31/mx31-regs.h b/include/asm-arm/arch-mx31/mx31-regs.h index 380b401a4..d04072e67 100644 --- a/include/asm-arm/arch-mx31/mx31-regs.h +++ b/include/asm-arm/arch-mx31/mx31-regs.h @@ -37,6 +37,9 @@  #define CCM_UPCTL	(CCM_BASE + 0x10)  #define CCM_SPCTL	(CCM_BASE + 0x18)  #define CCM_COSR	(CCM_BASE + 0x1C) +#define CCM_CGR0	(CCM_BASE + 0x20) +#define CCM_CGR1	(CCM_BASE + 0x24) +#define CCM_CGR2	(CCM_BASE + 0x28)  #define CCMR_MDS	(1 << 7)  #define CCMR_SBYCS	(1 << 4) @@ -118,7 +121,9 @@  #define MUX_CTL_RXD1		0x82  #define MUX_CTL_TXD1		0x83  #define MUX_CTL_CSPI2_MISO	0x84 -/* 0x85 .. 0x8a */ +#define MUX_CTL_CSPI2_SS0	0x85 +#define MUX_CTL_CSPI2_SS1	0x86 +#define MUX_CTL_CSPI2_SS2	0x87  #define MUX_CTL_CSPI2_MOSI	0x8b  /* The modes a specific pin can be in diff --git a/include/spi.h b/include/spi.h index 03dc5bc03..3a55a68c4 100644 --- a/include/spi.h +++ b/include/spi.h @@ -24,6 +24,18 @@  #ifndef _SPI_H_  #define _SPI_H_ +/* SPI mode flags */ +#define	SPI_CPHA	0x01			/* clock phase */ +#define	SPI_CPOL	0x02			/* clock polarity */ +#define	SPI_MODE_0	(0|0)			/* (original MicroWire) */ +#define	SPI_MODE_1	(0|SPI_CPHA) +#define	SPI_MODE_2	(SPI_CPOL|0) +#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA) +#define	SPI_CS_HIGH	0x04			/* chipselect active high? */ +#define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */ +#define	SPI_3WIRE	0x10			/* SI/SO signals shared */ +#define	SPI_LOOP	0x20			/* loopback mode */ +  /*   * The function call pointer type used to drive the chip select.   */ @@ -68,6 +80,8 @@ void spi_init(void);   *   *   Returns: 0 on success, not 0 on failure   */ -int  spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din); +int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din); + +int spi_select(unsigned int bus, unsigned int dev, unsigned long mode);  #endif	/* _SPI_H_ */ |