uboot/drivers/spi/armada100_spi.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2011
   3 * eInfochips Ltd. <www.einfochips.com>
   4 * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
   5 *
   6 * (C) Copyright 2009
   7 * Marvell Semiconductor <www.marvell.com>
   8 * Based on SSP driver
   9 * Written-by: Lei Wen <leiwen@marvell.com>
  10 *
  11 * SPDX-License-Identifier:     GPL-2.0+
  12 */
  13
  14
  15#include <common.h>
  16#include <malloc.h>
  17#include <spi.h>
  18
  19#include <asm/io.h>
  20#include <asm/arch/spi.h>
  21#include <asm/gpio.h>
  22
  23#define to_armd_spi_slave(s)    container_of(s, struct armd_spi_slave, slave)
  24
  25struct armd_spi_slave {
  26        struct spi_slave slave;
  27        struct ssp_reg *spi_reg;
  28        u32 cr0, cr1;
  29        u32 int_cr1;
  30        u32 clear_sr;
  31        const void *tx;
  32        void *rx;
  33        int gpio_cs_inverted;
  34};
  35
  36static int spi_armd_write(struct armd_spi_slave *pss)
  37{
  38        int wait_timeout = SSP_FLUSH_NUM;
  39        while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_TNF))
  40                ;
  41        if (!wait_timeout) {
  42                debug("%s: timeout error\n", __func__);
  43                return -1;
  44        }
  45
  46        if (pss->tx != NULL) {
  47                writel(*(u8 *)pss->tx, &pss->spi_reg->ssdr);
  48                ++pss->tx;
  49        } else {
  50                writel(0, &pss->spi_reg->ssdr);
  51        }
  52        return 0;
  53}
  54
  55static int spi_armd_read(struct armd_spi_slave *pss)
  56{
  57        int wait_timeout = SSP_FLUSH_NUM;
  58        while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_RNE))
  59                ;
  60        if (!wait_timeout) {
  61                debug("%s: timeout error\n", __func__);
  62                return -1;
  63        }
  64
  65        if (pss->rx != NULL) {
  66                *(u8 *)pss->rx = readl(&pss->spi_reg->ssdr);
  67                ++pss->rx;
  68        } else {
  69                readl(&pss->spi_reg->ssdr);
  70        }
  71        return 0;
  72}
  73
  74static int spi_armd_flush(struct armd_spi_slave *pss)
  75{
  76        unsigned long limit = SSP_FLUSH_NUM;
  77
  78        do {
  79                while (readl(&pss->spi_reg->sssr) & SSSR_RNE)
  80                        readl(&pss->spi_reg->ssdr);
  81        } while ((readl(&pss->spi_reg->sssr) & SSSR_BSY) && limit--);
  82
  83        writel(SSSR_ROR, &pss->spi_reg->sssr);
  84
  85        return limit;
  86}
  87
  88void spi_cs_activate(struct spi_slave *slave)
  89{
  90        struct armd_spi_slave *pss = to_armd_spi_slave(slave);
  91
  92        gpio_set_value(slave->cs, pss->gpio_cs_inverted);
  93}
  94
  95void spi_cs_deactivate(struct spi_slave *slave)
  96{
  97        struct armd_spi_slave *pss = to_armd_spi_slave(slave);
  98
  99        gpio_set_value(slave->cs, !pss->gpio_cs_inverted);
 100}
 101
 102struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 103                unsigned int max_hz, unsigned int mode)
 104{
 105        struct armd_spi_slave *pss;
 106
 107        pss = spi_alloc_slave(struct armd_spi_slave, bus, cs);
 108        if (!pss)
 109                return NULL;
 110
 111        pss->spi_reg = (struct ssp_reg *)SSP_REG_BASE(CONFIG_SYS_SSP_PORT);
 112
 113        pss->cr0 = SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN) | SSCR0_SSE;
 114
 115        pss->cr1 = (SSCR1_RXTRESH(RX_THRESH_DEF) & SSCR1_RFT) |
 116                (SSCR1_TXTRESH(TX_THRESH_DEF) & SSCR1_TFT);
 117        pss->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
 118        pss->cr1 |= (((mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
 119                | (((mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
 120
 121        pss->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
 122        pss->clear_sr = SSSR_ROR | SSSR_TINT;
 123
 124        pss->gpio_cs_inverted = mode & SPI_CS_HIGH;
 125        gpio_set_value(cs, !pss->gpio_cs_inverted);
 126
 127        return &pss->slave;
 128}
 129
 130void spi_free_slave(struct spi_slave *slave)
 131{
 132        struct armd_spi_slave *pss = to_armd_spi_slave(slave);
 133
 134        free(pss);
 135}
 136
 137int spi_claim_bus(struct spi_slave *slave)
 138{
 139        struct armd_spi_slave *pss = to_armd_spi_slave(slave);
 140
 141        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 142        if (spi_armd_flush(pss) == 0)
 143                return -1;
 144
 145        return 0;
 146}
 147
 148void spi_release_bus(struct spi_slave *slave)
 149{
 150}
 151
 152int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 153                void *din, unsigned long flags)
 154{
 155        struct armd_spi_slave *pss = to_armd_spi_slave(slave);
 156        uint bytes = bitlen / 8;
 157        unsigned long limit;
 158        int ret = 0;
 159
 160        if (bitlen == 0)
 161                goto done;
 162
 163        /* we can only do 8 bit transfers */
 164        if (bitlen % 8) {
 165                flags |= SPI_XFER_END;
 166                goto done;
 167        }
 168
 169        pss->tx = dout;
 170        pss->rx = din;
 171
 172        if (flags & SPI_XFER_BEGIN) {
 173                spi_cs_activate(slave);
 174                writel(pss->cr1 | pss->int_cr1, &pss->spi_reg->sscr1);
 175                writel(TIMEOUT_DEF, &pss->spi_reg->ssto);
 176                writel(pss->cr0, &pss->spi_reg->sscr0);
 177        }
 178
 179        while (bytes--) {
 180                limit = SSP_FLUSH_NUM;
 181                ret = spi_armd_write(pss);
 182                if (ret)
 183                        break;
 184
 185                while ((readl(&pss->spi_reg->sssr) & SSSR_BSY) && limit--)
 186                        udelay(1);
 187
 188                ret = spi_armd_read(pss);
 189                if (ret)
 190                        break;
 191        }
 192
 193 done:
 194        if (flags & SPI_XFER_END) {
 195                /* Stop SSP */
 196                writel(pss->clear_sr, &pss->spi_reg->sssr);
 197                clrbits_le32(&pss->spi_reg->sscr1, pss->int_cr1);
 198                writel(0, &pss->spi_reg->ssto);
 199                spi_cs_deactivate(slave);
 200        }
 201
 202        return ret;
 203}
 204