OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [spi/] [opencores/] [simple_spi/] [current/] [src/] [spi_simple_spi.c] - Blame information for rev 810

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 810 skrzyp
//=============================================================================
2
//
3
//      spi_simple_spi.c
4
//
5
//      SPI driver implementation for simple_spi
6
//
7
//=============================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2008, 2009 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//=============================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):   Piotr Skrzypek
43
// Date:        2012-05-14
44
//
45
//####DESCRIPTIONEND####
46
//
47
//=============================================================================
48
 
49
#include <cyg/hal/hal_io.h>
50
#include <cyg/hal/hal_if.h>
51
#include <cyg/hal/hal_intr.h>
52
#include <cyg/hal/drv_api.h>
53
 
54
#include <cyg/infra/cyg_type.h>
55
#include <cyg/infra/cyg_ass.h>
56
#include <cyg/infra/diag.h>
57
 
58
#include <cyg/io/spi.h>
59
#include <cyg/io/spi_simple_spi.h>
60
 
61
#include <pkgconf/devs_spi_opencores_simple_spi.h>
62
#include <pkgconf/hal.h>
63
#include <pkgconf/io_spi.h>
64
 
65
#define SIMPLE_SPI_BASE 0xB0000000
66
#define SIMPLE_SPI_SPACE 0x01000000
67
 
68
// Register space
69
#define SIMPLE_SPI_SPCR 0x00
70
#define SIMPLE_SPI_SPSR 0x01
71
#define SIMPLE_SPI_SPDR 0x02
72
#define SIMPLE_SPI_SPER 0x03
73
#define SIMPLE_SPI_SPSS 0x04
74
 
75
// SIMPLE_SPI_SPCR bits
76
#define SIMPLE_SPI_SPCR_SPIE 0x80
77
#define SIMPLE_SPI_SPCR_SPE  0x40
78
#define SIMPLE_SPI_SPCR_MSTR 0x10
79
#define SIMPLE_SPI_SPCR_CPOL 0x08
80
#define SIMPLE_SPI_SPCR_CPHA 0x04
81
#define SIMPLE_SPI_SPCR_SPR  0x03
82
 
83
// SIMPLE_SPI_SPSR bits
84
#define SIMPLE_SPI_SPSR_SPIF    0x80
85
#define SIMPLE_SPI_SPSR_WCOL    0x40
86
#define SIMPLE_SPI_SPSR_WFFULL  0x08
87
#define SIMPLE_SPI_SPSR_WFEMPTY 0x04
88
#define SIMPLE_SPI_SPSR_RFFULL  0x02
89
#define SIMPLE_SPI_SPSR_RFEMPTY 0x01
90
 
91
// SIMPLE_SPI_SPER bits
92
#define SIMPLE_SPI_SPER_ICNT(x) ((x-1) << 6)
93
 
94
// Divider table
95
cyg_uint8 simple_spi_divflags[] = {0x0, 0x1, 0x4, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB};
96
 
97
cyg_vector_t simple_spi_int_vectors[] = { CYGNUM_DEVS_SPI_OPENCORES_SIMPLE_SPI_INTS };
98
 
99
static cyg_uint32 simple_spi_isr(cyg_vector_t vector, cyg_addrword_t data) {
100
 
101
        cyg_drv_interrupt_mask(vector);
102
        cyg_drv_interrupt_acknowledge(vector);
103
 
104
        return(CYG_ISR_CALL_DSR | CYG_ISR_HANDLED);
105
 
106
}
107
 
108
static void simple_spi_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) {
109
 
110
        cyg_spi_opencores_simple_spi_bus_t *bus = (cyg_spi_opencores_simple_spi_bus_t *) data;
111
 
112
        // Clear interrupt
113
        HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPSR, SIMPLE_SPI_SPSR_SPIF);
114
        cyg_drv_interrupt_unmask(vector);
115
 
116
        // Unlock waiting thread
117
        cyg_drv_cond_signal(&bus->condvar);
118
 
119
}
120
 
121
 
122
static void simple_spi_transaction_begin(cyg_spi_device* device) {
123
 
124
        cyg_spi_opencores_simple_spi_bus_t* bus = (cyg_spi_opencores_simple_spi_bus_t*) device->spi_bus;
125
        cyg_spi_opencores_simple_spi_device_t* dev = (cyg_spi_opencores_simple_spi_device_t*) device;
126
 
127
        // Temporarily disable peripheral and clean up fifos.
128
        HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, 0);
129
 
130
        // Determine divider flags to meet required SCK speed. Find highest speed that is
131
        // lower or equal the provided threshold.
132
        cyg_uint32 freq = CYGNUM_DEVS_SPI_OPENCORES_SIMPLE_SPI_BUS_SPEED * 1000000;
133
        int i = 0;
134
        while((freq / (1 << (i + 1))) > (dev->freq) && (i) < (sizeof(simple_spi_divflags)-1)) {
135
                i++;
136
        }
137
 
138
        cyg_uint8 reg;
139
 
140
        // Configure extensions register with speed and interrupt granularity
141
        reg = SIMPLE_SPI_SPER_ICNT(1) |
142
              (simple_spi_divflags[i] >> 2);
143
        HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPER, reg);
144
 
145
        // Configure control register with speed, phase and polarity
146
        reg = SIMPLE_SPI_SPCR_SPE |
147
              SIMPLE_SPI_SPCR_MSTR |
148
              (dev->polarity ? SIMPLE_SPI_SPCR_CPOL : 0) |
149
              (dev->phase ? SIMPLE_SPI_SPCR_CPHA : 0) |
150
              (simple_spi_divflags[i] & SIMPLE_SPI_SPCR_SPR);
151
        HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, reg);
152
 
153
}
154
 
155
static void simple_spi_transaction_transfer_tick(cyg_spi_device* device,
156
                                                 cyg_bool polled,
157
                                                 cyg_uint32 count,
158
                                                 const cyg_uint8* tx_data,
159
                                                 cyg_uint8* rx_data,
160
                                                 cyg_bool drop_cs,
161
                                                 cyg_bool is_tick) {
162
 
163
        cyg_spi_opencores_simple_spi_bus_t* bus = (cyg_spi_opencores_simple_spi_bus_t*) device->spi_bus;
164
        cyg_spi_opencores_simple_spi_device_t* dev = (cyg_spi_opencores_simple_spi_device_t*) device;
165
 
166
        // Enable interrupts if using interrupt mode
167
        cyg_uint8 reg;
168
        if(!polled) {
169
                HAL_READ_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, reg);
170
                reg |= SIMPLE_SPI_SPCR_SPIE;
171
                HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, reg);
172
        }
173
 
174
        // Assert CS if it is not asserted yet. Note that tick command is not supposed
175
        // to use CS
176
        if(!bus->cs_asserted && !is_tick) {
177
                HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPSS, (1 << dev->cs));
178
                CYGACC_CALL_IF_DELAY_US(dev->cs_to_tran);
179
                bus->cs_asserted = true;
180
        }
181
 
182
        // Transfer the data
183
        int i;
184
        for(i = 0; i < count; i++) {
185
 
186
                // If multiple bytes are transfered, then wait tran_to_tran
187
                if(i > 0) {
188
                        CYGACC_CALL_IF_DELAY_US(dev->tran_to_tran);
189
                }
190
 
191
                // Send data or NULL (tick uses NULL)
192
                reg = tx_data ? tx_data[i] : 0;
193
                HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPDR, reg);
194
 
195
                // Wait for transmission
196
                if(polled) {
197
                        do {
198
                                HAL_READ_UINT8(bus->base_addr + SIMPLE_SPI_SPSR, reg);
199
                        } while(!(reg & SIMPLE_SPI_SPSR_SPIF));
200
                        HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPSR, SIMPLE_SPI_SPSR_SPIF);
201
                }
202
                else {
203
                        //FIXME at high SCK speeds the interrupt happens so quickly that
204
                        //this thread can't make to cond_wait. Signal from DSR is posted 
205
                        //to nowhere and the thread hangs.
206
                        cyg_drv_mutex_lock(&bus->mutex);
207
                        cyg_drv_cond_wait(&bus->condvar);
208
                        cyg_drv_mutex_unlock(&bus->mutex);
209
                }
210
 
211
                // Read received byte and store if required
212
                HAL_READ_UINT8(bus->base_addr + SIMPLE_SPI_SPDR, reg);
213
                if(rx_data) {
214
                        rx_data[i] = reg;
215
                }
216
        }
217
 
218
        // Drop CS if required
219
        if(drop_cs && !is_tick) {
220
                bus->cs_asserted = false;
221
                CYGACC_CALL_IF_DELAY_US(dev->tran_to_cs);
222
                HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPSS, 0);
223
        }
224
 
225
        // Disable interrupts if using interrupt mode
226
        if(!polled) {
227
                HAL_READ_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, reg);
228
                reg &= ~SIMPLE_SPI_SPCR_SPIE;
229
                HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, reg);
230
        }
231
 
232
}
233
 
234
static void simple_spi_transaction_transfer(cyg_spi_device* device,
235
                                       cyg_bool polled,
236
                                       cyg_uint32 count,
237
                                       const cyg_uint8* tx_data,
238
                                       cyg_uint8* rx_data,
239
                                       cyg_bool drop_cs) {
240
 
241
        simple_spi_transaction_transfer_tick(device, polled, count, tx_data, rx_data, drop_cs, false);
242
 
243
}
244
 
245
static void simple_spi_transaction_tick(cyg_spi_device* device,
246
                                   cyg_bool polled,
247
                                   cyg_uint32 count) {
248
 
249
        simple_spi_transaction_transfer_tick(device, polled, count, NULL, NULL, true, true);
250
 
251
}
252
 
253
static void simple_spi_transaction_end(cyg_spi_device* device) {
254
 
255
        cyg_spi_opencores_simple_spi_bus_t* bus = (cyg_spi_opencores_simple_spi_bus_t*) device->spi_bus;
256
 
257
        // Disable the peripheral and clean up buffers.
258
        HAL_WRITE_UINT8(bus->base_addr + SIMPLE_SPI_SPCR, 0);
259
 
260
}
261
 
262
static int simple_spi_get_config(cyg_spi_device* device,
263
                            cyg_uint32 key,
264
                            void* buf,
265
                            cyg_uint32* len) {
266
 
267
        cyg_spi_opencores_simple_spi_device_t* dev = (cyg_spi_opencores_simple_spi_device_t*) device;
268
 
269
        if(key == CYG_IO_GET_CONFIG_SPI_CLOCKRATE) {
270
                cyg_uint32 *freq = (cyg_uint32*) buf;
271
                *freq = dev->freq;
272
                return 0;
273
        }
274
        else {
275
                return -1;
276
        }
277
}
278
 
279
static int simple_spi_set_config(cyg_spi_device* device,
280
                            cyg_uint32 key,
281
                            const void* buf,
282
                            cyg_uint32* len) {
283
 
284
        cyg_spi_opencores_simple_spi_device_t* dev = (cyg_spi_opencores_simple_spi_device_t*) device;
285
 
286
        if(key == CYG_IO_SET_CONFIG_SPI_CLOCKRATE) {
287
                dev->freq = *((cyg_uint32*)buf);
288
                return 0;
289
        }
290
        else {
291
                return -1;
292
        }
293
 
294
}
295
 
296
// Declare number of SPI buses
297
cyg_spi_opencores_simple_spi_bus_t cyg_spi_simple_spi_bus[CYGNUM_DEVS_SPI_OPENCORES_SIMPLE_SPI_COUNT];
298
 
299
// This is a low level constructor of the driver. It is called very early
300
static void CYGBLD_ATTRIB_C_INIT_PRI(CYG_INIT_BUS_SPI) simple_spi_init(void) {
301
 
302
        int i;
303
        cyg_uint32 base = SIMPLE_SPI_BASE;
304
        for(i = 0; i < CYGNUM_DEVS_SPI_OPENCORES_SIMPLE_SPI_COUNT; i++) {
305
 
306
                // Connect functions
307
                cyg_spi_simple_spi_bus[i].spi_bus.spi_transaction_begin = simple_spi_transaction_begin;
308
                cyg_spi_simple_spi_bus[i].spi_bus.spi_transaction_transfer = simple_spi_transaction_transfer;
309
                cyg_spi_simple_spi_bus[i].spi_bus.spi_transaction_tick = simple_spi_transaction_tick;
310
                cyg_spi_simple_spi_bus[i].spi_bus.spi_transaction_end = simple_spi_transaction_end;
311
                cyg_spi_simple_spi_bus[i].spi_bus.spi_get_config = simple_spi_get_config;
312
                cyg_spi_simple_spi_bus[i].spi_bus.spi_set_config = simple_spi_set_config;
313
 
314
                // Fill the base address
315
                cyg_spi_simple_spi_bus[i].base_addr = base;
316
                base += SIMPLE_SPI_SPACE;
317
 
318
                // Initialize interrupts
319
                cyg_drv_interrupt_create(simple_spi_int_vectors[i],
320
                                         CYGNUM_DEVS_SPI_OPENCORES_SIMPLE_SPI_INT_PRI,
321
                                         (cyg_addrword_t) &cyg_spi_simple_spi_bus[i],
322
                                         simple_spi_isr,
323
                                         simple_spi_dsr,
324
                                         &cyg_spi_simple_spi_bus[i].int_handle,
325
                                         &cyg_spi_simple_spi_bus[i].int_data);
326
                cyg_drv_interrupt_attach(cyg_spi_simple_spi_bus[i].int_handle);
327
                cyg_drv_interrupt_unmask(simple_spi_int_vectors[i]);
328
 
329
                // Initialize synchronization
330
                cyg_drv_mutex_init(&cyg_spi_simple_spi_bus[i].mutex);
331
                cyg_drv_cond_init(&cyg_spi_simple_spi_bus[i].condvar,
332
                                  &cyg_spi_simple_spi_bus[i].mutex);
333
 
334
                // Private status
335
                cyg_spi_simple_spi_bus[i].cs_asserted = false;
336
 
337
                // Initialize upper layer
338
                CYG_SPI_BUS_COMMON_INIT(&cyg_spi_simple_spi_bus[i].spi_bus);
339
        }
340
}
341
 
342
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.