/** * Read/write data via SPI bit-bashing bus * * @v bus SPI bus * @v device SPI device * @v command Command * @v address Address to read/write (<0 for no address) * @v data_out TX data buffer (or NULL) * @v data_in RX data buffer (or NULL) * @v len Length of transfer * @ret rc Return status code */ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device, unsigned int command, int address, const void *data_out, void *data_in, size_t len ) { struct spi_bit_basher *spibit = container_of ( bus, struct spi_bit_basher, bus ); uint32_t tmp; /* Set clock line to idle state */ write_bit ( &spibit->basher, SPI_BIT_SCLK, ( bus->mode & SPI_MODE_CPOL ) ); /* Assert chip select on specified slave */ spi_bit_set_slave_select ( spibit, device->slave, SELECT_SLAVE ); /* Transmit command */ assert ( device->command_len <= ( 8 * sizeof ( tmp ) ) ); tmp = cpu_to_le32 ( command ); spi_bit_transfer ( spibit, &tmp, NULL, device->command_len, SPI_BIT_BIG_ENDIAN ); /* Transmit address, if present */ if ( address >= 0 ) { assert ( device->address_len <= ( 8 * sizeof ( tmp ) ) ); tmp = cpu_to_le32 ( address ); spi_bit_transfer ( spibit, &tmp, NULL, device->address_len, SPI_BIT_BIG_ENDIAN ); } /* Transmit/receive data */ spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ), spibit->endianness ); /* Deassert chip select on specified slave */ spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE ); return 0; }
/** * Read/write data via SPI bit-bashing bus * * @v bus SPI bus * @v device SPI device * @v command Command * @v address Address to read/write (<0 for no address) * @v data_out TX data buffer (or NULL) * @v data_in RX data buffer (or NULL) * @v len Length of transfer * @ret rc Return status code */ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device, unsigned int command, int address, const void *data_out, void *data_in, size_t len ) { struct spi_bit_basher *spibit = container_of ( bus, struct spi_bit_basher, bus ); uint32_t tmp_command; uint32_t tmp_address; uint32_t tmp_address_detect; /* Open bit-bashing interface */ open_bit ( &spibit->basher ); /* Deassert chip select to reset specified slave */ spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE ); /* Set clock line to idle state */ write_bit ( &spibit->basher, SPI_BIT_SCLK, ( bus->mode & SPI_MODE_CPOL ) ); /* Assert chip select on specified slave */ spi_bit_set_slave_select ( spibit, device->slave, SELECT_SLAVE ); /* Transmit command */ assert ( device->command_len <= ( 8 * sizeof ( tmp_command ) ) ); tmp_command = cpu_to_le32 ( command ); spi_bit_transfer ( spibit, &tmp_command, NULL, device->command_len, SPI_BIT_BIG_ENDIAN ); /* Transmit address, if present */ if ( address >= 0 ) { assert ( device->address_len <= ( 8 * sizeof ( tmp_address ))); tmp_address = cpu_to_le32 ( address ); if ( device->address_len == SPI_AUTODETECT_ADDRESS_LEN ) { /* Autodetect address length. This relies on * the device responding with a dummy zero * data bit before the first real data bit. */ DBGC ( spibit, "SPIBIT %p autodetecting device " "address length\n", spibit ); assert ( address == 0 ); device->address_len = 0; do { spi_bit_transfer ( spibit, &tmp_address, &tmp_address_detect, 1, SPI_BIT_BIG_ENDIAN ); device->address_len++; } while ( le32_to_cpu ( tmp_address_detect ) & 1 ); DBGC ( spibit, "SPIBIT %p autodetected device address " "length %d\n", spibit, device->address_len ); } else { spi_bit_transfer ( spibit, &tmp_address, NULL, device->address_len, SPI_BIT_BIG_ENDIAN ); } } /* Transmit/receive data */ spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ), spibit->endianness ); /* Deassert chip select on specified slave */ spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE ); /* Close bit-bashing interface */ close_bit ( &spibit->basher ); return 0; }