spi_bitbang.h 4.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#ifndef	__SPI_BITBANG_H
#define	__SPI_BITBANG_H

/*
 * Mix this utility code with some glue code to get one of several types of
 * simple SPI master driver.  Two do polled word-at-a-time I/O:
 *
 *   -	GPIO/parport bitbangers.  Provide chipselect() and txrx_word[](),
 *	expanding the per-word routines from the inline templates below.
 *
 *   -	Drivers for controllers resembling bare shift registers.  Provide
 *	chipselect() and txrx_word[](), with custom setup()/cleanup() methods
 *	that use your controller's clock and chipselect registers.
 *
 * Some hardware works well with requests at spi_transfer scope:
 *
 *   -	Drivers leveraging smarter hardware, with fifos or DMA; or for half
18
 *	duplex (MicroWire) controllers.  Provide chipselect() and txrx_bufs(),
19 20
 *	and custom setup()/cleanup() methods.
 */
F
Fernando Luis Vazquez Cao 已提交
21 22 23

#include <linux/workqueue.h>

24 25 26 27 28 29 30 31
struct spi_bitbang {
	struct workqueue_struct	*workqueue;
	struct work_struct	work;

	spinlock_t		lock;
	struct list_head	queue;
	u8			busy;
	u8			use_dma;
32
	u8			flags;		/* extra spi->mode support */
33 34 35

	struct spi_master	*master;

36 37 38 39 40 41
	/* setup_transfer() changes clock and/or wordsize to match settings
	 * for this transfer; zeroes restore defaults from spi_device.
	 */
	int	(*setup_transfer)(struct spi_device *spi,
			struct spi_transfer *t);

42
	void	(*chipselect)(struct spi_device *spi, int is_on);
43 44
#define	BITBANG_CS_ACTIVE	1	/* normally nCS, active low */
#define	BITBANG_CS_INACTIVE	0
45

46 47 48
	/* txrx_bufs() may handle dma mapping for transfers that don't
	 * already have one (transfer.{tx,rx}_dma is zero), or use PIO
	 */
49
	int	(*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
50 51

	/* txrx_word[SPI_MODE_*]() just looks like a shift register */
52 53 54 55 56 57 58 59 60
	u32	(*txrx_word[4])(struct spi_device *spi,
			unsigned nsecs,
			u32 word, u8 bits);
};

/* you can call these default bitbang->master methods from your custom
 * methods, if you like.
 */
extern int spi_bitbang_setup(struct spi_device *spi);
61
extern void spi_bitbang_cleanup(struct spi_device *spi);
62
extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
63 64
extern int spi_bitbang_setup_transfer(struct spi_device *spi,
				      struct spi_transfer *t);
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

/* start or stop queue processing */
extern int spi_bitbang_start(struct spi_bitbang *spi);
extern int spi_bitbang_stop(struct spi_bitbang *spi);

#endif	/* __SPI_BITBANG_H */

/*-------------------------------------------------------------------------*/

#ifdef	EXPAND_BITBANG_TXRX

/*
 * The code that knows what GPIO pins do what should have declared four
 * functions, ideally as inlines, before #defining EXPAND_BITBANG_TXRX
 * and including this header:
 *
 *  void setsck(struct spi_device *, int is_on);
 *  void setmosi(struct spi_device *, int is_on);
 *  int getmiso(struct spi_device *);
 *  void spidelay(unsigned);
 *
86 87 88 89 90 91 92
 * setsck()'s is_on parameter is a zero/nonzero boolean.
 *
 * setmosi()'s is_on parameter is a zero/nonzero boolean.
 *
 * getmiso() is required to return 0 or 1 only. Any other value is invalid
 * and will result in improper operation.
 *
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
 * A non-inlined routine would call bitbang_txrx_*() routines.  The
 * main loop could easily compile down to a handful of instructions,
 * especially if the delay is a NOP (to run at peak speed).
 *
 * Since this is software, the timings may not be exactly what your board's
 * chips need ... there may be several reasons you'd need to tweak timings
 * in these routines, not just make to make it faster or slower to match a
 * particular CPU clock rate.
 */

static inline u32
bitbang_txrx_be_cpha0(struct spi_device *spi,
		unsigned nsecs, unsigned cpol,
		u32 word, u8 bits)
{
	/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */

	/* clock starts at inactive polarity */
	for (word <<= (32 - bits); likely(bits); bits--) {

		/* setup MSB (to slave) on trailing edge */
		setmosi(spi, word & (1 << 31));
		spidelay(nsecs);	/* T(setup) */

		setsck(spi, !cpol);
		spidelay(nsecs);

		/* sample MSB (from slave) on leading edge */
		word <<= 1;
		word |= getmiso(spi);
		setsck(spi, cpol);
	}
	return word;
}

static inline u32
bitbang_txrx_be_cpha1(struct spi_device *spi,
		unsigned nsecs, unsigned cpol,
		u32 word, u8 bits)
{
	/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */

	/* clock starts at inactive polarity */
	for (word <<= (32 - bits); likely(bits); bits--) {

		/* setup MSB (to slave) on leading edge */
		setsck(spi, !cpol);
		setmosi(spi, word & (1 << 31));
		spidelay(nsecs); /* T(setup) */

		setsck(spi, cpol);
		spidelay(nsecs);

		/* sample MSB (from slave) on trailing edge */
		word <<= 1;
		word |= getmiso(spi);
	}
	return word;
}

#endif	/* EXPAND_BITBANG_TXRX */