source: trunk/softs/tsar_boot/src/spi.c @ 592

Last change on this file since 592 was 590, checked in by bouyer, 11 years ago

Use the SPI controller's DMA if the defs_platform.h defines
IOC_USE_DMA.

File size: 4.8 KB
RevLine 
[388]1/**
[292]2 * \file    spi.c
[388]3 * \date    31 August 2012
[292]4 * \author  Cesar Fuguet <cesar.fuguet-tortolero@lip6.fr>
5 */
6#include <spi.h>
[590]7#include <reset_ioc.h>
8#include <reset_utils.h>
[292]9
10/**
[398]11 * \param   x: input value
12 *
13 * \return  byte-swapped value
14 *
15 * \brief   byte-swap a 32bit word
16 */
17static unsigned int bswap32(unsigned int x)
18{
19  unsigned int y;
20  y =  (x & 0x000000ff) << 24;
21  y |= (x & 0x0000ff00) <<  8;
22  y |= (x & 0x00ff0000) >>  8;
23  y |= (x & 0xff000000) >> 24;
24  return y;
25}
26
27/**
[292]28 * \param   spi :   Initialized pointer to the SPI controller
29 *
30 * \brief   Wait until the SPI controller has finished a transfer
31 *
32 * Wait until the GO_BUSY bit of the SPI controller be deasserted
33 */
34static void _spi_wait_if_busy(struct spi_dev * spi)
35{
[388]36    register int delay;
[292]37
38    while(SPI_IS_BUSY(spi))
39    {
[388]40        for (delay = 0; delay < 100; delay++);
[292]41    }
42}
43
44/**
45 * \param   spi : Initialized pointer to the SPI controller
46 *
47 * \return  void
48 *
49 * \brief   Init transfer of the tx registers to the selected slaves
50 */
51static void _spi_init_transfer(struct spi_dev * spi)
52{
53    unsigned int spi_ctrl = ioread32(&spi->ctrl);
54
55    iowrite32(&spi->ctrl, spi_ctrl | SPI_CTRL_GO_BSY);
56}
57
58/**
59 * \param   spi_freq    : Desired frequency for the generated clock from the SPI
60 *                        controller
61 * \param   sys_freq    : System clock frequency
62 *
63 * \brief   Calculated the value for the divider register in order to obtain the SPI
64 *          desired clock frequency
65 */
66static unsigned int _spi_calc_divider_value  (
67    unsigned int spi_freq   ,
68    unsigned int sys_freq   )
69{
70    return ((sys_freq / (spi_freq * 2)) - 1);
71}
72
73void spi_put_tx(struct spi_dev * spi, unsigned char byte, int index)
74{
75    _spi_wait_if_busy(spi);
76    {
77        iowrite8(&spi->rx_tx[index % 4], byte);
78        _spi_init_transfer(spi);
79    }
80    _spi_wait_if_busy(spi);
81}
82
83volatile unsigned char spi_get_rx(struct spi_dev * spi, int index)
84{
85    return ioread8(&spi->rx_tx[index % 4]);
86}
87
[398]88void spi_get_data(struct spi_dev * spi, void *buf, unsigned int count)
89{
90    unsigned int *data = buf;
91    unsigned char *data8;
92    unsigned int spi_ctrl0, spi_ctrl;
93    int i;
94
95    _spi_wait_if_busy(spi);
[415]96
[398]97    spi_ctrl0 = ioread32(&spi->ctrl);
[590]98    if (count == 512 && ((int)buf & 0x3f) == 0) {
99        /* use DMA */
100        spi->dma_base = (int)buf;
101        spi->dma_baseh = 0;
102        spi->dma_count = count | SPI_DMA_COUNT_READ;
103        _spi_wait_if_busy(spi);
104        i = count / 4;
105    } else {
106        /* switch to 128 bits words */
107        spi_ctrl = (spi_ctrl0 & ~SPI_CTRL_CHAR_LEN_MASK) | 128;
108        iowrite32(&spi->ctrl, spi_ctrl);
[398]109
[590]110        /* read data */
111        for (i = 0; i + 3 < count / 4; i += 4) {
112            iowrite32(&spi->rx_tx[0], 0xffffffff);
113            iowrite32(&spi->rx_tx[1], 0xffffffff);
114            iowrite32(&spi->rx_tx[2], 0xffffffff);
115            iowrite32(&spi->rx_tx[3], 0xffffffff);
116            iowrite32(&spi->ctrl,  spi_ctrl | SPI_CTRL_GO_BSY);
[415]117
[590]118            _spi_wait_if_busy(spi);
[415]119       
[590]120            *data = bswap32(ioread32(&spi->rx_tx[3]));
121            data++;
122            *data = bswap32(ioread32(&spi->rx_tx[2]));
123            data++;
124            *data = bswap32(ioread32(&spi->rx_tx[1]));
125            data++;
126            *data = bswap32(ioread32(&spi->rx_tx[0]));
127            data++;
128        }
[398]129    }
[415]130
[398]131    /* switch back to original word size */
132    iowrite32(&spi->ctrl, spi_ctrl0);
[415]133
[398]134    /* read missing bits */
135    data8 = (void *)data;
136    i = i * 4;
[415]137    for (; i < count; i++)
138    {
139        iowrite32(&spi->rx_tx[0], 0xffffffff);
140        iowrite32(&spi->ctrl,  spi_ctrl0 | SPI_CTRL_GO_BSY);
141   
142        _spi_wait_if_busy(spi);
143   
144        *data8 = spi_get_rx(spi, 0);
145        data8++;
[398]146    }
147    return;
148}
149
[292]150void spi_ss_assert(struct spi_dev * spi, int index)
151{
152    unsigned int spi_ss = ioread32(&spi->ss);
153
154    iowrite32(&spi->ss, spi_ss | (1 << index));
155}
156
157void spi_ss_deassert(struct spi_dev * spi, int index)
158{
159    unsigned int spi_ss = ioread32(&spi->ss);
160
161    iowrite32(&spi->ss, spi_ss & ~(1 << index));
162}
163
164void spi_dev_config (
165    struct spi_dev * spi,
[415]166    int spi_freq        ,
[292]167    int sys_freq        ,
[415]168    int char_len        ,
169    int tx_edge         ,
170    int rx_edge         )
[292]171{
172    unsigned int spi_ctrl = ioread32(&spi->ctrl);
173
174    if      ( tx_edge == 0 ) spi_ctrl |=  SPI_CTRL_TXN_EN;
175    else if ( tx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_TXN_EN;
176    if      ( rx_edge == 0 ) spi_ctrl |=  SPI_CTRL_RXN_EN;
177    else if ( rx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_RXN_EN;
178    if      ( char_len > 0 ) spi_ctrl  = (spi_ctrl & ~SPI_CTRL_CHAR_LEN_MASK) |
179                                         (char_len &  SPI_CTRL_CHAR_LEN_MASK);
180
181    iowrite32(&spi->ctrl, spi_ctrl);
182
183    if (spi_freq > 0 && sys_freq > 0)
184        iowrite32(&spi->divider, _spi_calc_divider_value(spi_freq, sys_freq));
185}
186
187/*
188 * vim: tabstop=4 : shiftwidth=4 : expandtab : softtabstop=4
189 */
Note: See TracBrowser for help on using the repository browser.