brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 0cab48b Raw
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