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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [spi/] [arm/] [lpc2xxx/] [current/] [src/] [spi_lpc2xxx.cxx] - Blame information for rev 817

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      spi_lpc2xxx.cxx
4
//
5
//      SPI driver for LPC2xxx
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 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):    Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
43
// Contributors: 
44
// Date:         2007-07-12
45
// Purpose:      
46
// Description:  
47
//              
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
#include <pkgconf/hal.h>
53
#include <pkgconf/io_spi.h>
54
#include <pkgconf/devs_spi_arm_lpc2xxx.h>
55
 
56
#include <cyg/infra/cyg_type.h>
57
#include <cyg/infra/cyg_ass.h>
58
#include <cyg/hal/hal_io.h>
59
#include <cyg/hal/hal_if.h>
60
#include <cyg/hal/hal_intr.h>
61
#include <cyg/io/spi.h>
62
#include <cyg/io/spi_lpc2xxx.h>
63
#include <cyg/error/codes.h>
64
 
65
#define SPI_SPCR_SPIE 0x80
66
#define SPI_SPCR_LSBF 0x40
67
#define SPI_SPCR_MSTR 0x20
68
#define SPI_SPCR_CPOL 0x10
69
#define SPI_SPCR_CPHA 0x08
70
 
71
#define SPI_SPSR_SPIF 0x80
72
#define SPI_SPSR_WCOL 0x40
73
#define SPI_SPSR_ROVR 0x20
74
#define SPI_SPSR_MODF 0x10
75
#define SPI_SPSR_ABRT 0x08
76
 
77
#define SPI_SPINT     0x01
78
 
79
#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0
80
cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus0;
81
CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 0);
82
#endif
83
#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1
84
cyg_spi_lpc2xxx_bus_t cyg_spi_lpc2xxx_bus1;
85
CYG_SPI_DEFINE_BUS_TABLE(cyg_spi_lpc2xxx_dev_t, 1);
86
#endif
87
 
88
/*
89
 * Interrupt routine
90
 * read & write the next byte until count reaches zero
91
 */
92
static cyg_uint32
93
spi_lpc2xxx_isr(cyg_vector_t vec, cyg_addrword_t data)
94
{
95
  cyg_spi_lpc2xxx_bus_t *bus = (cyg_spi_lpc2xxx_bus_t *) data;
96
  cyg_uint8 tmp;
97
 
98
  tmp = bus->spi_dev->spsr;
99
 
100
  if(tmp & SPI_SPSR_MODF)
101
    bus->spi_dev->spcr = bus->spi_dev->spcr | SPI_SPCR_MSTR;
102
 
103
  tmp = bus->spi_dev->spdr;
104
 
105
  if(bus->count) {
106
    if(bus->rx)
107
      *bus->rx++ = tmp;
108
    if(--bus->count) {
109
      bus->spi_dev->spint = SPI_SPINT;
110
      bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0;
111
      cyg_drv_interrupt_acknowledge(bus->spi_vect);
112
      return CYG_ISR_HANDLED;
113
    }
114
  }
115
 
116
  bus->count = 0;
117
  bus->tx = NULL;
118
  bus->rx = NULL;
119
 
120
  bus->spi_dev->spint = SPI_SPINT;
121
  cyg_drv_interrupt_acknowledge(bus->spi_vect);
122
  return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR;
123
}
124
 
125
static void
126
spi_lpc2xxx_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
127
{
128
  cyg_drv_cond_signal(&((cyg_spi_lpc2xxx_bus_t *) data)->spi_wait);
129
}
130
 
131
 
132
/*
133
 * Configure bus for a specific baud rate
134
 */
135
static void
136
spi_lpc2xxx_baud(cyg_spi_lpc2xxx_bus_t *bus, cyg_uint32 baud)
137
{
138
  cyg_uint32 ccr = 8;
139
 
140
  if(baud) {
141
    ccr = (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED
142
           / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / baud;
143
    if(((CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED
144
         / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) / ccr) > baud)
145
      ccr++;
146
    ccr++;
147
    ccr &= 0xfe;
148
  }
149
 
150
  bus->spi_dev->spccr = ccr < 8 ? 8 : ccr;
151
}
152
 
153
/*
154
 * get/set configuration
155
 */
156
static int
157
spi_lpc2xxx_get_config(cyg_spi_device *device, cyg_uint32 key, void *buf,
158
                       cyg_uint32 *len)
159
{
160
  cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device;
161
 
162
  switch(key) {
163
    case CYG_IO_GET_CONFIG_SPI_CLOCKRATE:
164
      if(*len == sizeof(cyg_uint32)) {
165
        cyg_uint32 *b = (cyg_uint32 *) buf;
166
        *b = dev->spi_baud;
167
      } else return -EINVAL;
168
      break;
169
    default:
170
      return -EINVAL;
171
  }
172
 
173
  return ENOERR;
174
}
175
 
176
static int
177
spi_lpc2xxx_set_config(cyg_spi_device *device, cyg_uint32 key, const void *buf,
178
                       cyg_uint32 *len)
179
{
180
  cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device;
181
 
182
  switch(key) {
183
    case CYG_IO_SET_CONFIG_SPI_CLOCKRATE:
184
      if(*len == sizeof(cyg_uint32)) {
185
        dev->spi_baud = * (cyg_uint32 *) buf;
186
        spi_lpc2xxx_baud((cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus,
187
                         dev->spi_baud);
188
      }
189
      else return -EINVAL;
190
      break;
191
    default:
192
      return -EINVAL;
193
  }
194
 
195
  return ENOERR;
196
}
197
 
198
 
199
/*
200
 * Begin transaction
201
 * configure bus for device and drive CS by calling device cs() function
202
 */
203
static void
204
spi_lpc2xxx_begin(cyg_spi_device *device)
205
{
206
  cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device;
207
  cyg_spi_lpc2xxx_bus_t *bus =
208
    (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus;
209
 
210
  cyg_uint8 cr =
211
    (dev->spi_cpha ? SPI_SPCR_CPHA : 0) |
212
    (dev->spi_cpol ? SPI_SPCR_CPOL : 0) |
213
    (dev->spi_lsbf ? SPI_SPCR_LSBF : 0);
214
 
215
  bus->spi_dev->spcr = SPI_SPCR_MSTR | cr;
216
 
217
  spi_lpc2xxx_baud(bus, dev->spi_baud);
218
 
219
  dev->spi_cs(1);
220
}
221
 
222
 
223
/*
224
 * Transfer a buffer to a device,
225
 * fill another buffer with data from the device
226
 */
227
static void
228
spi_lpc2xxx_transfer(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count,
229
                     const cyg_uint8 *tx_data, cyg_uint8 *rx_data,
230
                     cyg_bool drop_cs)
231
{
232
  cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device;
233
  cyg_spi_lpc2xxx_bus_t *bus =
234
    (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus;
235
  cyg_uint8 tmp;
236
 
237
  if(!count) return;
238
 
239
  if(!polled) {
240
    bus->count = count;
241
    bus->tx = tx_data;
242
    bus->rx = rx_data;
243
 
244
    bus->spi_dev->spcr |= SPI_SPCR_SPIE;
245
    bus->spi_dev->spdr = bus->tx ? *bus->tx++ : 0;
246
 
247
    cyg_drv_mutex_lock(&bus->spi_lock);
248
    cyg_drv_dsr_lock();
249
    cyg_drv_interrupt_unmask(bus->spi_vect);
250
    while(bus->count)
251
      cyg_drv_cond_wait(&bus->spi_wait);
252
    cyg_drv_interrupt_mask(bus->spi_vect);
253
    cyg_drv_dsr_unlock();
254
    cyg_drv_mutex_unlock(&bus->spi_lock);
255
  } else do {
256
      bus->spi_dev->spdr = tx_data ? *tx_data++ : 0;
257
      while(!(bus->spi_dev->spsr & SPI_SPSR_SPIF));
258
      tmp = bus->spi_dev->spdr;
259
      if(rx_data)
260
        *rx_data++ = tmp;
261
      count--;
262
    } while(count);
263
 
264
  if(drop_cs)
265
    dev->spi_cs(0);
266
 
267
  return;
268
}
269
 
270
 
271
/*
272
 * Tick
273
 */
274
static void
275
spi_lpc2xxx_tick(cyg_spi_device *device, cyg_bool polled, cyg_uint32 count)
276
{
277
  spi_lpc2xxx_transfer(device, polled, count, NULL, NULL, false);
278
}
279
 
280
 
281
/*
282
 * End transaction
283
 * disable SPI bus, drop CS, reset transfer variables
284
 */
285
static void
286
spi_lpc2xxx_end(cyg_spi_device *device)
287
{
288
  cyg_spi_lpc2xxx_dev_t *dev = (cyg_spi_lpc2xxx_dev_t *) device;
289
  cyg_spi_lpc2xxx_bus_t *bus =
290
    (cyg_spi_lpc2xxx_bus_t *) dev->spi_device.spi_bus;
291
 
292
  bus->spi_dev->spcr = 0;
293
  dev->spi_cs(0);
294
 
295
  bus->count = 0;
296
  bus->tx = NULL;
297
  bus->rx = NULL;
298
}
299
 
300
 
301
/*
302
 * Driver & bus initialization
303
 */
304
static void
305
spi_lpc2xxx_init_bus(cyg_spi_lpc2xxx_bus_t *bus,
306
                     cyg_addrword_t dev,
307
                     cyg_vector_t vec,
308
                     cyg_priority_t prio)
309
{
310
  bus->spi_bus.spi_transaction_begin    = spi_lpc2xxx_begin;
311
  bus->spi_bus.spi_transaction_transfer = spi_lpc2xxx_transfer;
312
  bus->spi_bus.spi_transaction_tick     = spi_lpc2xxx_tick;
313
  bus->spi_bus.spi_transaction_end      = spi_lpc2xxx_end;
314
  bus->spi_bus.spi_get_config           = spi_lpc2xxx_get_config;
315
  bus->spi_bus.spi_set_config           = spi_lpc2xxx_set_config;
316
  CYG_SPI_BUS_COMMON_INIT(&bus->spi_bus);
317
 
318
  cyg_drv_mutex_init(&bus->spi_lock);
319
  cyg_drv_cond_init(&bus->spi_wait, &bus->spi_lock);
320
 
321
  bus->spi_dev = (struct spi_dev *) dev;
322
  bus->spi_vect = vec;
323
  bus->spi_prio = prio;
324
  cyg_drv_interrupt_create(
325
                           vec, prio, (cyg_addrword_t) bus,
326
                           &spi_lpc2xxx_isr, &spi_lpc2xxx_dsr,
327
                           &bus->spi_hand, &bus->spi_intr);
328
  cyg_drv_interrupt_attach(bus->spi_hand);
329
}
330
 
331
/*
332
 * initialization class
333
 */
334
class cyg_spi_lpc2xxx_init_class {
335
public:
336
  cyg_spi_lpc2xxx_init_class(void) {
337
    cyg_uint32 addr, tmp;
338
 
339
#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS0
340
    addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE
341
            + CYGARC_HAL_LPC2XXX_REG_PINSEL0);
342
    HAL_READ_UINT32(addr, tmp);
343
    tmp |= 0x5500;
344
    HAL_WRITE_UINT32(addr, tmp);
345
 
346
    spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus0,
347
                         CYGARC_HAL_LPC2XXX_REG_SPI0_BASE,
348
                         CYGNUM_HAL_INTERRUPT_SPI0,
349
                         CYGNUM_IO_SPI_ARM_LPC2XXX_BUS0_INTPRIO);
350
#endif
351
#ifdef CYGPKG_DEVS_SPI_ARM_LPC2XXX_BUS1
352
    addr = (CYGARC_HAL_LPC2XXX_REG_PIN_BASE
353
            + CYGARC_HAL_LPC2XXX_REG_PINSEL1);
354
    HAL_READ_UINT32(addr, tmp);
355
    tmp |= 0x2a8;
356
    HAL_WRITE_UINT32(addr, tmp);
357
    spi_lpc2xxx_init_bus(&cyg_spi_lpc2xxx_bus1,
358
                         CYGARC_HAL_LPC2XXX_REG_SPI1_BASE,
359
                         CYGNUM_HAL_INTERRUPT_SPI1,
360
                         CYGNUM_IO_SPI_ARM_LPC2XXX_BUS1_INTPRIO);
361
#endif
362
  }
363
};
364
 
365
static cyg_spi_lpc2xxx_init_class spi_lpc2xxx_init
366
    CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_BUS_SPI);
367
 

powered by: WebSVN 2.1.0

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