| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 1 | #ifndef	__SPI_BITBANG_H | 
|  | 2 | #define	__SPI_BITBANG_H | 
|  | 3 |  | 
|  | 4 | /* | 
|  | 5 | * Mix this utility code with some glue code to get one of several types of | 
|  | 6 | * simple SPI master driver.  Two do polled word-at-a-time I/O: | 
|  | 7 | * | 
|  | 8 | *   -	GPIO/parport bitbangers.  Provide chipselect() and txrx_word[](), | 
|  | 9 | *	expanding the per-word routines from the inline templates below. | 
|  | 10 | * | 
|  | 11 | *   -	Drivers for controllers resembling bare shift registers.  Provide | 
|  | 12 | *	chipselect() and txrx_word[](), with custom setup()/cleanup() methods | 
|  | 13 | *	that use your controller's clock and chipselect registers. | 
|  | 14 | * | 
|  | 15 | * Some hardware works well with requests at spi_transfer scope: | 
|  | 16 | * | 
|  | 17 | *   -	Drivers leveraging smarter hardware, with fifos or DMA; or for half | 
| Uwe Kleine-König | b71a8eb | 2009-10-06 12:42:51 +0200 | [diff] [blame] | 18 | *	duplex (MicroWire) controllers.  Provide chipselect() and txrx_bufs(), | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 19 | *	and custom setup()/cleanup() methods. | 
|  | 20 | */ | 
| Fernando Luis Vazquez Cao | effdb94 | 2008-10-29 14:01:21 -0700 | [diff] [blame] | 21 |  | 
|  | 22 | #include <linux/workqueue.h> | 
|  | 23 |  | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 24 | struct spi_bitbang { | 
|  | 25 | struct workqueue_struct	*workqueue; | 
|  | 26 | struct work_struct	work; | 
|  | 27 |  | 
|  | 28 | spinlock_t		lock; | 
|  | 29 | struct list_head	queue; | 
|  | 30 | u8			busy; | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 31 | u8			use_dma; | 
| David Brownell | dccd573 | 2007-07-17 04:04:02 -0700 | [diff] [blame] | 32 | u8			flags;		/* extra spi->mode support */ | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 33 |  | 
|  | 34 | struct spi_master	*master; | 
|  | 35 |  | 
| Imre Deak | 4cff33f | 2006-02-17 10:02:18 -0800 | [diff] [blame] | 36 | /* setup_transfer() changes clock and/or wordsize to match settings | 
|  | 37 | * for this transfer; zeroes restore defaults from spi_device. | 
|  | 38 | */ | 
|  | 39 | int	(*setup_transfer)(struct spi_device *spi, | 
|  | 40 | struct spi_transfer *t); | 
|  | 41 |  | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 42 | void	(*chipselect)(struct spi_device *spi, int is_on); | 
| Vitaly Wool | 8275c64 | 2006-01-08 13:34:28 -0800 | [diff] [blame] | 43 | #define	BITBANG_CS_ACTIVE	1	/* normally nCS, active low */ | 
|  | 44 | #define	BITBANG_CS_INACTIVE	0 | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 45 |  | 
| Vitaly Wool | 8275c64 | 2006-01-08 13:34:28 -0800 | [diff] [blame] | 46 | /* txrx_bufs() may handle dma mapping for transfers that don't | 
|  | 47 | * already have one (transfer.{tx,rx}_dma is zero), or use PIO | 
|  | 48 | */ | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 49 | int	(*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); | 
| Vitaly Wool | 8275c64 | 2006-01-08 13:34:28 -0800 | [diff] [blame] | 50 |  | 
|  | 51 | /* txrx_word[SPI_MODE_*]() just looks like a shift register */ | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 52 | u32	(*txrx_word[4])(struct spi_device *spi, | 
|  | 53 | unsigned nsecs, | 
|  | 54 | u32 word, u8 bits); | 
|  | 55 | }; | 
|  | 56 |  | 
|  | 57 | /* you can call these default bitbang->master methods from your custom | 
|  | 58 | * methods, if you like. | 
|  | 59 | */ | 
|  | 60 | extern int spi_bitbang_setup(struct spi_device *spi); | 
| Hans-Peter Nilsson | 0ffa028 | 2007-02-12 00:52:45 -0800 | [diff] [blame] | 61 | extern void spi_bitbang_cleanup(struct spi_device *spi); | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 62 | extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); | 
| Kumar Gala | ff9f477 | 2006-04-02 16:06:35 -0500 | [diff] [blame] | 63 | extern int spi_bitbang_setup_transfer(struct spi_device *spi, | 
|  | 64 | struct spi_transfer *t); | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 65 |  | 
|  | 66 | /* start or stop queue processing */ | 
|  | 67 | extern int spi_bitbang_start(struct spi_bitbang *spi); | 
|  | 68 | extern int spi_bitbang_stop(struct spi_bitbang *spi); | 
|  | 69 |  | 
|  | 70 | #endif	/* __SPI_BITBANG_H */ | 
|  | 71 |  | 
|  | 72 | /*-------------------------------------------------------------------------*/ | 
|  | 73 |  | 
|  | 74 | #ifdef	EXPAND_BITBANG_TXRX | 
|  | 75 |  | 
|  | 76 | /* | 
|  | 77 | * The code that knows what GPIO pins do what should have declared four | 
|  | 78 | * functions, ideally as inlines, before #defining EXPAND_BITBANG_TXRX | 
|  | 79 | * and including this header: | 
|  | 80 | * | 
|  | 81 | *  void setsck(struct spi_device *, int is_on); | 
|  | 82 | *  void setmosi(struct spi_device *, int is_on); | 
|  | 83 | *  int getmiso(struct spi_device *); | 
|  | 84 | *  void spidelay(unsigned); | 
|  | 85 | * | 
| Michael Buesch | 01b24fe | 2009-02-20 15:38:49 -0800 | [diff] [blame] | 86 | * setsck()'s is_on parameter is a zero/nonzero boolean. | 
|  | 87 | * | 
|  | 88 | * setmosi()'s is_on parameter is a zero/nonzero boolean. | 
|  | 89 | * | 
|  | 90 | * getmiso() is required to return 0 or 1 only. Any other value is invalid | 
|  | 91 | * and will result in improper operation. | 
|  | 92 | * | 
| David Brownell | 9904f22 | 2006-01-08 13:34:26 -0800 | [diff] [blame] | 93 | * A non-inlined routine would call bitbang_txrx_*() routines.  The | 
|  | 94 | * main loop could easily compile down to a handful of instructions, | 
|  | 95 | * especially if the delay is a NOP (to run at peak speed). | 
|  | 96 | * | 
|  | 97 | * Since this is software, the timings may not be exactly what your board's | 
|  | 98 | * chips need ... there may be several reasons you'd need to tweak timings | 
|  | 99 | * in these routines, not just make to make it faster or slower to match a | 
|  | 100 | * particular CPU clock rate. | 
|  | 101 | */ | 
|  | 102 |  | 
|  | 103 | static inline u32 | 
|  | 104 | bitbang_txrx_be_cpha0(struct spi_device *spi, | 
|  | 105 | unsigned nsecs, unsigned cpol, | 
|  | 106 | u32 word, u8 bits) | 
|  | 107 | { | 
|  | 108 | /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ | 
|  | 109 |  | 
|  | 110 | /* clock starts at inactive polarity */ | 
|  | 111 | for (word <<= (32 - bits); likely(bits); bits--) { | 
|  | 112 |  | 
|  | 113 | /* setup MSB (to slave) on trailing edge */ | 
|  | 114 | setmosi(spi, word & (1 << 31)); | 
|  | 115 | spidelay(nsecs);	/* T(setup) */ | 
|  | 116 |  | 
|  | 117 | setsck(spi, !cpol); | 
|  | 118 | spidelay(nsecs); | 
|  | 119 |  | 
|  | 120 | /* sample MSB (from slave) on leading edge */ | 
|  | 121 | word <<= 1; | 
|  | 122 | word |= getmiso(spi); | 
|  | 123 | setsck(spi, cpol); | 
|  | 124 | } | 
|  | 125 | return word; | 
|  | 126 | } | 
|  | 127 |  | 
|  | 128 | static inline u32 | 
|  | 129 | bitbang_txrx_be_cpha1(struct spi_device *spi, | 
|  | 130 | unsigned nsecs, unsigned cpol, | 
|  | 131 | u32 word, u8 bits) | 
|  | 132 | { | 
|  | 133 | /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ | 
|  | 134 |  | 
|  | 135 | /* clock starts at inactive polarity */ | 
|  | 136 | for (word <<= (32 - bits); likely(bits); bits--) { | 
|  | 137 |  | 
|  | 138 | /* setup MSB (to slave) on leading edge */ | 
|  | 139 | setsck(spi, !cpol); | 
|  | 140 | setmosi(spi, word & (1 << 31)); | 
|  | 141 | spidelay(nsecs); /* T(setup) */ | 
|  | 142 |  | 
|  | 143 | setsck(spi, cpol); | 
|  | 144 | spidelay(nsecs); | 
|  | 145 |  | 
|  | 146 | /* sample MSB (from slave) on trailing edge */ | 
|  | 147 | word <<= 1; | 
|  | 148 | word |= getmiso(spi); | 
|  | 149 | } | 
|  | 150 | return word; | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | #endif	/* EXPAND_BITBANG_TXRX */ |