diff options
| -rw-r--r-- | drivers/misc/fsl_pmic.c | 10 | ||||
| -rw-r--r-- | drivers/spi/mxc_spi.c | 149 | 
2 files changed, 118 insertions, 41 deletions
| diff --git a/drivers/misc/fsl_pmic.c b/drivers/misc/fsl_pmic.c index dca0a1d57..5ee1de176 100644 --- a/drivers/misc/fsl_pmic.c +++ b/drivers/misc/fsl_pmic.c @@ -46,6 +46,7 @@ void pmic_spi_free(struct spi_slave *slave)  u32 pmic_reg(u32 reg, u32 val, u32 write)  {  	u32 pmic_tx, pmic_rx; +	u32 tmp;  	if (!slave) {  		slave = pmic_spi_probe(); @@ -65,7 +66,9 @@ u32 pmic_reg(u32 reg, u32 val, u32 write)  	pmic_tx = (write << 31) | (reg << 25) | (val & 0x00FFFFFF); -	if (spi_xfer(slave, 4 << 3, &pmic_tx, &pmic_rx, +	tmp = cpu_to_be32(pmic_tx); + +	if (spi_xfer(slave, 4 << 3, &tmp, &pmic_rx,  			SPI_XFER_BEGIN | SPI_XFER_END)) {  		spi_release_bus(slave);  		return -1; @@ -73,7 +76,8 @@ u32 pmic_reg(u32 reg, u32 val, u32 write)  	if (write) {  		pmic_tx &= ~(1 << 31); -		if (spi_xfer(slave, 4 << 3, &pmic_tx, &pmic_rx, +		tmp = cpu_to_be32(pmic_tx); +		if (spi_xfer(slave, 4 << 3, &tmp, &pmic_rx,  			SPI_XFER_BEGIN | SPI_XFER_END)) {  			spi_release_bus(slave);  			return -1; @@ -81,7 +85,7 @@ u32 pmic_reg(u32 reg, u32 val, u32 write)  	}  	spi_release_bus(slave); -	return pmic_rx; +	return cpu_to_be32(pmic_rx);  }  void pmic_reg_write(u32 reg, u32 value) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index c6c8f60c3..d558137c9 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -62,6 +62,7 @@  #define MXC_CSPICTRL_MAXBITS	0x1f  #define MXC_CSPIPERIOD_32KHZ	(1 << 15) +#define MAX_SPI_BYTES	4  static unsigned long spi_bases[] = {  	0x43fa4000, @@ -95,6 +96,7 @@ static unsigned long spi_bases[] = {  #define MXC_CSPICTRL_RXOVF	(1 << 6)  #define MXC_CSPIPERIOD_32KHZ	(1 << 15) +#define MAX_SPI_BYTES	32  /* Bit position inside CTRL register to be associated with SS */  #define MXC_CSPICTRL_CHAN	18 @@ -252,13 +254,15 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs,  }  #endif -static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen, -			   unsigned long flags) +int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, +	const u8 *dout, u8 *din, unsigned long flags)  {  	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); +	int nbytes = (bitlen + 7) / 8; +	u32 data, cnt, i; -	if (flags & SPI_XFER_BEGIN) -		spi_cs_activate(slave); +	debug("%s: bitlen %d dout 0x%x din 0x%x\n", +		__func__, bitlen, (u32)dout, (u32)din);  	mxcs->ctrl_reg = (mxcs->ctrl_reg &  		~MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS)) | @@ -273,8 +277,46 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen,  	reg_write(mxcs->base + MXC_CSPISTAT,  		MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); -	debug("Sending SPI 0x%x\n", data); -	reg_write(mxcs->base + MXC_CSPITXDATA, data); +	/* +	 * The SPI controller works only with words, +	 * check if less than a word is sent. +	 * Access to the FIFO is only 32 bit +	 */ +	if (bitlen % 32) { +		data = 0; +		cnt = (bitlen % 32) / 8; +		if (dout) { +			for (i = 0; i < cnt; i++) { +				data = (data << 8) | (*dout++ & 0xFF); +			} +		} +		debug("Sending SPI 0x%x\n", data); + +		reg_write(mxcs->base + MXC_CSPITXDATA, data); +		nbytes -= cnt; +	} + +	data = 0; + +	while (nbytes > 0) { +		data = 0; +		if (dout) { +			/* Buffer is not 32-bit aligned */ +			if ((unsigned long)dout & 0x03) { +				data = 0; +				for (i = 0; i < 4; i++, data <<= 8) { +					data = (data << 8) | (*dout++ & 0xFF); +				} +			} else { +				data = *(u32 *)dout; +				data = cpu_to_be32(data); +			} +			dout += 4; +		} +		debug("Sending SPI 0x%x\n", data); +		reg_write(mxcs->base + MXC_CSPITXDATA, data); +		nbytes -= 4; +	}  	/* FIFO is written, now starts the transfer setting the XCH bit */  	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg | @@ -288,49 +330,78 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen,  	reg_write(mxcs->base + MXC_CSPISTAT,  		MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); -	data = reg_read(mxcs->base + MXC_CSPIRXDATA); -	debug("SPI Rx: 0x%x\n", data); +	nbytes = (bitlen + 7) / 8; -	if (flags & SPI_XFER_END) -		spi_cs_deactivate(slave); +	cnt = nbytes % 32; -	return data; +	if (bitlen % 32) { +		data = reg_read(mxcs->base + MXC_CSPIRXDATA); +		cnt = (bitlen % 32) / 8; +		debug("SPI Rx unaligned: 0x%x\n", data); +		if (din) { +			for (i = 0; i < cnt; i++, data >>= 8) { +				*din++ = data & 0xFF; +			} +		} +		nbytes -= cnt; +	} + +	while (nbytes > 0) { +		u32 tmp; +		tmp = reg_read(mxcs->base + MXC_CSPIRXDATA); +		data = cpu_to_be32(tmp); +		debug("SPI Rx: 0x%x 0x%x\n", tmp, data); +		cnt = min(nbytes, sizeof(data)); +		if (din) { +			memcpy(din, &data, cnt); +			din += cnt; +		} +		nbytes -= cnt; +	} + +	return 0;  } +  int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  		void *din, unsigned long flags)  { -	int n_blks = (bitlen + 31) / 32; -	u32 *out_l, *in_l; -	int i; +	int n_bytes = (bitlen + 7) / 8; +	int n_bits; +	int ret; +	u32 blk_size; +	u8 *p_outbuf = (u8 *)dout; +	u8 *p_inbuf = (u8 *)din; -	if ((int)dout & 3 || (int)din & 3) { -		printf("Error: unaligned buffers in: %p, out: %p\n", din, dout); -		return 1; -	} +	if (!slave) +		return -1; -	/* This driver is currently partly broken, alert the user */ -	if (bitlen > 16 && (bitlen % 32)) { -		printf("Error: SPI transfer with bitlen=%d is broken.\n", -		       bitlen); -		return 1; -	} +	if (flags & SPI_XFER_BEGIN) +		spi_cs_activate(slave); -	for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; -	     i < n_blks; -	     i++, in_l++, out_l++, bitlen -= 32) { -		u32 data = spi_xchg_single(slave, *out_l, bitlen, flags); +	while (n_bytes > 0) { -		/* Check if we're only transfering 8 or 16 bits */ -		if (!i) { -			if (bitlen < 9) -				*(u8 *)din = data; -			else if (bitlen < 17) -				*(u16 *)din = data; -			else -				*in_l = data; -		} +		if (n_bytes < MAX_SPI_BYTES) +			blk_size = n_bytes; +		else +			blk_size = MAX_SPI_BYTES; + +		n_bits = blk_size * 8; + +		ret = spi_xchg_single(slave, n_bits, p_outbuf, p_inbuf, 0); + +		if (ret) +			return ret; +		if (dout) +			p_outbuf += blk_size; +		if (din) +			p_inbuf += blk_size; +		n_bytes -= blk_size; +	} + +	if (flags & SPI_XFER_END) { +		spi_cs_deactivate(slave);  	}  	return 0; @@ -378,8 +449,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,  		return NULL;  	mxcs = malloc(sizeof(struct mxc_spi_slave)); -	if (!mxcs) +	if (!mxcs) { +		puts("mxc_spi: SPI Slave not allocated !\n");  		return NULL; +	}  	ret = decode_cs(mxcs, cs);  	if (ret < 0) { |