Ticket #1489: bfinspi.patch

File bfinspi.patch, 16.0 KB (added by Allan Hessenflow, on 01/10/10 at 21:20:24)

implement bfin spi driver

Line 
1Index: c/src/lib/libcpu/bfin/ChangeLog
2===================================================================
3RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/bfin/ChangeLog,v
4retrieving revision 1.13
5diff -c -3 -p -r1.13 ChangeLog
6*** c/src/lib/libcpu/bfin/ChangeLog     11 Dec 2009 04:15:58 -0000      1.13
7--- c/src/lib/libcpu/bfin/ChangeLog     10 Jan 2010 22:12:55 -0000
8***************
9*** 1,3 ****
10--- 1,10 ----
11+ 2010-01-10    Allan Hessenflow <allanh@kallisti.com
12+
13+       * serial/spi.c, serial/spi.h:
14+       Fill in skeleton with functional SPI master code.
15+       * include/spiRegs.h:
16+       Correct spi shadow register declaration.
17+
18  2009-12-11    Ralf Corsépius <ralf.corsepius@rtems.org>
19 
20        * serial/uart.c:
21Index: c/src/lib/libcpu/bfin/README
22===================================================================
23RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/bfin/README,v
24retrieving revision 1.1
25diff -c -3 -p -r1.1 README
26*** c/src/lib/libcpu/bfin/README        15 Aug 2008 20:18:40 -0000      1.1
27--- c/src/lib/libcpu/bfin/README        10 Jan 2010 22:12:55 -0000
28*************** It is assumed that bsp.h includes <libcp
29*** 9,15 ****
30  the processor type.  This is how the libcpu modules determine which
31  processor variant they're being built for.
32 
33! serial/spi* and serial/sport* are currently just placeholders.
34! serial/twi* does not contain enough code to do anything useful;
35! it is however a start at an I2C driver.
36 
37--- 9,15 ----
38  the processor type.  This is how the libcpu modules determine which
39  processor variant they're being built for.
40 
41! serial/sport* is currently just a placeholders.  serial/twi* does not
42! contain enough code to do anything useful; it is however a start at an
43! I2C driver.
44 
45Index: c/src/lib/libcpu/bfin/include/spiRegs.h
46===================================================================
47RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/bfin/include/spiRegs.h,v
48retrieving revision 1.1
49diff -c -3 -p -r1.1 spiRegs.h
50*** c/src/lib/libcpu/bfin/include/spiRegs.h     15 Aug 2008 20:18:41 -0000      1.1
51--- c/src/lib/libcpu/bfin/include/spiRegs.h     10 Jan 2010 22:12:55 -0000
52***************
53*** 22,28 ****
54  #define SPI_TDBR_OFFSET                               0x000c
55  #define SPI_RDBR_OFFSET                               0x0010
56  #define SPI_BAUD_OFFSET                               0x0014
57! #define SPI_SHADOW                                    0x0018
58 
59 
60  /* register fields */
61--- 22,28 ----
62  #define SPI_TDBR_OFFSET                               0x000c
63  #define SPI_RDBR_OFFSET                               0x0010
64  #define SPI_BAUD_OFFSET                               0x0014
65! #define SPI_SHADOW_OFFSET                             0x0018
66 
67 
68  /* register fields */
69Index: c/src/lib/libcpu/bfin/serial/spi.c
70===================================================================
71RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/bfin/serial/spi.c,v
72retrieving revision 1.2
73diff -c -3 -p -r1.2 spi.c
74*** c/src/lib/libcpu/bfin/serial/spi.c  30 Nov 2009 05:03:49 -0000      1.2
75--- c/src/lib/libcpu/bfin/serial/spi.c  10 Jan 2010 22:12:55 -0000
76***************
77*** 1,8 ****
78- /* placeholder (just a shell) */
79-
80  /*  SPI driver for Blackfin
81   *
82!  *  Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA
83   *             written by Allan Hessenflow <allanh@kallisti.com>
84   *
85   *  The license and distribution terms for this file may be
86--- 1,6 ----
87  /*  SPI driver for Blackfin
88   *
89!  *  Copyright (c) 2010 Kallisti Labs, Los Gatos, CA, USA
90   *             written by Allan Hessenflow <allanh@kallisti.com>
91   *
92   *  The license and distribution terms for this file may be
93***************
94*** 12,109 ****
95   *  $Id: spi.c,v 1.2 2009/11/30 05:03:49 ralf Exp $
96   */
97 
98-
99  #include <stdlib.h>
100! #include <rtems.h>
101  #include <rtems/libi2c.h>
102-
103  #include <libcpu/spiRegs.h>
104  #include "spi.h"
105 
106 
107! static rtems_status_code spiInit(rtems_libi2c_bus_t *bus) {
108!   bfin_spi_softc_t *softc;
109!   rtems_status_code status;
110 
111!   softc = &(((bfin_spi_desc_t *)(bus))->softc);
112!
113!   status = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
114                                    0,
115                                    RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
116                                    0,
117!                                   &softc->irq_sema_id);
118 
119!   return status;
120  }
121 
122! static rtems_status_code spiSendStart(rtems_libi2c_bus_t *bus) {
123!   bfin_spi_softc_t *softc;
124!   rtems_status_code status;
125!
126!   status = RTEMS_SUCCESSFUL;
127!   softc = &(((bfin_spi_desc_t *)(bus))->softc);
128 
129!   return status;
130  }
131 
132! static rtems_status_code spiSendStop(rtems_libi2c_bus_t *bus) {
133!   bfin_spi_softc_t *softc;
134!   rtems_status_code status;
135 
136!   status = RTEMS_SUCCESSFUL;
137!   softc = &(((bfin_spi_desc_t *)(bus))->softc);
138!
139!   return status;
140  }
141 
142! static rtems_status_code spiSendAddr(rtems_libi2c_bus_t *bus,
143!                                      uint32_t addr, int rw) {
144!   bfin_spi_softc_t *softc;
145!   rtems_status_code status;
146!
147!   status = RTEMS_SUCCESSFUL;
148!   softc = &(((bfin_spi_desc_t *)(bus))->softc);
149 
150!   return status;
151  }
152 
153! static int spiReadBytes(rtems_libi2c_bus_t *bus,
154!                         unsigned char *buf, int len) {
155!   bfin_spi_softc_t *softc;
156 
157!   softc = &(((bfin_spi_desc_t *)(bus))->softc);
158 
159!   return 0;
160  }
161 
162- static int spiWriteBytes(rtems_libi2c_bus_t *bus,
163-                          unsigned char *buf, int len) {
164-   bfin_spi_softc_t *softc;
165-
166-   softc = &(((bfin_spi_desc_t *)(bus))->softc);
167-
168-   return 0;
169- }
170-
171- static int spiIoctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) {
172-   bfin_spi_softc_t *softc;
173-
174-   softc = &(((bfin_spi_desc_t *)(bus))->softc);
175-
176-
177-   return 0;
178- }
179-
180- void bfin_spi_isr(int source) {
181- }
182-
183- rtems_libi2c_bus_ops_t bfin_spi_libi2c_bus_ops = {
184-   init: spiInit,
185-   send_start: spiSendStart,
186-   send_stop: spiSendStop,
187-   send_addr: spiSendAddr,
188-   read_bytes: spiReadBytes,
189-   write_bytes: spiWriteBytes,
190-   ioctl: spiIoctl
191- };
192-
193--- 10,242 ----
194   *  $Id: spi.c,v 1.2 2009/11/30 05:03:49 ralf Exp $
195   */
196 
197  #include <stdlib.h>
198! #include <bsp.h>
199! #include <rtems/error.h>
200! #include <rtems/bspIo.h>
201! #include <errno.h>
202  #include <rtems/libi2c.h>
203  #include <libcpu/spiRegs.h>
204  #include "spi.h"
205 
206 
207! #ifndef BFIN_REG16
208! #define BFIN_REG16(base, offset) \
209!         (*((uint16_t volatile *) ((uint8_t *)(base) + (offset))))
210! #endif
211!
212!
213! static bfin_spi_state_t *bfin_spi;
214!
215!
216! void bfin_spi_isr(int v) {
217!   bfin_spi_state_t *state;
218!   uint16_t r;
219!
220!   state = bfin_spi;
221!   if (state->len > state->bytes_per_word) {
222!     if (state->wr_ptr) {
223!       if (state->bytes_per_word == 2)
224!         r = *(uint16_t *) state->wr_ptr;
225!       else
226!         r = (uint16_t) *state->wr_ptr;
227!       state->wr_ptr += state->bytes_per_word;
228!     } else
229!       r = state->idle_pattern;
230!     BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r;
231!   }
232!   state->len -= state->bytes_per_word;
233!   if (state->len <= 0) {
234!     /*
235!        The transfers are done, so I don't want to kick off another
236!        transfer or get any more interrupts.  Reading the last word from
237!        SPI_SHADOW instead of SPI_RDBR should prevent it from triggering
238!        another transfer, but that doesn't clear the interrupt flag.  I
239!        could mask the interrupt in the SIC, but that would preclude ever
240!        using the DMA channel that shares the interrupt independently (and
241!        they might just share it with something more important in some other
242!        member of the Blackfin family).  And who knows what problems it
243!        might cause in this code potentially dealing with that still pended
244!        interrupt at the beginning of the next transfer.
245!
246!        So instead I disable the SPI interface, read the data from RDBR
247!        (thus clearing the interrupt but not triggering another transfer
248!        since the interface is disabled), then re-eanble the interface.
249!        This has the problem that the bf537 tri-states the SPI signals
250!        while the interface is disabled.  Either adding pull-ups on at
251!        least the chip select signals, or using GPIOs for them so they're
252!        not controlled by the SPI module, would be correct fixes for that
253!        (really pull-ups/downs should be added to the SPI CLK and MOSI
254!        signals as well to insure they cannot float into some region that
255!        causes input structures to consume excessive power).  Or they can
256!        all be left alone, assuming that there's enough capacitance on the
257!        lines to prevent any problems for the short time they're being left
258!        disabled.
259!
260!        An alternative approach I attempted involved switching TIMOD
261!        between RDBR and TDBR when starting and finishing a transfer, but
262!        I didn't get anywhere with that.  In my limited testing TIMOD TDBR
263!        wasn't behaving as I expected it to, but maybe with more
264!        experimentation I'd find some solution there.  However I'm out
265!        of time for this project, at least for now.
266!     */
267!
268!     BFIN_REG16(state->base, SPI_CTL_OFFSET) &= ~SPI_CTL_SPE;
269!     r = BFIN_REG16(state->base, SPI_RDBR_OFFSET);
270!     BFIN_REG16(state->base, SPI_CTL_OFFSET) |= SPI_CTL_SPE;
271!     rtems_semaphore_release(state->sem);
272!   } else
273!     r = BFIN_REG16(state->base, SPI_RDBR_OFFSET);
274!
275!   if (state->rd_ptr) {
276!     if (state->bytes_per_word == 2)
277!       *(uint16_t *) state->rd_ptr = r;
278!     else
279!       *state->rd_ptr = (uint8_t) r;
280!     state->rd_ptr += state->bytes_per_word;
281!   }
282! }
283!
284! static rtems_status_code setTFRMode(rtems_libi2c_bus_t *bus,
285!                                     const rtems_libi2c_tfr_mode_t *tfrMode) {
286!   rtems_status_code result;
287!   bfin_spi_state_t *state;
288!   uint32_t divisor;
289!   uint16_t ctrl;
290!
291!   result = RTEMS_SUCCESSFUL;
292!   state = &((bfin_spi_bus_t *) bus)->p;
293!
294!   if (result == RTEMS_SUCCESSFUL) {
295!     if (tfrMode->bits_per_char != 8 &&
296!         tfrMode->bits_per_char != 16)
297!       result = RTEMS_INVALID_NUMBER;
298!     if (tfrMode->baudrate <= 0)
299!       result = RTEMS_INVALID_NUMBER;
300!   }
301!   if (result == RTEMS_SUCCESSFUL) {
302!     divisor = (SCLK / 2 + tfrMode->baudrate - 1) /
303!               tfrMode->baudrate;
304!     if (divisor < 2)
305!       divisor = 2;
306!     else if (divisor > 65535)
307!       result = RTEMS_INVALID_NUMBER;
308!   }
309!   if (result == RTEMS_SUCCESSFUL) {
310!     state->idle_pattern = (uint16_t) tfrMode->idle_char;
311!     state->bytes_per_word = (tfrMode->bits_per_char > 8) ? 2 : 1;
312!     BFIN_REG16(state->base, SPI_BAUD_OFFSET) = divisor;
313!     ctrl = BFIN_REG16(state->base, SPI_CTL_OFFSET);
314!     if (tfrMode->lsb_first)
315!       ctrl |= SPI_CTL_LSBF;
316!     else
317!       ctrl &= ~SPI_CTL_LSBF;
318!     if (tfrMode->bits_per_char > 8)
319!       ctrl |= SPI_CTL_SIZE;
320!     else
321!       ctrl &= ~SPI_CTL_SIZE;
322!     if (tfrMode->clock_inv)
323!       ctrl |= SPI_CTL_CPOL;
324!     else
325!       ctrl &= ~SPI_CTL_CPOL;
326!     if (tfrMode->clock_phs)
327!       ctrl |= SPI_CTL_CPHA;
328!     else
329!       ctrl &= ~SPI_CTL_CPHA;
330!     BFIN_REG16(state->base, SPI_CTL_OFFSET) = ctrl;
331!   }
332!
333!   return result;
334! }
335!
336! static int readWrite(rtems_libi2c_bus_t *bus, uint8_t *rdBuf,
337!                      const uint8_t *wrBuf, int len) {
338!   rtems_status_code result;
339!   bfin_spi_state_t *state;
340!   uint16_t r;
341!
342!   result = RTEMS_SUCCESSFUL;
343!   state = &((bfin_spi_bus_t *) bus)->p;
344!
345!   if (len) {
346!     state->rd_ptr = rdBuf;
347!     state->wr_ptr = wrBuf;
348!     state->len = len;
349!     if (state->wr_ptr) {
350!       if (state->bytes_per_word == 2)
351!         r = *(uint16_t *) state->wr_ptr;
352!       else
353!         r = (uint16_t) *state->wr_ptr;
354!       state->wr_ptr += state->bytes_per_word;
355!     } else
356!       r = state->idle_pattern;
357!     BFIN_REG16(state->base, SPI_TDBR_OFFSET) = r;
358!     BFIN_REG16(state->base, SPI_RDBR_OFFSET); /* trigger */
359!     /* wait until done */
360!     do {
361!       result = rtems_semaphore_obtain(state->sem, RTEMS_WAIT, 100);
362!     } while (result == RTEMS_SUCCESSFUL && state->len > 0);
363!   }
364!
365!   return (result == RTEMS_SUCCESSFUL) ? len : -result;
366! }
367!
368!
369! rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus) {
370!   rtems_status_code result;
371!   bfin_spi_state_t *state;
372!
373!   state = &((bfin_spi_bus_t *) bus)->p;
374!
375!   BFIN_REG16(state->base, SPI_CTL_OFFSET) = SPI_CTL_SPE |
376!                                             SPI_CTL_MSTR |
377!                                             SPI_CTL_CPHA |
378!                                             SPI_CTL_TIMOD_RDBR;
379 
380!   result = rtems_semaphore_create(rtems_build_name('s','p','i','s'),
381                                    0,
382                                    RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
383                                    0,
384!                                   &state->sem);
385!   if (result == RTEMS_SUCCESSFUL)
386!     bfin_spi = state; /* for isr */
387 
388!   return result;
389  }
390 
391! rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus) {
392 
393!   return RTEMS_SUCCESSFUL;
394  }
395 
396! int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) {
397 
398!   return readWrite(bus, buf, NULL, len);
399  }
400 
401! int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len) {
402 
403!   return readWrite(bus, NULL, buf, len);
404  }
405 
406! int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) {
407!   int result;
408 
409!   result = -RTEMS_NOT_DEFINED;
410!   switch(cmd) {
411!   case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
412!     result = -setTFRMode(bus, (const rtems_libi2c_tfr_mode_t *) arg);
413!     break;
414!   case RTEMS_LIBI2C_IOCTL_READ_WRITE:
415!     result = readWrite(bus,
416!                        ((rtems_libi2c_read_write_t *) arg)->rd_buf,
417!                        ((rtems_libi2c_read_write_t *) arg)->wr_buf,
418!                        ((rtems_libi2c_read_write_t *) arg)->byte_cnt);
419!     break;
420!   default:
421!     break;
422!   }
423 
424!   return result;
425  }
426 
427Index: c/src/lib/libcpu/bfin/serial/spi.h
428===================================================================
429RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/bfin/serial/spi.h,v
430retrieving revision 1.3
431diff -c -3 -p -r1.3 spi.h
432*** c/src/lib/libcpu/bfin/serial/spi.h  30 Nov 2009 05:03:49 -0000      1.3
433--- c/src/lib/libcpu/bfin/serial/spi.h  10 Jan 2010 22:12:55 -0000
434***************
435*** 1,9 ****
436- /* placeholder (just a shell) */
437-
438  /*
439   *  RTEMS driver for Blackfin SPI
440   *
441!  *  COPYRIGHT (c) 2008 Kallisti Labs, Los Gatos, CA, USA
442   *            written by Allan Hessenflow <allanh@kallisti.com>
443   *
444   *  The license and distribution terms for this file may be
445--- 1,7 ----
446  /*
447   *  RTEMS driver for Blackfin SPI
448   *
449!  *  COPYRIGHT (c) 2010 Kallisti Labs, Los Gatos, CA, USA
450   *            written by Allan Hessenflow <allanh@kallisti.com>
451   *
452   *  The license and distribution terms for this file may be
453***************
454*** 13,52 ****
455   *  $Id: spi.h,v 1.3 2009/11/30 05:03:49 ralf Exp $
456   */
457 
458!
459! #ifndef _spi_h_
460! #define _spi_h_
461!
462 
463  #ifdef __cplusplus
464  extern "C" {
465  #endif
466 
467-
468  typedef struct {
469!   /* parameters provided by bsp */
470!   uint32_t freq;
471!   void    *base;
472!   bool     fast;
473!   /* internal use */
474!   rtems_id irq_sema_id;
475! } bfin_spi_softc_t;
476 
477  typedef struct {
478    rtems_libi2c_bus_t bus;
479!   bfin_spi_softc_t softc;
480! } bfin_spi_desc_t;
481 
482 
483! extern rtems_libi2c_bus_ops_t bfin_spi_libi2c_bus_ops;
484 
485 
486! void bfin_spi_isr(int source);
487 
488 
489  #ifdef __cplusplus
490  }
491  #endif
492 
493- #endif /* _spi_h_ */
494 
495--- 11,55 ----
496   *  $Id: spi.h,v 1.3 2009/11/30 05:03:49 ralf Exp $
497   */
498 
499! #ifndef _spi_h
500! #define _spi_h
501 
502  #ifdef __cplusplus
503  extern "C" {
504  #endif
505 
506  typedef struct {
507!   void *base;
508!   /* remaining entries are for internal use */
509!   rtems_id sem;
510!   int bytes_per_word;
511!   uint16_t idle_pattern;
512!   uint8_t *rd_ptr;
513!   const uint8_t *wr_ptr;
514!   int len;
515! } bfin_spi_state_t;
516 
517  typedef struct {
518    rtems_libi2c_bus_t bus;
519!   bfin_spi_state_t p;
520! } bfin_spi_bus_t;
521!
522!
523! void bfin_spi_isr(int v);
524 
525+ rtems_status_code bfin_spi_init(rtems_libi2c_bus_t *bus);
526 
527! rtems_status_code bfin_spi_send_start(rtems_libi2c_bus_t *bus);
528 
529+ int bfin_spi_read_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len);
530 
531! int bfin_spi_write_bytes(rtems_libi2c_bus_t *bus, unsigned char *buf, int len);
532 
533+ int bfin_spi_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg);
534 
535  #ifdef __cplusplus
536  }
537  #endif
538 
539 
540+ #endif /* _spi_h */