u-boot/include/spi.h
Haavard Skinnemoen d255bb0e78 SPI API improvements
This patch gets rid of the spi_chipsel table and adds a handful of new
functions that makes the SPI layer cleaner and more flexible.

Instead of the spi_chipsel table, each board that wants to use SPI
gets to implement three hooks:
  * spi_cs_activate(): Activates the chipselect for a given slave
  * spi_cs_deactivate(): Deactivates the chipselect for a given slave
  * spi_cs_is_valid(): Determines if the given bus/chipselect
    combination can be activated.

Not all drivers may need those extra functions however. If that's the
case, the board code may just leave them out (assuming they know what
the driver needs) or rely on the linker to strip them out (assuming
--gc-sections is being used.)

To set up communication parameters for a given slave, the driver needs
to call spi_setup_slave(). This returns a pointer to an opaque
spi_slave struct which must be passed as a parameter to subsequent SPI
calls. This struct can be freed by calling spi_free_slave(), but most
driver probably don't want to do this.

Before starting one or more SPI transfers, the driver must call
spi_claim_bus() to gain exclusive access to the SPI bus and initialize
the hardware. When all transfers are done, the driver must call
spi_release_bus() to make the bus available to others, and possibly
shut down the SPI controller hardware.

spi_xfer() behaves mostly the same as before, but it now takes a
spi_slave parameter instead of a spi_chipsel function pointer. It also
got a new parameter, flags, which is used to specify chip select
behaviour. This may be extended with other flags in the future.

This patch has been build-tested on all powerpc and arm boards
involved. I have not tested NIOS since I don't have a toolchain for it
installed, so I expect some breakage there even though I've tried
fixing up everything I could find by visual inspection.

I have run-time tested this on AVR32 ATNGW100 using the atmel_spi and
DataFlash drivers posted as a follow-up. I'd like some help testing
other boards that use the existing SPI API.

But most of all, I'd like some comments on the new API. Is this stuff
usable for everyone? If not, why?

Changed in v4:
  - Build fixes for various boards, drivers and commands
  - Provide common struct spi_slave definition that can be extended by
    drivers
  - Pass a struct spi_slave * to spi_cs_activate and spi_cs_deactivate
  - Make default bus and mode build-time configurable
  - Override default SPI bus ID and mode on mx32ads and imx31_litekit.

Changed in v3:
  - Add opaque struct spi_slave for controller-specific data associated
    with a slave.
  - Add spi_claim_bus() and spi_release_bus()
  - Add spi_free_slave()
  - spi_setup() is now called spi_setup_slave() and returns a
    struct spi_slave
  - soft_spi now supports four SPI modes (CPOL|CPHA)
  - Add bus parameter to spi_setup_slave()
  - Convert the new i.MX32 SPI driver
  - Convert the new MC13783 RTC driver

Changed in v2:
  - Convert the mpc8xxx_spi driver and the mpc8349emds board to the
    new API.

Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Tested-by: Guennadi Liakhovetski <lg@denx.de>
2008-06-03 20:28:50 +02:00

192 lines
6.8 KiB
C

/*
* (C) Copyright 2001
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
#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 /* CS 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 */
/* SPI transfer flags */
#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */
#define SPI_XFER_END 0x02 /* Deassert CS after transfer */
/*-----------------------------------------------------------------------
* Representation of a SPI slave, i.e. what we're communicating with.
*
* Drivers are expected to extend this with controller-specific data.
*
* bus: ID of the bus that the slave is attached to.
* cs: ID of the chip select connected to the slave.
*/
struct spi_slave {
unsigned int bus;
unsigned int cs;
};
/*-----------------------------------------------------------------------
* Initialization, must be called once on start up.
*
* TODO: I don't think we really need this.
*/
void spi_init(void);
/*-----------------------------------------------------------------------
* Set up communications parameters for a SPI slave.
*
* This must be called once for each slave. Note that this function
* usually doesn't touch any actual hardware, it only initializes the
* contents of spi_slave so that the hardware can be easily
* initialized later.
*
* bus: Bus ID of the slave chip.
* cs: Chip select ID of the slave chip on the specified bus.
* max_hz: Maximum SCK rate in Hz.
* mode: Clock polarity, clock phase and other parameters.
*
* Returns: A spi_slave reference that can be used in subsequent SPI
* calls, or NULL if one or more of the parameters are not supported.
*/
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode);
/*-----------------------------------------------------------------------
* Free any memory associated with a SPI slave.
*
* slave: The SPI slave
*/
void spi_free_slave(struct spi_slave *slave);
/*-----------------------------------------------------------------------
* Claim the bus and prepare it for communication with a given slave.
*
* This must be called before doing any transfers with a SPI slave. It
* will enable and initialize any SPI hardware as necessary, and make
* sure that the SCK line is in the correct idle state. It is not
* allowed to claim the same bus for several slaves without releasing
* the bus in between.
*
* slave: The SPI slave
*
* Returns: 0 if the bus was claimed successfully, or a negative value
* if it wasn't.
*/
int spi_claim_bus(struct spi_slave *slave);
/*-----------------------------------------------------------------------
* Release the SPI bus
*
* This must be called once for every call to spi_claim_bus() after
* all transfers have finished. It may disable any SPI hardware as
* appropriate.
*
* slave: The SPI slave
*/
void spi_release_bus(struct spi_slave *slave);
/*-----------------------------------------------------------------------
* SPI transfer
*
* This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
* "bitlen" bits in the SPI MISO port. That's just the way SPI works.
*
* The source of the outgoing bits is the "dout" parameter and the
* destination of the input bits is the "din" parameter. Note that "dout"
* and "din" can point to the same memory location, in which case the
* input data overwrites the output data (since both are buffered by
* temporary variables, this is OK).
*
* spi_xfer() interface:
* slave: The SPI slave which will be sending/receiving the data.
* bitlen: How many bits to write and read.
* dout: Pointer to a string of bits to send out. The bits are
* held in a byte array and are sent MSB first.
* din: Pointer to a string of bits that will be filled in.
* flags: A bitwise combination of SPI_XFER_* flags.
*
* Returns: 0 on success, not 0 on failure
*/
int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
void *din, unsigned long flags);
/*-----------------------------------------------------------------------
* Determine if a SPI chipselect is valid.
* This function is provided by the board if the low-level SPI driver
* needs it to determine if a given chipselect is actually valid.
*
* Returns: 1 if bus:cs identifies a valid chip on this board, 0
* otherwise.
*/
int spi_cs_is_valid(unsigned int bus, unsigned int cs);
/*-----------------------------------------------------------------------
* Activate a SPI chipselect.
* This function is provided by the board code when using a driver
* that can't control its chipselects automatically (e.g.
* common/soft_spi.c). When called, it should activate the chip select
* to the device identified by "slave".
*/
void spi_cs_activate(struct spi_slave *slave);
/*-----------------------------------------------------------------------
* Deactivate a SPI chipselect.
* This function is provided by the board code when using a driver
* that can't control its chipselects automatically (e.g.
* common/soft_spi.c). When called, it should deactivate the chip
* select to the device identified by "slave".
*/
void spi_cs_deactivate(struct spi_slave *slave);
/*-----------------------------------------------------------------------
* Write 8 bits, then read 8 bits.
* slave: The SPI slave we're communicating with
* byte: Byte to be written
*
* Returns: The value that was read, or a negative value on error.
*
* TODO: This function probably shouldn't be inlined.
*/
static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte)
{
unsigned char dout[2];
unsigned char din[2];
int ret;
dout[0] = byte;
dout[1] = 0;
ret = spi_xfer(slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END);
return ret < 0 ? ret : din[1];
}
#endif /* _SPI_H_ */