summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-bitbang-txrx.h
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-22 14:52:44 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-22 14:52:44 -0700
commit7235dd74a4733d4b3651349b5261d2e06996427d (patch)
tree737d4141e77fdd6bfd8c9878ed4f7fe293e7b629 /drivers/spi/spi-bitbang-txrx.h
parentc7c8518498e82591d7784452f5674c3aeb4d079c (diff)
parent22a85e4cd51b49ec99703ddfdff8686d5442a093 (diff)
Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
* 'spi/next' of git://git.secretlab.ca/git/linux-2.6: (34 commits) spi/imx: add device tree probe support spi/imx: copy gpio number passed by platform data into driver private data spi/imx: use soc name in spi device type naming scheme spi/imx: merge type SPI_IMX_VER_0_7 into SPI_IMX_VER_0_4 spi/imx: do not use spi_imx2_3 to name SPI_IMX_VER_2_3 function and macro spi/imx: use mx21 to name SPI_IMX_VER_0_0 function and macro spi/imx: do not make copy of spi_imx_devtype_data spi/dw: Add spi number into spi irq desc spi/tegra: Use engineering names in DT compatible property spi/fsl_spi: fix CPM spi driver mach-s3c2410: remove unused spi-gpio.h file spi: remove obsolete spi-s3c24xx-gpio driver mach-gta2: remove unused spi-gpio.h include mach-qt2410: convert to spi_gpio mach-jive: convert to spi_gpio spi/pxa2xx: Remove unavailable ssp_type from documentation spi/bfin_spi: uninline fat queue funcs spi/bfin_spi: constify pin array spi/bfin_spi: use structs for accessing hardware regs spi/topcliff-pch: Support new device ML7223 IOH ... Fix up trivial conflict in arch/arm/mach-ep93xx/Makefile
Diffstat (limited to 'drivers/spi/spi-bitbang-txrx.h')
-rw-r--r--drivers/spi/spi-bitbang-txrx.h97
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h
new file mode 100644
index 000000000000..c16bf853c3eb
--- /dev/null
+++ b/drivers/spi/spi-bitbang-txrx.h
@@ -0,0 +1,97 @@
+/*
+ * 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
+ * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(),
+ * and custom setup()/cleanup() methods.
+ */
+
+/*
+ * The code that knows what GPIO pins do what should have declared four
+ * functions, ideally as inlines, before 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);
+ *
+ * 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.
+ *
+ * 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, unsigned flags,
+ 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 */
+ if ((flags & SPI_MASTER_NO_TX) == 0)
+ setmosi(spi, word & (1 << 31));
+ spidelay(nsecs); /* T(setup) */
+
+ setsck(spi, !cpol);
+ spidelay(nsecs);
+
+ /* sample MSB (from slave) on leading edge */
+ word <<= 1;
+ if ((flags & SPI_MASTER_NO_RX) == 0)
+ word |= getmiso(spi);
+ setsck(spi, cpol);
+ }
+ return word;
+}
+
+static inline u32
+bitbang_txrx_be_cpha1(struct spi_device *spi,
+ unsigned nsecs, unsigned cpol, unsigned flags,
+ 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);
+ if ((flags & SPI_MASTER_NO_TX) == 0)
+ setmosi(spi, word & (1 << 31));
+ spidelay(nsecs); /* T(setup) */
+
+ setsck(spi, cpol);
+ spidelay(nsecs);
+
+ /* sample MSB (from slave) on trailing edge */
+ word <<= 1;
+ if ((flags & SPI_MASTER_NO_RX) == 0)
+ word |= getmiso(spi);
+ }
+ return word;
+}