uboot/drivers/spi/soft_spi_legacy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2002
   4 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
   5 *
   6 * Influenced by code from:
   7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   8 */
   9
  10#include <common.h>
  11#include <spi.h>
  12
  13#include <malloc.h>
  14
  15/*-----------------------------------------------------------------------
  16 * Definitions
  17 */
  18
  19#ifdef DEBUG_SPI
  20#define PRINTD(fmt,args...)     printf (fmt ,##args)
  21#else
  22#define PRINTD(fmt,args...)
  23#endif
  24
  25struct soft_spi_slave {
  26        struct spi_slave slave;
  27        unsigned int mode;
  28};
  29
  30static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
  31{
  32        return container_of(slave, struct soft_spi_slave, slave);
  33}
  34
  35/*=====================================================================*/
  36/*                         Public Functions                            */
  37/*=====================================================================*/
  38
  39struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  40                unsigned int max_hz, unsigned int mode)
  41{
  42        struct soft_spi_slave *ss;
  43
  44        if (!spi_cs_is_valid(bus, cs))
  45                return NULL;
  46
  47        ss = spi_alloc_slave(struct soft_spi_slave, bus, cs);
  48        if (!ss)
  49                return NULL;
  50
  51        ss->mode = mode;
  52
  53        /* TODO: Use max_hz to limit the SCK rate */
  54
  55        return &ss->slave;
  56}
  57
  58void spi_free_slave(struct spi_slave *slave)
  59{
  60        struct soft_spi_slave *ss = to_soft_spi(slave);
  61
  62        free(ss);
  63}
  64
  65int spi_claim_bus(struct spi_slave *slave)
  66{
  67#ifdef CONFIG_SYS_IMMR
  68        volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
  69#endif
  70        struct soft_spi_slave *ss = to_soft_spi(slave);
  71
  72        /*
  73         * Make sure the SPI clock is in idle state as defined for
  74         * this slave.
  75         */
  76        if (ss->mode & SPI_CPOL)
  77                SPI_SCL(1);
  78        else
  79                SPI_SCL(0);
  80
  81        return 0;
  82}
  83
  84void spi_release_bus(struct spi_slave *slave)
  85{
  86        /* Nothing to do */
  87}
  88
  89/*-----------------------------------------------------------------------
  90 * SPI transfer
  91 *
  92 * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
  93 * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
  94 *
  95 * The source of the outgoing bits is the "dout" parameter and the
  96 * destination of the input bits is the "din" parameter.  Note that "dout"
  97 * and "din" can point to the same memory location, in which case the
  98 * input data overwrites the output data (since both are buffered by
  99 * temporary variables, this is OK).
 100 */
 101int  spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 102                const void *dout, void *din, unsigned long flags)
 103{
 104#ifdef CONFIG_SYS_IMMR
 105        volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
 106#endif
 107        struct soft_spi_slave *ss = to_soft_spi(slave);
 108        uchar           tmpdin  = 0;
 109        uchar           tmpdout = 0;
 110        const u8        *txd = dout;
 111        u8              *rxd = din;
 112        int             cpol = ss->mode & SPI_CPOL;
 113        int             cpha = ss->mode & SPI_CPHA;
 114        unsigned int    j;
 115
 116        PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
 117                slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen);
 118
 119        if (flags & SPI_XFER_BEGIN)
 120                spi_cs_activate(slave);
 121
 122        for(j = 0; j < bitlen; j++) {
 123                /*
 124                 * Check if it is time to work on a new byte.
 125                 */
 126                if ((j % 8) == 0) {
 127                        if (txd)
 128                                tmpdout = *txd++;
 129                        else
 130                                tmpdout = 0;
 131                        if(j != 0) {
 132                                if (rxd)
 133                                        *rxd++ = tmpdin;
 134                        }
 135                        tmpdin  = 0;
 136                }
 137
 138                if (!cpha)
 139                        SPI_SCL(!cpol);
 140                SPI_SDA(tmpdout & 0x80);
 141                SPI_DELAY;
 142                if (cpha)
 143                        SPI_SCL(!cpol);
 144                else
 145                        SPI_SCL(cpol);
 146                tmpdin  <<= 1;
 147                tmpdin  |= SPI_READ;
 148                tmpdout <<= 1;
 149                SPI_DELAY;
 150                if (cpha)
 151                        SPI_SCL(cpol);
 152        }
 153        /*
 154         * If the number of bits isn't a multiple of 8, shift the last
 155         * bits over to left-justify them.  Then store the last byte
 156         * read in.
 157         */
 158        if (rxd) {
 159                if ((bitlen % 8) != 0)
 160                        tmpdin <<= 8 - (bitlen % 8);
 161                *rxd++ = tmpdin;
 162        }
 163
 164        if (flags & SPI_XFER_END)
 165                spi_cs_deactivate(slave);
 166
 167        return(0);
 168}
 169