source: soft/giet_vm/giet_drivers/spi_driver.c @ 315

Last change on this file since 315 was 289, checked in by cfuguet, 11 years ago

Modifications on GIET-VM IOC driver:

  • Introducing new layer on the IOC driver. Every call to ioc_read, ioc_write, ioc_get_block_size or ioc_init

functions will call the specific driver of the used IOC
controller. Supported IOC controllers are (for now) :

  1. BDV (Soclib Block Device)
  2. HBA
  3. SPI (SDCARD - SPI controller)
  • All functions of IOC controllers drivers respect the same interface.
  • To specify the used IOC controller of the platform, a subtype field has been introduced on the map.xml file. This subtype field must be declared on the IOC periph instantiation. Available subtypes (for now) : BDV, HBA or SPI.
File size: 8.6 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : spi_driver.c
3// Date     : 31/08/2012
4// Author   : cesar fuguet
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7#include <spi_driver.h>
8#include <utils.h>
9
10///////////////////////////////////////////////////////////////////////////////
11//      bswap32()
12// This function makes a byte swap for a 4 bytes word
13// Arguments are:
14// - x : word
15// Returns the word x swapped
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//      _spi_wait_if_busy()
29// This function returns when the SPI controller has finished a transfer
30// Arguments are:
31// - spi : initialized pointer to the SPI controller
32///////////////////////////////////////////////////////////////////////////////
33static void _spi_wait_if_busy(struct spi_dev * spi)
34{
35    register int delay;
36
37    while(SPI_IS_BUSY(spi))
38    {
39        for (delay = 0; delay < 100; delay++);
40    }
41}
42
43///////////////////////////////////////////////////////////////////////////////
44//      _spi_init_transfer()
45// This function trigger transfer of the tx registers to the selected slaves
46// Arguments are:
47// - spi : initialized pointer to the SPI controller
48///////////////////////////////////////////////////////////////////////////////
49static void _spi_init_transfer(struct spi_dev * spi)
50{
51    unsigned int spi_ctrl = ioread32(&spi->ctrl);
52
53    iowrite32(&spi->ctrl, spi_ctrl | SPI_CTRL_GO_BSY);
54}
55
56///////////////////////////////////////////////////////////////////////////////
57//      _spi_calc_divider_value()
58// This function computes the value for the divider register in order to obtain
59// the SPI desired clock frequency
60// - spi_freq : desired frequency for the generated clock from the SPI
61//              controller
62// - sys_freq : system clock frequency
63// Returns the computed frequency
64///////////////////////////////////////////////////////////////////////////////
65static unsigned int _spi_calc_divider_value( unsigned int spi_freq ,
66                                             unsigned int sys_freq )
67{
68    return ((sys_freq / (spi_freq * 2)) - 1);
69}
70
71///////////////////////////////////////////////////////////////////////////////
72//      spi_put_tx()
73// This function writes a byte on the tx register and trigger transfert
74// - spi  : initialized pointer to the SPI controller
75// - byte : byte to write on tx register
76// - index: index of the tx register
77///////////////////////////////////////////////////////////////////////////////
78void spi_put_tx(struct spi_dev * spi, unsigned char byte, int index)
79{
80    _spi_wait_if_busy(spi);
81    {
82        iowrite8(&spi->rx_tx[index % 4], byte);
83        _spi_init_transfer(spi);
84    }
85    _spi_wait_if_busy(spi);
86}
87
88///////////////////////////////////////////////////////////////////////////////
89//      spi_get_rx()
90// This function reads a byte on the rx register
91// - spi  : initialized pointer to the SPI controller
92// - index: index of the rx register
93// Returns the byte read
94///////////////////////////////////////////////////////////////////////////////
95volatile unsigned char spi_get_rx(struct spi_dev * spi, int index)
96{
97    return ioread8(&spi->rx_tx[index % 4]);
98}
99
100///////////////////////////////////////////////////////////////////////////////
101//      spi_get_data()
102// This function reads count bytes and store them on a memory buffer
103// - spi   : initialized pointer to the SPI controller
104// - buffer: physical address of the buffer containing the read data
105// - count : number of bytes to get (must be 512 bytes)
106// Returns 0 if success and other value when failure
107///////////////////////////////////////////////////////////////////////////////
108unsigned int spi_get_data( struct spi_dev * spi,
109                           paddr_t buffer      ,
110                           unsigned int count  )
111{
112    unsigned int spi_ctrl0; // ctrl value before calling this function
113    unsigned int spi_ctrl;
114    int i;
115
116    /*
117     * Only reading of one block (512 bytes) are supported
118     */
119    if ( count != 512 ) return 1;
120
121    _spi_wait_if_busy(spi);
122
123    spi_ctrl0 = ioread32(&spi->ctrl);
124
125#if 0
126    /*
127     * Read data using SPI DMA mechanism
128     * Two restrictions:
129     *   1. Can transfer only one block (512 bytes).
130     *   2. The destination buffer must be aligned to SPI burst size (64 bytes)
131     */
132    if ((buffer & 0x3f) == 0)
133    {
134        _puts("spi_get_data(): Starting DMA transfer / count = ");
135        _putx(count);
136        _puts("\n");
137
138        _puts("spi_get_data(): buffer = ");
139        _putx(buffer);
140        _puts("\n");
141
142        spi->dma_base  = (buffer      ) & ((1 << 32) - 1); // 32 lsb
143        spi->dma_baseh = (buffer >> 32) & ((1 << 8 ) - 1); // 8  msb
144        spi->dma_count = count | SPI_DMA_COUNT_READ;
145
146        while ( (spi->dma_count >> 1) );
147
148        goto reset_ctrl;
149    }
150#endif
151
152    /*
153     * Read data without SPI DMA mechanism
154     *
155     * Switch to 128 bits words
156     */
157
158    spi_ctrl = (spi_ctrl0 & ~SPI_CTRL_CHAR_LEN_MASK) | 128;
159    iowrite32(&spi->ctrl, spi_ctrl);
160
161    /*
162     * Read data.
163     * Four 32 bits words at each iteration (128 bits = 16 bytes)
164     */
165    for (i = 0; i < count/16; i++)
166    {
167        iowrite32(&spi->rx_tx[0], 0xffffffff);
168        iowrite32(&spi->rx_tx[1], 0xffffffff);
169        iowrite32(&spi->rx_tx[2], 0xffffffff);
170        iowrite32(&spi->rx_tx[3], 0xffffffff);
171        iowrite32(&spi->ctrl,  spi_ctrl | SPI_CTRL_GO_BSY);
172
173        _spi_wait_if_busy(spi);
174
175        _physical_write( buffer, bswap32(ioread32(&spi->rx_tx[3])) ); 
176        buffer += 4;
177        _physical_write( buffer, bswap32(ioread32(&spi->rx_tx[2])) ); 
178        buffer += 4;
179        _physical_write( buffer, bswap32(ioread32(&spi->rx_tx[1])) ); 
180        buffer += 4;
181        _physical_write( buffer, bswap32(ioread32(&spi->rx_tx[0])) ); 
182        buffer += 4;
183    }
184
185#if 0
186reset_ctrl:
187#endif
188
189    /* Switch back to original word size */
190    iowrite32(&spi->ctrl, spi_ctrl0);
191
192    return 0;
193}
194
195///////////////////////////////////////////////////////////////////////////////
196//      spi_ss_assert()
197// This function enables a SPI slave
198// - spi   : initialized pointer to the SPI controller
199// - index : slave index
200///////////////////////////////////////////////////////////////////////////////
201void spi_ss_assert(struct spi_dev * spi, int index)
202{
203    unsigned int spi_ss = ioread32(&spi->ss);
204
205    iowrite32(&spi->ss, spi_ss | (1 << index));
206}
207
208///////////////////////////////////////////////////////////////////////////////
209//      spi_ss_deassert()
210// This function disables a SPI slave
211// - spi   : initialized pointer to the SPI controller
212// - index : slave index
213///////////////////////////////////////////////////////////////////////////////
214void spi_ss_deassert(struct spi_dev * spi, int index)
215{
216    unsigned int spi_ss = ioread32(&spi->ss);
217
218    iowrite32(&spi->ss, spi_ss & ~(1 << index));
219}
220
221///////////////////////////////////////////////////////////////////////////////
222//      _spi_init()
223// This function initializes the configuration register of SPI controller
224// - spi      : initialized pointer to the SPI controller
225// - spi_freq : SPI desired frequency (Hz)
226// - sys_freq : system frequency (Hz)
227// - char_len : bits per transfer
228// - tx_edge  : if 1, transfer on positive edge
229// - rx_edge  : if 1, latch received data on negative edge
230///////////////////////////////////////////////////////////////////////////////
231void _spi_init ( struct spi_dev * spi,
232                 int spi_freq        ,
233                 int sys_freq        ,
234                 int char_len        ,
235                 int tx_edge         ,
236                 int rx_edge         )
237{
238    unsigned int spi_ctrl = ioread32(&spi->ctrl);
239
240    if      ( tx_edge == 0 ) spi_ctrl |=  SPI_CTRL_TXN_EN;
241    else if ( tx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_TXN_EN;
242    if      ( rx_edge == 0 ) spi_ctrl |=  SPI_CTRL_RXN_EN;
243    else if ( rx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_RXN_EN;
244    if      ( char_len > 0 ) spi_ctrl  = (spi_ctrl & ~SPI_CTRL_CHAR_LEN_MASK) |
245                                         (char_len &  SPI_CTRL_CHAR_LEN_MASK);
246
247    iowrite32(&spi->ctrl, spi_ctrl);
248
249    if (spi_freq > 0 && sys_freq > 0)
250        iowrite32(&spi->divider, _spi_calc_divider_value(spi_freq, sys_freq));
251}
252
253// Local Variables:
254// tab-width: 4
255// c-basic-offset: 4
256// c-file-offsets:((innamespace . 0)(inline-open . 0))
257// indent-tabs-mode: nil
258// End:
259// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
Note: See TracBrowser for help on using the repository browser.