uboot/common/soft_spi.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002
   3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
   4 *
   5 * Influenced by code from:
   6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   7 *
   8 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27#include <common.h>
  28#include <spi.h>
  29
  30#if defined(CONFIG_SOFT_SPI)
  31
  32#include <malloc.h>
  33
  34/*-----------------------------------------------------------------------
  35 * Definitions
  36 */
  37
  38#ifdef DEBUG_SPI
  39#define PRINTD(fmt,args...)     printf (fmt ,##args)
  40#else
  41#define PRINTD(fmt,args...)
  42#endif
  43
  44struct soft_spi_slave {
  45        struct spi_slave slave;
  46        unsigned int mode;
  47};
  48
  49static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
  50{
  51        return container_of(slave, struct soft_spi_slave, slave);
  52}
  53
  54/*=====================================================================*/
  55/*                         Public Functions                            */
  56/*=====================================================================*/
  57
  58/*-----------------------------------------------------------------------
  59 * Initialization
  60 */
  61void spi_init (void)
  62{
  63#ifdef  SPI_INIT
  64        volatile immap_t *immr = (immap_t *)CFG_IMMR;
  65
  66        SPI_INIT;
  67#endif
  68}
  69
  70struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  71                unsigned int max_hz, unsigned int mode)
  72{
  73        struct soft_spi_slave *ss;
  74
  75        if (!spi_cs_is_valid(bus, cs))
  76                return NULL;
  77
  78        ss = malloc(sizeof(struct soft_spi_slave));
  79        if (!ss)
  80                return NULL;
  81
  82        ss->slave.bus = bus;
  83        ss->slave.cs = cs;
  84        ss->mode = mode;
  85
  86        /* TODO: Use max_hz to limit the SCK rate */
  87
  88        return &ss->slave;
  89}
  90
  91void spi_free_slave(struct spi_slave *slave)
  92{
  93        struct soft_spi_slave *ss = to_soft_spi(slave);
  94
  95        free(ss);
  96}
  97
  98int spi_claim_bus(struct spi_slave *slave)
  99{
 100#ifdef CFG_IMMR
 101        volatile immap_t *immr = (immap_t *)CFG_IMMR;
 102#endif
 103        struct soft_spi_slave *ss = to_soft_spi(slave);
 104
 105        /*
 106         * Make sure the SPI clock is in idle state as defined for
 107         * this slave.
 108         */
 109        if (ss->mode & SPI_CPOL)
 110                SPI_SCL(1);
 111        else
 112                SPI_SCL(0);
 113
 114        return 0;
 115}
 116
 117void spi_release_bus(struct spi_slave *slave)
 118{
 119        /* Nothing to do */
 120}
 121
 122/*-----------------------------------------------------------------------
 123 * SPI transfer
 124 *
 125 * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
 126 * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
 127 *
 128 * The source of the outgoing bits is the "dout" parameter and the
 129 * destination of the input bits is the "din" parameter.  Note that "dout"
 130 * and "din" can point to the same memory location, in which case the
 131 * input data overwrites the output data (since both are buffered by
 132 * temporary variables, this is OK).
 133 */
 134int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 135                const void *dout, void *din, unsigned long flags)
 136{
 137#ifdef CFG_IMMR
 138        volatile immap_t *immr = (immap_t *)CFG_IMMR;
 139#endif
 140        struct soft_spi_slave *ss = to_soft_spi(slave);
 141        uchar           tmpdin  = 0;
 142        uchar           tmpdout = 0;
 143        const u8        *txd = dout;
 144        u8              *rxd = din;
 145        int             cpol = ss->mode & SPI_CPOL;
 146        int             cpha = ss->mode & SPI_CPHA;
 147        unsigned int    j;
 148
 149        PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
 150                slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen);
 151
 152        if (flags & SPI_XFER_BEGIN)
 153                spi_cs_activate(slave);
 154
 155        for(j = 0; j < bitlen; j++) {
 156                /*
 157                 * Check if it is time to work on a new byte.
 158                 */
 159                if((j % 8) == 0) {
 160                        tmpdout = *txd++;
 161                        if(j != 0) {
 162                                *rxd++ = tmpdin;
 163                        }
 164                        tmpdin  = 0;
 165                }
 166
 167                if (!cpha)
 168                        SPI_SCL(!cpol);
 169                SPI_SDA(tmpdout & 0x80);
 170                SPI_DELAY;
 171                if (cpha)
 172                        SPI_SCL(!cpol);
 173                else
 174                        SPI_SCL(cpol);
 175                tmpdin  <<= 1;
 176                tmpdin  |= SPI_READ;
 177                tmpdout <<= 1;
 178                SPI_DELAY;
 179                if (cpha)
 180                        SPI_SCL(cpol);
 181        }
 182        /*
 183         * If the number of bits isn't a multiple of 8, shift the last
 184         * bits over to left-justify them.  Then store the last byte
 185         * read in.
 186         */
 187        if((bitlen % 8) != 0)
 188                tmpdin <<= 8 - (bitlen % 8);
 189        *rxd++ = tmpdin;
 190
 191        if (flags & SPI_XFER_END)
 192                spi_cs_deactivate(slave);
 193
 194        return(0);
 195}
 196
 197#endif  /* CONFIG_SOFT_SPI */
 198