uboot/drivers/spi/kirkwood_spi.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2009
   3 * Marvell Semiconductor <www.marvell.com>
   4 * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
   5 *
   6 * Derived from drivers/spi/mpc8xxx_spi.c
   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., 51 Franklin Street, Fifth Floor, Boston,
  24 * MA 02110-1301 USA
  25 */
  26
  27#include <common.h>
  28#include <malloc.h>
  29#include <spi.h>
  30#include <asm/arch/kirkwood.h>
  31#include <asm/arch/spi.h>
  32#include <asm/arch/mpp.h>
  33
  34static struct kwspi_registers *spireg = (struct kwspi_registers *)KW_SPI_BASE;
  35
  36struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  37                                unsigned int max_hz, unsigned int mode)
  38{
  39        struct spi_slave *slave;
  40        u32 data;
  41        u32 kwspi_mpp_config[] = {
  42                MPP0_GPIO,
  43                MPP7_SPI_SCn,
  44                0
  45        };
  46
  47        if (!spi_cs_is_valid(bus, cs))
  48                return NULL;
  49
  50        slave = malloc(sizeof(struct spi_slave));
  51        if (!slave)
  52                return NULL;
  53
  54        slave->bus = bus;
  55        slave->cs = cs;
  56
  57        writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
  58
  59        /* calculate spi clock prescaller using max_hz */
  60        data = ((CONFIG_SYS_TCLK / 2) / max_hz) & KWSPI_CLKPRESCL_MASK;
  61        data |= 0x10;
  62
  63        /* program spi clock prescaller using max_hz */
  64        writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg);
  65        debug("data = 0x%08x \n", data);
  66
  67        writel(KWSPI_SMEMRDIRQ, &spireg->irq_cause);
  68        writel(KWSPI_IRQMASK, spireg->irq_mask);
  69
  70        /* program mpp registers to select  SPI_CSn */
  71        if (cs) {
  72                kwspi_mpp_config[0] = MPP0_GPIO;
  73                kwspi_mpp_config[1] = MPP7_SPI_SCn;
  74        } else {
  75                kwspi_mpp_config[0] = MPP0_SPI_SCn;
  76                kwspi_mpp_config[1] = MPP7_GPO;
  77        }
  78        kirkwood_mpp_conf(kwspi_mpp_config);
  79
  80        return slave;
  81}
  82
  83void spi_free_slave(struct spi_slave *slave)
  84{
  85        free(slave);
  86}
  87
  88int spi_claim_bus(struct spi_slave *slave)
  89{
  90        return 0;
  91}
  92
  93void spi_release_bus(struct spi_slave *slave)
  94{
  95}
  96
  97#ifndef CONFIG_SPI_CS_IS_VALID
  98/*
  99 * you can define this function board specific
 100 * define above CONFIG in board specific config file and
 101 * provide the function in board specific src file
 102 */
 103int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 104{
 105        return (bus == 0 && (cs == 0 || cs == 1));
 106}
 107#endif
 108
 109void spi_cs_activate(struct spi_slave *slave)
 110{
 111        writel(readl(&spireg->ctrl) | KWSPI_IRQUNMASK, &spireg->ctrl);
 112}
 113
 114void spi_cs_deactivate(struct spi_slave *slave)
 115{
 116        writel(readl(&spireg->ctrl) & KWSPI_IRQMASK, &spireg->ctrl);
 117}
 118
 119int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 120             void *din, unsigned long flags)
 121{
 122        unsigned int tmpdout, tmpdin;
 123        int tm, isread = 0;
 124
 125        debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
 126              slave->bus, slave->cs, dout, din, bitlen);
 127
 128        if (flags & SPI_XFER_BEGIN)
 129                spi_cs_activate(slave);
 130
 131        /*
 132         * handle data in 8-bit chunks
 133         * TBD: 2byte xfer mode to be enabled
 134         */
 135        writel(((readl(&spireg->cfg) & ~KWSPI_XFERLEN_MASK) |
 136                KWSPI_XFERLEN_1BYTE), &spireg->cfg);
 137
 138        while (bitlen > 4) {
 139                debug("loopstart bitlen %d\n", bitlen);
 140                tmpdout = 0;
 141
 142                /* Shift data so it's msb-justified */
 143                if (dout)
 144                        tmpdout = *(u32 *) dout & 0x0ff;
 145
 146                writel(~KWSPI_SMEMRDIRQ, &spireg->irq_cause);
 147                writel(tmpdout, &spireg->dout); /* Write the data out */
 148                debug("*** spi_xfer: ... %08x written, bitlen %d\n",
 149                      tmpdout, bitlen);
 150
 151                /*
 152                 * Wait for SPI transmit to get out
 153                 * or time out (1 second = 1000 ms)
 154                 * The NE event must be read and cleared first
 155                 */
 156                for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) {
 157                        if (readl(&spireg->irq_cause) & KWSPI_SMEMRDIRQ) {
 158                                isread = 1;
 159                                tmpdin = readl(&spireg->din);
 160                                debug
 161                                        ("spi_xfer: din %08x..%08x read\n",
 162                                        din, tmpdin);
 163
 164                                if (din) {
 165                                        *((u8 *) din) = (u8) tmpdin;
 166                                        din += 1;
 167                                }
 168                                if (dout)
 169                                        dout += 1;
 170                                bitlen -= 8;
 171                        }
 172                        if (isread)
 173                                break;
 174                }
 175                if (tm >= KWSPI_TIMEOUT)
 176                        printf("*** spi_xfer: Time out during SPI transfer\n");
 177
 178                debug("loopend bitlen %d\n", bitlen);
 179        }
 180
 181        if (flags & SPI_XFER_END)
 182                spi_cs_deactivate(slave);
 183
 184        return 0;
 185}
 186