uboot/drivers/spi/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#include <malloc.h>
  31
  32/*-----------------------------------------------------------------------
  33 * Definitions
  34 */
  35
  36#ifdef DEBUG_SPI
  37#define PRINTD(fmt,args...)     printf (fmt ,##args)
  38#else
  39#define PRINTD(fmt,args...)
  40#endif
  41
  42struct soft_spi_slave {
  43        struct spi_slave slave;
  44        unsigned int mode;
  45};
  46
  47static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
  48{
  49        return container_of(slave, struct soft_spi_slave, slave);
  50}
  51
  52/*=====================================================================*/
  53/*                         Public Functions                            */
  54/*=====================================================================*/
  55
  56/*-----------------------------------------------------------------------
  57 * Initialization
  58 */
  59void spi_init (void)
  60{
  61#ifdef  SPI_INIT
  62        volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
  63
  64        SPI_INIT;
  65#endif
  66}
  67
  68struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  69                unsigned int max_hz, unsigned int mode)
  70{
  71        struct soft_spi_slave *ss;
  72
  73        if (!spi_cs_is_valid(bus, cs))
  74                return NULL;
  75
  76        ss = malloc(sizeof(struct soft_spi_slave));
  77        if (!ss)
  78                return NULL;
  79
  80        ss->slave.bus = bus;
  81        ss->slave.cs = cs;
  82        ss->mode = mode;
  83
  84        /* TODO: Use max_hz to limit the SCK rate */
  85
  86        return &ss->slave;
  87}
  88
  89void spi_free_slave(struct spi_slave *slave)
  90{
  91        struct soft_spi_slave *ss = to_soft_spi(slave);
  92
  93        free(ss);
  94}
  95
  96int spi_claim_bus(struct spi_slave *slave)
  97{
  98#ifdef CONFIG_SYS_IMMR
  99        volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
 100#endif
 101        struct soft_spi_slave *ss = to_soft_spi(slave);
 102
 103        /*
 104         * Make sure the SPI clock is in idle state as defined for
 105         * this slave.
 106         */
 107        if (ss->mode & SPI_CPOL)
 108                SPI_SCL(1);
 109        else
 110                SPI_SCL(0);
 111
 112        return 0;
 113}
 114
 115void spi_release_bus(struct spi_slave *slave)
 116{
 117        /* Nothing to do */
 118}
 119
 120/*-----------------------------------------------------------------------
 121 * SPI transfer
 122 *
 123 * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
 124 * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
 125 *
 126 * The source of the outgoing bits is the "dout" parameter and the
 127 * destination of the input bits is the "din" parameter.  Note that "dout"
 128 * and "din" can point to the same memory location, in which case the
 129 * input data overwrites the output data (since both are buffered by
 130 * temporary variables, this is OK).
 131 */
 132int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 133                const void *dout, void *din, unsigned long flags)
 134{
 135#ifdef CONFIG_SYS_IMMR
 136        volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
 137#endif
 138        struct soft_spi_slave *ss = to_soft_spi(slave);
 139        uchar           tmpdin  = 0;
 140        uchar           tmpdout = 0;
 141        const u8        *txd = dout;
 142        u8              *rxd = din;
 143        int             cpol = ss->mode & SPI_CPOL;
 144        int             cpha = ss->mode & SPI_CPHA;
 145        unsigned int    j;
 146
 147        PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
 148                slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen);
 149
 150        if (flags & SPI_XFER_BEGIN)
 151                spi_cs_activate(slave);
 152
 153        for(j = 0; j < bitlen; j++) {
 154                /*
 155                 * Check if it is time to work on a new byte.
 156                 */
 157                if((j % 8) == 0) {
 158                        tmpdout = *txd++;
 159                        if(j != 0) {
 160                                *rxd++ = tmpdin;
 161                        }
 162                        tmpdin  = 0;
 163                }
 164
 165                if (!cpha)
 166                        SPI_SCL(!cpol);
 167                SPI_SDA(tmpdout & 0x80);
 168                SPI_DELAY;
 169                if (cpha)
 170                        SPI_SCL(!cpol);
 171                else
 172                        SPI_SCL(cpol);
 173                tmpdin  <<= 1;
 174                tmpdin  |= SPI_READ;
 175                tmpdout <<= 1;
 176                SPI_DELAY;
 177                if (cpha)
 178                        SPI_SCL(cpol);
 179        }
 180        /*
 181         * If the number of bits isn't a multiple of 8, shift the last
 182         * bits over to left-justify them.  Then store the last byte
 183         * read in.
 184         */
 185        if((bitlen % 8) != 0)
 186                tmpdin <<= 8 - (bitlen % 8);
 187        *rxd++ = tmpdin;
 188
 189        if (flags & SPI_XFER_END)
 190                spi_cs_deactivate(slave);
 191
 192        return(0);
 193}
 194