|
@@ -73,6 +73,7 @@ static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit,
|
73
|
73
|
* @v data_out TX data buffer (or NULL)
|
74
|
74
|
* @v data_in RX data buffer (or NULL)
|
75
|
75
|
* @v len Length of transfer (in @b bits)
|
|
76
|
+ * @v endianness Endianness of this data transfer
|
76
|
77
|
*
|
77
|
78
|
* This issues @c len clock cycles on the SPI bus, shifting out data
|
78
|
79
|
* from the @c data_out buffer to the MOSI line and shifting in data
|
|
@@ -82,31 +83,34 @@ static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit,
|
82
|
83
|
*/
|
83
|
84
|
static void spi_bit_transfer ( struct spi_bit_basher *spibit,
|
84
|
85
|
const void *data_out, void *data_in,
|
85
|
|
- unsigned int len ) {
|
|
86
|
+ unsigned int len, int endianness ) {
|
86
|
87
|
struct spi_bus *bus = &spibit->bus;
|
87
|
88
|
struct bit_basher *basher = &spibit->basher;
|
88
|
89
|
unsigned int sclk = ( ( bus->mode & SPI_MODE_CPOL ) ? 1 : 0 );
|
89
|
90
|
unsigned int cpha = ( ( bus->mode & SPI_MODE_CPHA ) ? 1 : 0 );
|
90
|
|
- unsigned int offset;
|
91
|
|
- unsigned int mask;
|
|
91
|
+ unsigned int bit_offset;
|
|
92
|
+ unsigned int byte_offset;
|
|
93
|
+ unsigned int byte_mask;
|
92
|
94
|
unsigned int bit;
|
93
|
|
- int step;
|
|
95
|
+ unsigned int step;
|
94
|
96
|
|
95
|
97
|
DBG ( "Transferring %d bits in mode %x\n", len, bus->mode );
|
96
|
98
|
|
97
|
|
- for ( step = ( ( len * 2 ) - 1 ) ; step >= 0 ; step-- ) {
|
98
|
|
- /* Calculate byte offset within data and bit mask */
|
99
|
|
- offset = ( step / 16 );
|
100
|
|
- mask = ( 1 << ( ( step % 16 ) / 2 ) );
|
101
|
|
-
|
|
99
|
+ for ( step = 0 ; step < ( len * 2 ) ; step++ ) {
|
|
100
|
+ /* Calculate byte offset and byte mask */
|
|
101
|
+ bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ?
|
|
102
|
+ ( len - ( step / 2 ) - 1 ) : ( step / 2 ) );
|
|
103
|
+ byte_offset = ( bit_offset / 8 );
|
|
104
|
+ byte_mask = ( 1 << ( bit_offset % 8 ) );
|
|
105
|
+
|
102
|
106
|
/* Shift data in or out */
|
103
|
107
|
if ( sclk == cpha ) {
|
104
|
108
|
const uint8_t *byte;
|
105
|
109
|
|
106
|
110
|
/* Shift data out */
|
107
|
111
|
if ( data_out ) {
|
108
|
|
- byte = ( data_out + offset );
|
109
|
|
- bit = ( *byte & mask );
|
|
112
|
+ byte = ( data_out + byte_offset );
|
|
113
|
+ bit = ( *byte & byte_mask );
|
110
|
114
|
} else {
|
111
|
115
|
bit = 0;
|
112
|
116
|
}
|
|
@@ -117,9 +121,9 @@ static void spi_bit_transfer ( struct spi_bit_basher *spibit,
|
117
|
121
|
/* Shift data in */
|
118
|
122
|
bit = read_bit ( basher, SPI_BIT_MISO );
|
119
|
123
|
if ( data_in ) {
|
120
|
|
- byte = ( data_in + offset );
|
121
|
|
- *byte &= ~mask;
|
122
|
|
- *byte |= ( bit & mask );
|
|
124
|
+ byte = ( data_in + byte_offset );
|
|
125
|
+ *byte &= ~byte_mask;
|
|
126
|
+ *byte |= ( bit & byte_mask );
|
123
|
127
|
}
|
124
|
128
|
}
|
125
|
129
|
|
|
@@ -155,17 +159,20 @@ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
|
155
|
159
|
/* Transmit command */
|
156
|
160
|
assert ( device->command_len <= ( 8 * sizeof ( tmp ) ) );
|
157
|
161
|
tmp = cpu_to_le32 ( command );
|
158
|
|
- spi_bit_transfer ( spibit, &tmp, NULL, device->command_len );
|
|
162
|
+ spi_bit_transfer ( spibit, &tmp, NULL, device->command_len,
|
|
163
|
+ SPI_BIT_BIG_ENDIAN );
|
159
|
164
|
|
160
|
165
|
/* Transmit address, if present */
|
161
|
166
|
if ( address >= 0 ) {
|
162
|
167
|
assert ( device->address_len <= ( 8 * sizeof ( tmp ) ) );
|
163
|
168
|
tmp = cpu_to_le32 ( address );
|
164
|
|
- spi_bit_transfer ( spibit, &tmp, NULL, device->address_len );
|
|
169
|
+ spi_bit_transfer ( spibit, &tmp, NULL, device->address_len,
|
|
170
|
+ SPI_BIT_BIG_ENDIAN );
|
165
|
171
|
}
|
166
|
172
|
|
167
|
173
|
/* Transmit/receive data */
|
168
|
|
- spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ) );
|
|
174
|
+ spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ),
|
|
175
|
+ spibit->endianness );
|
169
|
176
|
|
170
|
177
|
/* Deassert chip select on specified slave */
|
171
|
178
|
spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
|