source: trunk/softs/tsar_boot/drivers/spi.c @ 997

Last change on this file since 997 was 758, checked in by cfuguet, 10 years ago

tsar_boot: improving configuration infrastructure

  • Using hard_config.h which respects the same sintax that the hard_config.h file of all TSAR platforms. This file can be then generated by the GIET-VM genmap tool or written manually.
  • All peripheral drivers have been moved to a drivers directory and they are compiled as a static library. This allows GCC to only include in the final .ELF the object files of used peripherals and not all of them.
  • Example hard_config.h and ldscripts have been introduced in the conf directory.
  • Improving comments in all files
File size: 4.8 KB
Line 
1/**
2 * \file    spi.c
3 * \date    31 August 2012
4 * \author  Cesar Fuguet <cesar.fuguet-tortolero@lip6.fr>
5 */
6#include <spi.h>
7#include <reset_ioc.h>
8#include <reset_utils.h>
9
10/**
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/**
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{
36    register int delay;
37
38    while(SPI_IS_BUSY(spi))
39    {
40        for (delay = 0; delay < 100; delay++);
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
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);
96
97    spi_ctrl0 = ioread32(&spi->ctrl);
98#ifdef IOC_USE_DMA
99    if (count == 512 && ((int)buf & 0x3f) == 0) {
100        /* use DMA */
101        spi->dma_base = (int)buf;
102        spi->dma_baseh = 0;
103        spi->dma_count = count | SPI_DMA_COUNT_READ;
104        _spi_wait_if_busy(spi);
105        i = count / 4;
106    } else
107#endif /* IOC_USE_DMA */
108    {
109        /* switch to 128 bits words */
110        spi_ctrl = (spi_ctrl0 & ~SPI_CTRL_CHAR_LEN_MASK) | 128;
111        iowrite32(&spi->ctrl, spi_ctrl);
112
113        /* read data */
114        for (i = 0; i + 3 < count / 4; i += 4) {
115            iowrite32(&spi->rx_tx[0], 0xffffffff);
116            iowrite32(&spi->rx_tx[1], 0xffffffff);
117            iowrite32(&spi->rx_tx[2], 0xffffffff);
118            iowrite32(&spi->rx_tx[3], 0xffffffff);
119            iowrite32(&spi->ctrl,  spi_ctrl | SPI_CTRL_GO_BSY);
120
121            _spi_wait_if_busy(spi);
122       
123            *data = bswap32(ioread32(&spi->rx_tx[3]));
124            data++;
125            *data = bswap32(ioread32(&spi->rx_tx[2]));
126            data++;
127            *data = bswap32(ioread32(&spi->rx_tx[1]));
128            data++;
129            *data = bswap32(ioread32(&spi->rx_tx[0]));
130            data++;
131        }
132    }
133
134    /* switch back to original word size */
135    iowrite32(&spi->ctrl, spi_ctrl0);
136
137    /* read missing bits */
138    data8 = (void *)data;
139    i = i * 4;
140    for (; i < count; i++)
141    {
142        iowrite32(&spi->rx_tx[0], 0xffffffff);
143        iowrite32(&spi->ctrl,  spi_ctrl0 | SPI_CTRL_GO_BSY);
144   
145        _spi_wait_if_busy(spi);
146   
147        *data8 = spi_get_rx(spi, 0);
148        data8++;
149    }
150    return;
151}
152
153void spi_ss_assert(struct spi_dev * spi, int index)
154{
155    unsigned int spi_ss = ioread32(&spi->ss);
156
157    iowrite32(&spi->ss, spi_ss | (1 << index));
158}
159
160void spi_ss_deassert(struct spi_dev * spi, int index)
161{
162    unsigned int spi_ss = ioread32(&spi->ss);
163
164    iowrite32(&spi->ss, spi_ss & ~(1 << index));
165}
166
167void spi_dev_config (
168    struct spi_dev * spi,
169    int spi_freq        ,
170    int sys_freq        ,
171    int char_len        ,
172    int tx_edge         ,
173    int rx_edge         )
174{
175    unsigned int spi_ctrl = ioread32(&spi->ctrl);
176
177    if      ( tx_edge == 0 ) spi_ctrl |=  SPI_CTRL_TXN_EN;
178    else if ( tx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_TXN_EN;
179    if      ( rx_edge == 0 ) spi_ctrl |=  SPI_CTRL_RXN_EN;
180    else if ( rx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_RXN_EN;
181    if      ( char_len > 0 ) spi_ctrl  = (spi_ctrl & ~SPI_CTRL_CHAR_LEN_MASK) |
182                                         (char_len &  SPI_CTRL_CHAR_LEN_MASK);
183
184    iowrite32(&spi->ctrl, spi_ctrl);
185
186    if (spi_freq > 0 && sys_freq > 0)
187        iowrite32(&spi->divider, _spi_calc_divider_value(spi_freq, sys_freq));
188}
189
190/*
191 * vim: tabstop=4 : shiftwidth=4 : expandtab : softtabstop=4
192 */
Note: See TracBrowser for help on using the repository browser.