664 lines
20 KiB
C
664 lines
20 KiB
C
/****************************************************************************
|
|
* include/nuttx/spi/spi_bitbang.c
|
|
*
|
|
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <nuttx/spi/spi_bitbang.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
/* Usage ********************************************************************/
|
|
/* To use this logic, you should provide a C file that does the following:
|
|
*
|
|
* - Defines SPI_SETSCK and SPI_CLRSCK to set and clear the SCK signal
|
|
* - Defines SPI_SETMOSI and SPI_CLRMOSI to set and clear the MISO signal
|
|
* - Defines SPI_GETMISO to sample the MISO state
|
|
* - Defines SPI_PERBIT_NSEC which is the minimum time to transfer one bit.
|
|
* This determines the maximum frequency.
|
|
* - Other configuration options:
|
|
* SPI_BITBAND_LOOPSPERMSEC - Delay loop calibration
|
|
* SPI_BITBANG_DISABLEMODE0 - Define to disable Mode 0 support
|
|
* SPI_BITBANG_DISABLEMODE1 - Define to disable Mode 1 support
|
|
* SPI_BITBANG_DISABLEMODE2 - Define to disable Mode 2 support
|
|
* SPI_BITBANG_DISABLEMODE3 - Define to disable Mode 3 support
|
|
* - Provide implementations of spi_select(), spi_status(), and spi_cmddata().
|
|
* - Then include this file
|
|
* - Provide an initialization function that initializes the GPIO pins used
|
|
* in the bit bang interface and calls spi_create_bitbang().
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static void spi_delay(uint32_t holdtime);
|
|
static void spi_select(FAR struct spi_bitbang_s *priv,
|
|
uint32_t devid, bool selected);
|
|
static uint32_t spi_setfrequency(FAR struct spi_bitbang_s *priv,
|
|
uint32_t frequency);
|
|
static void spi_setmode(FAR struct spi_bitbang_s *priv,
|
|
enum spi_mode_e mode);
|
|
#ifndef SPI_BITBANG_DISABLEMODE0
|
|
static uint16_t spi_bitexchange0(uint16_t dataout, uint32_t holdtime);
|
|
#endif
|
|
#ifndef SPI_BITBANG_DISABLEMODE1
|
|
static uint16_t spi_bitexchange1(uint16_t dataout, uint32_t holdtime);
|
|
#endif
|
|
#ifndef SPI_BITBANG_DISABLEMODE2
|
|
static uint16_t spi_bitexchange2(uint16_t dataout, uint32_t holdtime);
|
|
#endif
|
|
#ifndef SPI_BITBANG_DISABLEMODE3
|
|
static uint16_t spi_bitexchange3(uint16_t dataout, uint32_t holdtime);
|
|
#endif
|
|
static uint16_t spi_exchange(FAR struct spi_bitbang_s *priv,
|
|
uint16_t dataout);
|
|
static uint8_t spi_status(FAR struct spi_bitbang_s *priv,
|
|
uint32_t devid);
|
|
#ifdef CONFIG_SPI_CMDDATA
|
|
static int spi_cmddata(FAR struct spi_bitbang_s *priv,
|
|
uint32_t devid, bool cmd);
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const struct spi_bitbang_ops_s g_spiops =
|
|
{
|
|
spi_select, /* select */
|
|
spi_setfrequency, /* setfrequency */
|
|
spi_setmode, /* setmode */
|
|
spi_exchange, /* exchange */
|
|
spi_status, /* status */
|
|
#ifdef CONFIG_SPI_CMDDATA
|
|
spi_cmddata, /* cmddata */
|
|
#endif
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
* Name: spi_delay
|
|
*
|
|
* Description:
|
|
* Delay for a specified number of loops
|
|
*
|
|
* Input Parameters:
|
|
* count - The number of loops
|
|
*
|
|
* Returned Value:
|
|
* Returns the actual frequency selected
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void spi_delay(uint32_t holdtime)
|
|
{
|
|
volatile int i;
|
|
|
|
for (i = 0; i < holdtime; i++);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: spi_setfrequency
|
|
*
|
|
* Description:
|
|
* Set the SPI frequency.
|
|
*
|
|
* Input Parameters:
|
|
* dev - Device-specific state data
|
|
* frequency - The SPI frequency requested
|
|
*
|
|
* Returned Value:
|
|
* Returns the actual frequency selected
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint32_t spi_setfrequency(FAR struct spi_bitbang_s *priv, uint32_t frequency)
|
|
{
|
|
uint32_t pnsec;
|
|
|
|
/* SPI frequency cannot be precisely controlled with a bit-bang interface.
|
|
* Freqency corresponds to delay in toggle the SPI clock line: Set high,
|
|
* wait, set low, wait, set high, wait, etc.
|
|
*
|
|
* Here we calcalute the half period of the frequency in nanoseconds (i.e.,
|
|
* the amount of time that the clock should remain in the high or low state).
|
|
*
|
|
* frequency = psec / 1 sec psec = full period in seconds
|
|
* psec = 1 sec / frequency
|
|
* pnsec = 1000000000 nsec / (2 * frequency) pnsec = full period in nsec
|
|
*
|
|
* As examples:
|
|
* 1) frequency = 400KHz; SPI_PERBIT_NSEC = 100
|
|
* pnsec = (2500 - 100) / 2 = 1200
|
|
* 2) frequency = 20MHz; SPI_PERBIT_NSEC = 100
|
|
* pnsec = (50 - 100( / 2 -> 0
|
|
*/
|
|
|
|
pnsec = (1000000000ul + (frequency >> 1)) / frequency;
|
|
|
|
/* Minus the bit transfer overhead */
|
|
|
|
if (pnsec > SPI_PERBIT_NSEC)
|
|
{
|
|
pnsec -= SPI_PERBIT_NSEC;
|
|
}
|
|
else
|
|
{
|
|
pnsec = 0;
|
|
}
|
|
|
|
/* The hold time in nanoseconds is then half this */
|
|
|
|
pnsec = (pnsec + 1) >> 1;
|
|
|
|
/* But what we really want is the hold time in loop counts. We know that
|
|
* SPI_BITBAND_LOOPSPERMSEC is the number of times through a delay loop
|
|
* to get 1 millisecond.
|
|
*
|
|
* SPI_BITBAND_LOOPSPERMSEC / 1000000 is then the number of counts
|
|
* to get 1 nanosecond. In reality, this is a number less than zero. But
|
|
* then we can use this to calculate:
|
|
*
|
|
* holdtime loops/hold = pnsec nsec/hold * (SPI_BITBAND_LOOPSPERMSEC / 1000000) loops/nsec
|
|
*
|
|
* As examples:
|
|
* 1) frequency = 400KHz; SPI_PERBIT_NSEC = 100; pnsec = 1200;
|
|
* SPI_BITBAND_LOOPSPERMSEC = 5000
|
|
* holdtime = (1200 * 5000 + 500000) / 1000000 = 6
|
|
* 2) frequency = 20MHz; SPI_PERBIT_NSEC = 100; pnsec = 0;
|
|
* SPI_BITBAND_LOOPSPERMSEC = 5000
|
|
* holdtime = (0 * 5000 + 500000) / 1000000 = 0
|
|
*/
|
|
|
|
priv->holdtime = (pnsec * SPI_BITBAND_LOOPSPERMSEC + 500000) / 1000000;
|
|
|
|
/* Let's do our best to calculate the actual frequency
|
|
*
|
|
* As examples:
|
|
* 1) frequency = 400KHz; SPI_PERBIT_NSEC = 100;
|
|
* SPI_BITBAND_LOOPSPERMSEC = 5000; holdtime = 6
|
|
* pnsec = 2 * 1000000 * 6 / 5000 + 100 = 2500 nsec
|
|
* frequency = 400KHz
|
|
* 2) frequency = 20MHz; SPI_PERBIT_NSEC = 100; holdtime = 0
|
|
* SPI_BITBAND_LOOPSPERMSEC = 5000; holdtime = 0
|
|
* pnsec = 2 * 0 * 6 / 5000 + 100 = 100 nsec
|
|
* frequency = 10MHz
|
|
*/
|
|
|
|
pnsec = 2 * 1000000 * priv->holdtime / SPI_BITBAND_LOOPSPERMSEC + SPI_PERBIT_NSEC;
|
|
frequency = 1000000000ul / pnsec;
|
|
return frequency;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: spi_setmode
|
|
*
|
|
* Description:
|
|
* Select the current SPI mode
|
|
*
|
|
* Input Parameters:
|
|
* dev - Device-specific state data
|
|
* mode - the new SPI mode
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void spi_setmode(FAR struct spi_bitbang_s *priv,
|
|
enum spi_mode_e mode)
|
|
{
|
|
spiinfo("mode=%d\n", mode);
|
|
|
|
switch (mode)
|
|
{
|
|
case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
|
|
#ifndef SPI_BITBANG_DISABLEMODE0
|
|
SPI_CLRSCK; /* Resting level of the clock is low */
|
|
priv->exchange = spi_bitexchange0;
|
|
#else
|
|
DEBUGPANIC();
|
|
#endif
|
|
break;
|
|
|
|
case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
|
|
#ifndef SPI_BITBANG_DISABLEMODE1
|
|
SPI_CLRSCK; /* Resting level of the clock is low */
|
|
priv->exchange = spi_bitexchange1;
|
|
#else
|
|
DEBUGPANIC();
|
|
#endif
|
|
break;
|
|
|
|
case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
|
|
#ifndef SPI_BITBANG_DISABLEMODE2
|
|
SPI_SETSCK; /* Resting level of the clock is high */
|
|
priv->exchange = spi_bitexchange2;
|
|
#else
|
|
DEBUGPANIC();
|
|
#endif
|
|
break;
|
|
|
|
case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
|
|
#ifndef SPI_BITBANG_DISABLEMODE3
|
|
SPI_SETSCK; /* Resting level of the clock is high */
|
|
priv->exchange = spi_bitexchange3;
|
|
#else
|
|
DEBUGPANIC();
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
DEBUGPANIC();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: spi_bitexchange0
|
|
*
|
|
* Description:
|
|
* Exchange one bit in mode 0
|
|
*
|
|
* MODE 0: CPOL=0 and CPHA = 0
|
|
* The base value of the clock is zero. Data is captured on the clock's
|
|
* rising edge and data is propagated on the falling edge (high->low
|
|
* transition).
|
|
*
|
|
* /CS --+
|
|
* |
|
|
* +-----------------------------------------------------------------
|
|
* <-hold time-> <-hold time-><-hold time-><-hold time-><-hold time->
|
|
* +------------+ +------------+
|
|
* | | | |
|
|
* SCLK ---------------+ +------------+ +------------
|
|
* `- Set MOSI | `- Set MOSI | `- Set MOSI
|
|
* `- Sample MISO `- Sample MISO
|
|
*
|
|
* MISO /-------------X-----------\/------------X-------------\/-----------
|
|
* MOSO \-------------X-----------/\------------X-------------/\-----------
|
|
*
|
|
* Input Parameters:
|
|
* dev - Device-specific state data
|
|
* lock - true: Lock spi bus, false: unlock SPI bus
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef SPI_BITBANG_DISABLEMODE0
|
|
static uint16_t spi_bitexchange0(uint16_t dataout, uint32_t holdtime)
|
|
{
|
|
uint16_t datain;
|
|
|
|
/* Here the clock is is in the resting set (low). Set MOSI output and wait
|
|
* for the hold time
|
|
*/
|
|
|
|
if (dataout != 0)
|
|
{
|
|
SPI_SETMOSI;
|
|
}
|
|
else
|
|
{
|
|
SPI_CLRMOSI;
|
|
}
|
|
|
|
spi_delay(holdtime);
|
|
|
|
/* Set the clock high and sample MISO */
|
|
|
|
SPI_SETSCK;
|
|
datain = (uint16_t)SPI_GETMISO;
|
|
|
|
/* Wait the required amount of hold time then put the clock back in the
|
|
* resting state.
|
|
*/
|
|
|
|
spi_delay(holdtime);
|
|
SPI_CLRSCK;
|
|
|
|
return datain;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: spi_bitexchange1
|
|
*
|
|
* Description:
|
|
* Exchange one bit in mode 1
|
|
*
|
|
* MODE 1: CPOL=0 and CPHA = 1
|
|
* The base value of the clock is zero. Data is captured on the clock's
|
|
* falling edge and data is propagated on the rising edge
|
|
*
|
|
* /CS --+
|
|
* |
|
|
* +-----------------------------------------------------------------
|
|
* <-hold time-> <-hold time-><-hold time-><-hold time-><-hold time->
|
|
* +------------+ +------------+
|
|
* | | | |
|
|
* SCLK -+ +------------+ +------------
|
|
* `- Set MOSI | `- Set MOSI |
|
|
* `- Sample MISO `- Sample MISO
|
|
*
|
|
* MISO /-----------X------------\/-----------X-------------\/------------
|
|
* MOSO \-----------X------------/\-----------X-------------/\------------
|
|
*
|
|
* Input Parameters:
|
|
* dev - Device-specific state data
|
|
* lock - true: Lock spi bus, false: unlock SPI bus
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef SPI_BITBANG_DISABLEMODE1
|
|
static uint16_t spi_bitexchange1(uint16_t dataout, uint32_t holdtime)
|
|
{
|
|
uint16_t datain;
|
|
|
|
/* The clock should be in the resting state (low). Set the clock to the
|
|
* high state and set MOSI.
|
|
*/
|
|
|
|
SPI_SETSCK;
|
|
if (dataout != 0)
|
|
{
|
|
SPI_SETMOSI;
|
|
}
|
|
else
|
|
{
|
|
SPI_CLRMOSI;
|
|
}
|
|
|
|
/* Wait for the required hold time then put the clock back into the
|
|
* resting (low) state.
|
|
*/
|
|
|
|
spi_delay(holdtime);
|
|
SPI_CLRSCK;
|
|
|
|
/* Sample MISO on the falling edge and wait for the hold time again */
|
|
|
|
datain = (uint16_t)SPI_GETMISO;
|
|
spi_delay(holdtime);
|
|
|
|
return datain;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: spi_bitexchange2
|
|
*
|
|
* Description:
|
|
* Exchange one bit in mode 2
|
|
*
|
|
* MODE 2: CPOL=1 and CPHA = 0
|
|
* The base value of the clock is one. Data is captured on the clock's
|
|
* falling edge and data is propagated on the rising edge.
|
|
*
|
|
* /CS --+
|
|
* |
|
|
* +-----------------------------------------------------------------
|
|
* <-hold time-> <-hold time-><-hold time-><-hold time-><-hold time->
|
|
* ---------------+ +------------+ +------------
|
|
* | | | |
|
|
* SCLK +------------+ +------------+
|
|
* `- Set MOSI | `- Set MOSI | `- Set MOSI
|
|
* `- Sample MISO `- Sample MISO
|
|
*
|
|
* MISO /-------------X------------\/-----------X-------------\/-----------
|
|
* MOSO \-------------X------------/\-----------X-------------/\-----------
|
|
*
|
|
* Input Parameters:
|
|
* dev - Device-specific state data
|
|
* lock - true: Lock spi bus, false: unlock SPI bus
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef SPI_BITBANG_DISABLEMODE2
|
|
static uint16_t spi_bitexchange2(uint16_t dataout, uint32_t holdtime)
|
|
{
|
|
uint16_t datain;
|
|
|
|
/* Here the clock is is in the resting set (high). Set MOSI output and wait
|
|
* for the hold time
|
|
*/
|
|
|
|
if (dataout != 0)
|
|
{
|
|
SPI_SETMOSI;
|
|
}
|
|
else
|
|
{
|
|
SPI_CLRMOSI;
|
|
}
|
|
|
|
spi_delay(holdtime);
|
|
|
|
/* Set the clock low and sample MISO */
|
|
|
|
SPI_CLRSCK;
|
|
datain = (uint16_t)SPI_GETMISO;
|
|
|
|
/* Wait the required amount of hold time then put the clock back in the
|
|
* resting state (high).
|
|
*/
|
|
|
|
spi_delay(holdtime);
|
|
SPI_SETSCK;
|
|
|
|
return datain;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: spi_bitexchange3
|
|
*
|
|
* Description:
|
|
* Exchange one bit in mode 3
|
|
*
|
|
* MODE 3: CPOL=1 and CPHA = 1
|
|
* The base value of the clock is one. Data is captured on the clock's
|
|
* rising edge and data is propagated on the falling edge.
|
|
*
|
|
* /CS --+
|
|
* |
|
|
* +-----------------------------------------------------------------
|
|
* <-hold time-> <-hold time-><-hold time-><-hold time-><-hold time->
|
|
* -+ +------------+ +------------
|
|
* | | | |
|
|
* SCLK +------------+ +------------+
|
|
* ` Set MOSI | `- Set MOSI |
|
|
* `- Sample MISO `- Sample MISO
|
|
*
|
|
* MISO /-----------X------------\/-----------X-------------\/------------
|
|
* MOSO \-----------X------------/\-----------X-------------/\------------
|
|
*
|
|
* Input Parameters:
|
|
* dev - Device-specific state data
|
|
* lock - true: Lock spi bus, false: unlock SPI bus
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef SPI_BITBANG_DISABLEMODE3
|
|
static uint16_t spi_bitexchange3(uint16_t dataout, uint32_t holdtime)
|
|
{
|
|
uint16_t datain;
|
|
|
|
/* The clock should be in the resting state (high). Set the clock to the
|
|
* low state and set MOSI.
|
|
*/
|
|
|
|
SPI_CLRSCK; /* Clock transition before setting MOSI */
|
|
if (dataout != 0)
|
|
{
|
|
SPI_SETMOSI; /* Set MOSI if the bit is set */
|
|
}
|
|
else
|
|
{
|
|
SPI_CLRMOSI; /* Clear MOSI if the bit is not set */
|
|
}
|
|
|
|
/* Wait for the required hold time then put the clock back into the
|
|
* resting (high) state.
|
|
*/
|
|
|
|
spi_delay(holdtime);
|
|
SPI_SETSCK;
|
|
|
|
/* Sample MISO on the rising edge and wait for the hold time again */
|
|
|
|
datain = (uint16_t)SPI_GETMISO;
|
|
spi_delay(holdtime);
|
|
|
|
return datain;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: spi_exchange
|
|
*
|
|
* Description:
|
|
* Exahange on word of data on SPI
|
|
*
|
|
* Input Parameters:
|
|
* priv - Device-specific state data
|
|
* data - The TX data to be exchanged with the slave
|
|
*
|
|
* Returned Value:
|
|
* The RX data received from the slave
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_SPI_BITBANG_VARWIDTH
|
|
static uint16_t spi_exchange(FAR struct spi_bitbang_s *priv, uint16_t dataout)
|
|
{
|
|
bitexchange_t exchange = priv->exchange;
|
|
uint32_t holdtime = priv->holdtime;
|
|
uint16_t datain;
|
|
uint16_t bit;
|
|
int shift;
|
|
|
|
/* Transfer each bit. This might be better done with straight-line
|
|
* logic because the loop overhead will limit our maximum transfer
|
|
* rate.
|
|
*/
|
|
|
|
shift = priv->nbits - 1
|
|
for (bit = 1 << shift; bit != 0; bit >>= 1)
|
|
{
|
|
/* Shift to make space for the next, less significant bit.
|
|
* Then exchange bits with the slave an OR in the new, returned
|
|
* bit.
|
|
*/
|
|
|
|
datain <<= 1;
|
|
datain |= exchange(dataout & bit, holdtime);
|
|
}
|
|
|
|
return datain;
|
|
}
|
|
|
|
#else
|
|
static uint16_t spi_exchange(FAR struct spi_bitbang_s *priv, uint16_t dataout)
|
|
{
|
|
bitexchange_t exchange = priv->exchange;
|
|
uint32_t holdtime = priv->holdtime;
|
|
uint8_t datain;
|
|
|
|
/* Transfer each bit. This is better done with straight-line logic
|
|
* when possible because the loop overhead will limit our maximum transfer
|
|
* rate.
|
|
*/
|
|
|
|
/* Exchange bit 7 with the slave */
|
|
|
|
datain = priv->exchange(dataout & (1 << 7), holdtime);
|
|
|
|
/* Exchange bit 6 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 6), holdtime);
|
|
|
|
/* Exchange bit 5 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 5), holdtime);
|
|
|
|
/* Exchange bit 4 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 4), holdtime);
|
|
|
|
/* Exchange bit 3 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 3), holdtime);
|
|
|
|
/* Exchange bit 2 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 2), holdtime);
|
|
|
|
/* Exchange bit 1 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 1), holdtime);
|
|
|
|
/* Exchange bit 0 with the slave */
|
|
|
|
datain <<= 1;
|
|
datain |= priv->exchange(dataout & (1 << 0), holdtime);
|
|
|
|
return datain;
|
|
}
|
|
#endif
|