Annotation of qemu/roms/ipxe/src/drivers/bitbash/spi_bit.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
                      3:  *
                      4:  * This program is free software; you can redistribute it and/or
                      5:  * modify it under the terms of the GNU General Public License as
                      6:  * published by the Free Software Foundation; either version 2 of the
                      7:  * License, or any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     12:  * General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: FILE_LICENCE ( GPL2_OR_LATER );
                     20: 
                     21: #include <stddef.h>
                     22: #include <stdint.h>
                     23: #include <string.h>
                     24: #include <byteswap.h>
                     25: #include <errno.h>
                     26: #include <assert.h>
                     27: #include <unistd.h>
                     28: #include <ipxe/bitbash.h>
                     29: #include <ipxe/spi_bit.h>
                     30: 
                     31: /** @file
                     32:  *
                     33:  * SPI bit-bashing interface
                     34:  *
                     35:  */
                     36: 
                     37: /** Delay between SCLK changes and around SS changes */
                     38: static void spi_bit_delay ( void ) {
                     39:        udelay ( SPI_BIT_UDELAY );
                     40: }
                     41: 
                     42: /** Chip select line will be asserted */
                     43: #define SELECT_SLAVE 0
                     44: 
                     45: /** Chip select line will be deasserted */
                     46: #define DESELECT_SLAVE SPI_MODE_SSPOL
                     47: 
                     48: /**
                     49:  * Select/deselect slave
                     50:  *
                     51:  * @v spibit           SPI bit-bashing interface
                     52:  * @v slave            Slave number
                     53:  * @v state            Slave select state
                     54:  *
                     55:  * @c state must be @c SELECT_SLAVE or @c DESELECT_SLAVE.
                     56:  */
                     57: static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit,
                     58:                                       unsigned int slave,
                     59:                                       unsigned int state ) {
                     60:        struct bit_basher *basher = &spibit->basher;
                     61: 
                     62:        state ^= ( spibit->bus.mode & SPI_MODE_SSPOL );
                     63:        DBGC2 ( spibit, "SPIBIT %p setting slave %d select %s\n",
                     64:                spibit, slave, ( state ? "high" : "low" ) );
                     65: 
                     66:        spi_bit_delay();
                     67:        write_bit ( basher, SPI_BIT_SS ( slave ), state );
                     68:        spi_bit_delay();
                     69: }
                     70: 
                     71: /**
                     72:  * Transfer bits over SPI bit-bashing bus
                     73:  *
                     74:  * @v bus              SPI bus
                     75:  * @v data_out         TX data buffer (or NULL)
                     76:  * @v data_in          RX data buffer (or NULL)
                     77:  * @v len              Length of transfer (in @b bits)
                     78:  * @v endianness       Endianness of this data transfer
                     79:  *
                     80:  * This issues @c len clock cycles on the SPI bus, shifting out data
                     81:  * from the @c data_out buffer to the MOSI line and shifting in data
                     82:  * from the MISO line to the @c data_in buffer.  If @c data_out is
                     83:  * NULL, then the data sent will be all zeroes.  If @c data_in is
                     84:  * NULL, then the incoming data will be discarded.
                     85:  */
                     86: static void spi_bit_transfer ( struct spi_bit_basher *spibit,
                     87:                               const void *data_out, void *data_in,
                     88:                               unsigned int len, int endianness ) {
                     89:        struct spi_bus *bus = &spibit->bus;
                     90:        struct bit_basher *basher = &spibit->basher;
                     91:        unsigned int sclk = ( ( bus->mode & SPI_MODE_CPOL ) ? 1 : 0 );
                     92:        unsigned int cpha = ( ( bus->mode & SPI_MODE_CPHA ) ? 1 : 0 );
                     93:        unsigned int bit_offset;
                     94:        unsigned int byte_offset;
                     95:        unsigned int byte_mask;
                     96:        unsigned int bit;
                     97:        unsigned int step;
                     98: 
                     99:        DBGC2 ( spibit, "SPIBIT %p transferring %d bits in mode %#x\n",
                    100:                spibit, len, bus->mode );
                    101: 
                    102:        for ( step = 0 ; step < ( len * 2 ) ; step++ ) {
                    103:                /* Calculate byte offset and byte mask */
                    104:                bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ?
                    105:                               ( len - ( step / 2 ) - 1 ) : ( step / 2 ) );
                    106:                byte_offset = ( bit_offset / 8 );
                    107:                byte_mask = ( 1 << ( bit_offset % 8 ) );
                    108: 
                    109:                /* Shift data in or out */
                    110:                if ( sclk == cpha ) {
                    111:                        const uint8_t *byte;
                    112: 
                    113:                        /* Shift data out */
                    114:                        if ( data_out ) {
                    115:                                byte = ( data_out + byte_offset );
                    116:                                bit = ( *byte & byte_mask );
                    117:                                DBGCP ( spibit, "SPIBIT %p wrote bit %d\n",
                    118:                                        spibit, ( bit ? 1 : 0 ) );
                    119:                        } else {
                    120:                                bit = 0;
                    121:                        }
                    122:                        write_bit ( basher, SPI_BIT_MOSI, bit );
                    123:                } else {
                    124:                        uint8_t *byte;
                    125: 
                    126:                        /* Shift data in */
                    127:                        bit = read_bit ( basher, SPI_BIT_MISO );
                    128:                        if ( data_in ) {
                    129:                                DBGCP ( spibit, "SPIBIT %p read bit %d\n",
                    130:                                        spibit, ( bit ? 1 : 0 ) );
                    131:                                byte = ( data_in + byte_offset );
                    132:                                *byte &= ~byte_mask;
                    133:                                *byte |= ( bit & byte_mask );
                    134:                        }
                    135:                }
                    136: 
                    137:                /* Toggle clock line */
                    138:                spi_bit_delay();
                    139:                sclk ^= 1;
                    140:                write_bit ( basher, SPI_BIT_SCLK, sclk );
                    141:        }
                    142: }
                    143: 
                    144: /**
                    145:  * Read/write data via SPI bit-bashing bus
                    146:  *
                    147:  * @v bus              SPI bus
                    148:  * @v device           SPI device
                    149:  * @v command          Command
                    150:  * @v address          Address to read/write (<0 for no address)
                    151:  * @v data_out         TX data buffer (or NULL)
                    152:  * @v data_in          RX data buffer (or NULL)
                    153:  * @v len              Length of transfer
                    154:  * @ret rc             Return status code
                    155:  */
                    156: static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
                    157:                        unsigned int command, int address,
                    158:                        const void *data_out, void *data_in, size_t len ) {
                    159:        struct spi_bit_basher *spibit
                    160:                = container_of ( bus, struct spi_bit_basher, bus );
                    161:        uint32_t tmp_command;
                    162:        uint32_t tmp_address;
                    163:        uint32_t tmp_address_detect;
                    164: 
                    165:        /* Deassert chip select to reset specified slave */
                    166:        spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
                    167: 
                    168:        /* Set clock line to idle state */
                    169:        write_bit ( &spibit->basher, SPI_BIT_SCLK, 
                    170:                    ( bus->mode & SPI_MODE_CPOL ) );
                    171: 
                    172:        /* Assert chip select on specified slave */
                    173:        spi_bit_set_slave_select ( spibit, device->slave, SELECT_SLAVE );
                    174: 
                    175:        /* Transmit command */
                    176:        assert ( device->command_len <= ( 8 * sizeof ( tmp_command ) ) );
                    177:        tmp_command = cpu_to_le32 ( command );
                    178:        spi_bit_transfer ( spibit, &tmp_command, NULL, device->command_len,
                    179:                           SPI_BIT_BIG_ENDIAN );
                    180: 
                    181:        /* Transmit address, if present */
                    182:        if ( address >= 0 ) {
                    183:                assert ( device->address_len <= ( 8 * sizeof ( tmp_address )));
                    184:                tmp_address = cpu_to_le32 ( address );
                    185:                if ( device->address_len == SPI_AUTODETECT_ADDRESS_LEN ) {
                    186:                        /* Autodetect address length.  This relies on
                    187:                         * the device responding with a dummy zero
                    188:                         * data bit before the first real data bit.
                    189:                         */
                    190:                        DBGC ( spibit, "SPIBIT %p autodetecting device "
                    191:                               "address length\n", spibit );
                    192:                        assert ( address == 0 );
                    193:                        device->address_len = 0;
                    194:                        do {
                    195:                                spi_bit_transfer ( spibit, &tmp_address,
                    196:                                                   &tmp_address_detect, 1,
                    197:                                                   SPI_BIT_BIG_ENDIAN );
                    198:                                device->address_len++;
                    199:                        } while ( le32_to_cpu ( tmp_address_detect ) & 1 );
                    200:                        DBGC ( spibit, "SPIBIT %p autodetected device address "
                    201:                               "length %d\n", spibit, device->address_len );
                    202:                } else {
                    203:                        spi_bit_transfer ( spibit, &tmp_address, NULL,
                    204:                                           device->address_len,
                    205:                                           SPI_BIT_BIG_ENDIAN );
                    206:                }
                    207:        }
                    208: 
                    209:        /* Transmit/receive data */
                    210:        spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ),
                    211:                           spibit->endianness );
                    212: 
                    213:        /* Deassert chip select on specified slave */
                    214:        spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
                    215: 
                    216:        return 0;
                    217: }
                    218: 
                    219: /**
                    220:  * Initialise SPI bit-bashing interface
                    221:  *
                    222:  * @v spibit           SPI bit-bashing interface
                    223:  */
                    224: void init_spi_bit_basher ( struct spi_bit_basher *spibit ) {
                    225:        assert ( &spibit->basher.op->read != NULL );
                    226:        assert ( &spibit->basher.op->write != NULL );
                    227:        spibit->bus.rw = spi_bit_rw;
                    228: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.