Annotation of qemu/roms/ipxe/src/drivers/bitbash/spi_bit.c, revision 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.