177 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * Mix this utility code with some glue code to get one of several types of4 * simple SPI master driver. Two do polled word-at-a-time I/O:5 *6 * - GPIO/parport bitbangers. Provide chipselect() and txrx_word[](),7 * expanding the per-word routines from the inline templates below.8 *9 * - Drivers for controllers resembling bare shift registers. Provide10 * chipselect() and txrx_word[](), with custom setup()/cleanup() methods11 * that use your controller's clock and chipselect registers.12 *13 * Some hardware works well with requests at spi_transfer scope:14 *15 * - Drivers leveraging smarter hardware, with fifos or DMA; or for half16 * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(),17 * and custom setup()/cleanup() methods.18 */19 20/*21 * The code that knows what GPIO pins do what should have declared four22 * functions, ideally as inlines, before including this header:23 *24 * void setsck(struct spi_device *, int is_on);25 * void setmosi(struct spi_device *, int is_on);26 * int getmiso(struct spi_device *);27 * void spidelay(unsigned);28 *29 * setsck()'s is_on parameter is a zero/nonzero boolean.30 *31 * setmosi()'s is_on parameter is a zero/nonzero boolean.32 *33 * getmiso() is required to return 0 or 1 only. Any other value is invalid34 * and will result in improper operation.35 *36 * A non-inlined routine would call bitbang_txrx_*() routines. The37 * main loop could easily compile down to a handful of instructions,38 * especially if the delay is a NOP (to run at peak speed).39 *40 * Since this is software, the timings may not be exactly what your board's41 * chips need ... there may be several reasons you'd need to tweak timings42 * in these routines, not just to make it faster or slower to match a43 * particular CPU clock rate.44 *45 * ToDo: Maybe the bitrev macros can be used to improve the code?46 */47 48static inline u3249bitbang_txrx_be_cpha0(struct spi_device *spi,50 unsigned nsecs, unsigned cpol, unsigned flags,51 u32 word, u8 bits)52{53 /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */54 55 u32 oldbit = (!(word & (1<<(bits-1)))) << 31;56 /* clock starts at inactive polarity */57 for (word <<= (32 - bits); likely(bits); bits--) {58 59 /* setup MSB (to slave) on trailing edge */60 if ((flags & SPI_CONTROLLER_NO_TX) == 0) {61 if ((word & (1 << 31)) != oldbit) {62 setmosi(spi, word & (1 << 31));63 oldbit = word & (1 << 31);64 }65 }66 spidelay(nsecs); /* T(setup) */67 68 setsck(spi, !cpol);69 spidelay(nsecs);70 71 /* sample MSB (from slave) on leading edge */72 word <<= 1;73 if ((flags & SPI_CONTROLLER_NO_RX) == 0)74 word |= getmiso(spi);75 setsck(spi, cpol);76 }77 return word;78}79 80static inline u3281bitbang_txrx_be_cpha1(struct spi_device *spi,82 unsigned nsecs, unsigned cpol, unsigned flags,83 u32 word, u8 bits)84{85 /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */86 87 u32 oldbit = (!(word & (1<<(bits-1)))) << 31;88 /* clock starts at inactive polarity */89 for (word <<= (32 - bits); likely(bits); bits--) {90 91 /* setup MSB (to slave) on leading edge */92 setsck(spi, !cpol);93 if ((flags & SPI_CONTROLLER_NO_TX) == 0) {94 if ((word & (1 << 31)) != oldbit) {95 setmosi(spi, word & (1 << 31));96 oldbit = word & (1 << 31);97 }98 }99 spidelay(nsecs); /* T(setup) */100 101 setsck(spi, cpol);102 spidelay(nsecs);103 104 /* sample MSB (from slave) on trailing edge */105 word <<= 1;106 if ((flags & SPI_CONTROLLER_NO_RX) == 0)107 word |= getmiso(spi);108 }109 return word;110}111 112static inline u32113bitbang_txrx_le_cpha0(struct spi_device *spi,114 unsigned int nsecs, unsigned int cpol, unsigned int flags,115 u32 word, u8 bits)116{117 /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */118 119 u8 rxbit = bits - 1;120 u32 oldbit = !(word & 1);121 /* clock starts at inactive polarity */122 for (; likely(bits); bits--) {123 124 /* setup LSB (to slave) on trailing edge */125 if ((flags & SPI_CONTROLLER_NO_TX) == 0) {126 if ((word & 1) != oldbit) {127 setmosi(spi, word & 1);128 oldbit = word & 1;129 }130 }131 spidelay(nsecs); /* T(setup) */132 133 setsck(spi, !cpol);134 spidelay(nsecs);135 136 /* sample LSB (from slave) on leading edge */137 word >>= 1;138 if ((flags & SPI_CONTROLLER_NO_RX) == 0)139 word |= getmiso(spi) << rxbit;140 setsck(spi, cpol);141 }142 return word;143}144 145static inline u32146bitbang_txrx_le_cpha1(struct spi_device *spi,147 unsigned int nsecs, unsigned int cpol, unsigned int flags,148 u32 word, u8 bits)149{150 /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */151 152 u8 rxbit = bits - 1;153 u32 oldbit = !(word & 1);154 /* clock starts at inactive polarity */155 for (; likely(bits); bits--) {156 157 /* setup LSB (to slave) on leading edge */158 setsck(spi, !cpol);159 if ((flags & SPI_CONTROLLER_NO_TX) == 0) {160 if ((word & 1) != oldbit) {161 setmosi(spi, word & 1);162 oldbit = word & 1;163 }164 }165 spidelay(nsecs); /* T(setup) */166 167 setsck(spi, cpol);168 spidelay(nsecs);169 170 /* sample LSB (from slave) on trailing edge */171 word >>= 1;172 if ((flags & SPI_CONTROLLER_NO_RX) == 0)173 word |= getmiso(spi) << rxbit;174 }175 return word;176}177