source: rtems/bsps/arm/atsam/spi/atsam_spi_bus.c @ 923a033

Last change on this file since 923a033 was 923a033, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 6, 2019 at 10:48:00 AM

bsp/atsam: Change CS delay after transfer

  • Property mode set to 100644
File size: 17.0 KB
Line 
1/* ---------------------------------------------------------------------------- */
2/*                  Atmel Microcontroller Software Support                      */
3/*                       SAM Software Package License                           */
4/* ---------------------------------------------------------------------------- */
5/* Copyright (c) 2015, Atmel Corporation                                        */
6/* Copyright (c) 2016, embedded brains GmbH                                     */
7/*                                                                              */
8/* All rights reserved.                                                         */
9/*                                                                              */
10/* Redistribution and use in source and binary forms, with or without           */
11/* modification, are permitted provided that the following condition is met:    */
12/*                                                                              */
13/* - Redistributions of source code must retain the above copyright notice,     */
14/* this list of conditions and the disclaimer below.                            */
15/*                                                                              */
16/* Atmel's name may not be used to endorse or promote products derived from     */
17/* this software without specific prior written permission.                     */
18/*                                                                              */
19/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
20/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
21/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
22/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
23/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
24/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
25/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
26/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
27/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
28/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
29/* ---------------------------------------------------------------------------- */
30
31#include <bsp/atsam-clock-config.h>
32#include <bsp/atsam-spi.h>
33#include <bsp/iocopy.h>
34
35#include <rtems/thread.h>
36
37#include <dev/spi/spi.h>
38
39#include <string.h>
40
41#define MAX_SPI_FREQUENCY 50000000
42
43#define DMA_NR_DESC_PER_DIR 3
44#define DMA_DESC_ALLIGNMENT 4
45
46#define DMA_BUF_RX 0
47#define DMA_BUF_TX 1
48#define DMA_BUF_DIRS 2
49
50struct atsam_spi_xdma_buf {
51  LinkedListDescriporView0 desc[DMA_NR_DESC_PER_DIR];
52  uint8_t leadbuf[CPU_CACHE_LINE_BYTES];
53  uint8_t trailbuf[CPU_CACHE_LINE_BYTES];
54};
55
56typedef struct {
57  spi_bus base;
58  rtems_binary_semaphore sem;
59  bool msg_cs_change;
60  const spi_ioc_transfer *msg_current;
61  const spi_ioc_transfer *msg_next;
62  uint32_t msg_todo;
63  int msg_error;
64  Spi *spi_regs;
65  uint32_t dma_tx_channel;
66  uint32_t dma_rx_channel;
67  struct atsam_spi_xdma_buf *dma_bufs;
68  size_t leadbuf_rx_buffered_len;
69  size_t trailbuf_rx_buffered_len;
70  int transfer_in_progress;
71  bool chip_select_active;
72  bool chip_select_decode;
73  uint8_t spi_id;
74  uint32_t peripheral_clk_per_us;
75  uint32_t spi_mr;
76  uint32_t spi_csr[4];
77} atsam_spi_bus;
78
79static void atsam_spi_wakeup_task(atsam_spi_bus *bus)
80{
81  rtems_binary_semaphore_post(&bus->sem);
82}
83
84static uint8_t atsam_calculate_dlybcs(const atsam_spi_bus *bus)
85{
86  uint32_t dlybcs = bus->base.delay_usecs * bus->peripheral_clk_per_us;
87
88  if (dlybcs > 0xff) {
89    dlybcs = 0xff;
90  }
91
92  return dlybcs;
93}
94
95static uint32_t atsam_calculate_scbr(uint32_t speed_hz)
96{
97  uint32_t scbr;
98
99  scbr = BOARD_MCK / speed_hz;
100  if (scbr > 0x0FF) {
101    /* Best estimation we can offer with the hardware. */
102    scbr = 0x0FF;
103  }
104  if (scbr == 0) {
105    /* SCBR = 0 isn't allowed. */
106    scbr = 1;
107  }
108
109  return scbr;
110}
111
112static void atsam_set_phase_and_polarity(uint32_t mode, uint32_t *csr)
113{
114  uint32_t mode_mask = mode & SPI_MODE_3;
115
116  switch(mode_mask) {
117    case SPI_MODE_0:
118      *csr |= SPI_CSR_NCPHA;
119      break;
120    case SPI_MODE_1:
121      break;
122    case SPI_MODE_2:
123      *csr |= SPI_CSR_NCPHA;
124      *csr |= SPI_CSR_CPOL;
125      break;
126    case SPI_MODE_3:
127      *csr |= SPI_CSR_CPOL;
128      break;
129  }
130  *csr |= SPI_CSR_CSAAT;
131}
132
133static void atsam_configure_spi(atsam_spi_bus *bus)
134{
135  uint32_t scbr;
136  uint32_t csr = 0;
137  uint32_t mr;
138  uint32_t cs = bus->base.cs;
139
140  scbr = atsam_calculate_scbr(bus->base.speed_hz);
141
142  mr = bus->spi_mr;
143
144  if (bus->chip_select_decode) {
145    mr |= SPI_MR_PCS(bus->base.cs);
146    mr |= SPI_MR_PCSDEC;
147    cs /= 4;
148  } else {
149    mr |= SPI_PCS(bus->base.cs);
150  }
151
152  bus->spi_regs->SPI_MR = mr;
153
154  csr = bus->spi_csr[cs]
155    | SPI_CSR_SCBR(scbr)
156    | SPI_CSR_BITS(bus->base.bits_per_word - 8);
157
158  atsam_set_phase_and_polarity(bus->base.mode, &csr);
159
160  SPI_ConfigureNPCS(bus->spi_regs, cs, csr);
161}
162
163static void atsam_reset_spi(atsam_spi_bus *bus)
164{
165  bus->spi_regs->SPI_CR = SPI_CR_SPIDIS;
166  bus->spi_regs->SPI_CR = SPI_CR_SWRST;
167  bus->spi_regs->SPI_CR = SPI_CR_SWRST;
168  bus->spi_regs->SPI_CR = SPI_CR_SPIEN;
169}
170
171static void atsam_spi_check_alignment_and_set_up_dma_descriptors(
172  atsam_spi_bus *bus,
173  struct atsam_spi_xdma_buf *buf,
174  const uint8_t *start,
175  size_t len,
176  bool tx
177)
178{
179  LinkedListDescriporView0 *curdesc = buf->desc;
180  size_t misaligned_begin;
181  size_t misaligned_end;
182  size_t len_main;
183  const uint8_t *start_main;
184  const uint8_t *start_trail;
185
186  /* Check alignments. */
187  if (len < CPU_CACHE_LINE_BYTES) {
188    misaligned_begin = len;
189    misaligned_end = 0;
190    len_main = 0;
191  } else {
192    misaligned_begin = ((uint32_t) start) % CPU_CACHE_LINE_BYTES;
193    misaligned_end = (((uint32_t) start) + len) % CPU_CACHE_LINE_BYTES;
194    len_main = len - misaligned_begin - misaligned_end;
195  }
196  start_main = start + misaligned_begin;
197  start_trail = start_main + len_main;
198
199  /* Store length for copying data back. */
200  if (!tx) {
201    bus->leadbuf_rx_buffered_len = misaligned_begin;
202    bus->trailbuf_rx_buffered_len = misaligned_end;
203  }
204
205  /* Handle misalignment on begin. */
206  if (misaligned_begin != 0) {
207    if (tx) {
208      atsam_copy_to_io(buf->leadbuf, start, misaligned_begin);
209    }
210    curdesc->mbr_nda = (uint32_t) (&curdesc[1]);
211    curdesc->mbr_ta = (uint32_t) buf->leadbuf;
212    curdesc->mbr_ubc = misaligned_begin;
213  }
214
215  /* Main part */
216  if (len_main > 0) {
217    curdesc->mbr_ubc |= tx ? XDMA_UBC_NSEN_UPDATED : XDMA_UBC_NDEN_UPDATED;
218    curdesc->mbr_ubc |= XDMA_UBC_NVIEW_NDV0;
219    curdesc->mbr_ubc |= XDMA_UBC_NDE_FETCH_EN;
220    ++curdesc;
221
222    curdesc->mbr_nda = (uint32_t) (&curdesc[1]);
223    curdesc->mbr_ta = (uint32_t) start_main;
224    curdesc->mbr_ubc = len_main;
225    if (tx) {
226      rtems_cache_flush_multiple_data_lines(start_main, len_main);
227    } else {
228      rtems_cache_invalidate_multiple_data_lines(start_main, len_main);
229    }
230  }
231
232  /* Handle misalignment on end */
233  if (misaligned_end != 0) {
234    curdesc->mbr_ubc |= tx ? XDMA_UBC_NSEN_UPDATED : XDMA_UBC_NDEN_UPDATED;
235    curdesc->mbr_ubc |= XDMA_UBC_NVIEW_NDV0;
236    curdesc->mbr_ubc |= XDMA_UBC_NDE_FETCH_EN;
237    ++curdesc;
238
239    if (tx) {
240      atsam_copy_to_io(buf->trailbuf, start_trail, misaligned_end);
241    }
242    curdesc->mbr_nda = 0;
243    curdesc->mbr_ta = (uint32_t) buf->trailbuf;
244    curdesc->mbr_ubc = misaligned_end;
245    curdesc->mbr_ubc |= XDMA_UBC_NDE_FETCH_DIS;
246  }
247}
248
249static void atsam_spi_copy_back_rx_after_dma_transfer(
250  atsam_spi_bus *bus
251)
252{
253  if (bus->leadbuf_rx_buffered_len != 0) {
254    atsam_copy_from_io(
255      bus->msg_current->rx_buf,
256      bus->dma_bufs[DMA_BUF_RX].leadbuf,
257      bus->leadbuf_rx_buffered_len
258    );
259  }
260  if (bus->trailbuf_rx_buffered_len != 0) {
261    atsam_copy_from_io(
262      bus->msg_current->rx_buf + bus->msg_current->len -
263        bus->trailbuf_rx_buffered_len,
264      bus->dma_bufs[DMA_BUF_RX].trailbuf,
265      bus->trailbuf_rx_buffered_len
266    );
267  }
268}
269
270static void atsam_spi_start_dma_transfer(
271  atsam_spi_bus *bus,
272  const spi_ioc_transfer *msg
273)
274{
275  Xdmac *pXdmac = XDMAC;
276
277  atsam_spi_check_alignment_and_set_up_dma_descriptors(
278    bus,
279    &bus->dma_bufs[DMA_BUF_RX],
280    msg->rx_buf,
281    msg->len,
282    false
283  );
284  atsam_spi_check_alignment_and_set_up_dma_descriptors(
285    bus,
286    &bus->dma_bufs[DMA_BUF_TX],
287    msg->tx_buf,
288    msg->len,
289    true
290  );
291
292  XDMAC_SetDescriptorAddr(
293    pXdmac,
294    bus->dma_rx_channel,
295    (uint32_t) bus->dma_bufs[DMA_BUF_RX].desc,
296    0
297  );
298  XDMAC_SetDescriptorControl(
299    pXdmac,
300    bus->dma_rx_channel,
301    XDMAC_CNDC_NDVIEW_NDV0 |
302    XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
303    XDMAC_CNDC_NDE_DSCR_FETCH_EN
304  );
305  XDMAC_SetDescriptorAddr(
306    pXdmac,
307    bus->dma_tx_channel,
308    (uint32_t) bus->dma_bufs[DMA_BUF_TX].desc,
309    0
310  );
311  XDMAC_SetDescriptorControl(
312    pXdmac,
313    bus->dma_tx_channel,
314    XDMAC_CNDC_NDVIEW_NDV0 |
315    XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |
316    XDMAC_CNDC_NDE_DSCR_FETCH_EN
317  );
318
319  XDMAC_StartTransfer(pXdmac, bus->dma_rx_channel);
320  XDMAC_StartTransfer(pXdmac, bus->dma_tx_channel);
321}
322
323static void atsam_spi_do_transfer(
324  atsam_spi_bus *bus,
325  const spi_ioc_transfer *msg
326)
327{
328  if (!bus->chip_select_active){
329    Spi *spi_regs = bus->spi_regs;
330
331    bus->chip_select_active = true;
332
333    if (bus->chip_select_decode) {
334      spi_regs->SPI_MR = (spi_regs->SPI_MR & ~SPI_MR_PCS_Msk) | SPI_MR_PCS(msg->cs);
335    } else {
336      SPI_ChipSelect(spi_regs, 1 << msg->cs);
337    }
338    SPI_Enable(spi_regs);
339  }
340
341  atsam_spi_start_dma_transfer(bus, msg);
342}
343
344static int atsam_check_configure_spi(atsam_spi_bus *bus, const spi_ioc_transfer *msg)
345{
346  if (
347    msg->mode != bus->base.mode
348      || msg->speed_hz != bus->base.speed_hz
349      || msg->bits_per_word != bus->base.bits_per_word
350      || msg->cs != bus->base.cs
351  ) {
352    if (
353      msg->bits_per_word < 8
354        || msg->bits_per_word > 16
355        || msg->mode > 3
356        || msg->speed_hz > bus->base.max_speed_hz
357    ) {
358      return -EINVAL;
359    }
360
361    bus->base.mode = msg->mode;
362    bus->base.speed_hz = msg->speed_hz;
363    bus->base.bits_per_word = msg->bits_per_word;
364    bus->base.cs = msg->cs;
365    atsam_configure_spi(bus);
366  }
367
368  return 0;
369}
370
371static void atsam_spi_setup_transfer(atsam_spi_bus *bus)
372{
373  uint32_t msg_todo = bus->msg_todo;
374
375  bus->transfer_in_progress = 2;
376
377  if (bus->msg_cs_change) {
378    bus->chip_select_active = false;
379    SPI_ReleaseCS(bus->spi_regs);
380    SPI_Disable(bus->spi_regs);
381  }
382
383  if (msg_todo > 0) {
384    const spi_ioc_transfer *msg = bus->msg_next;
385    int error;
386
387    bus->msg_cs_change = msg->cs_change;
388    bus->msg_next = msg + 1;
389    bus->msg_current = msg;
390    bus->msg_todo = msg_todo - 1;
391
392    error = atsam_check_configure_spi(bus, msg);
393    if (error == 0) {
394      atsam_spi_do_transfer(bus, msg);
395    } else {
396      bus->msg_error = error;
397      atsam_spi_wakeup_task(bus);
398    }
399  } else {
400    atsam_spi_wakeup_task(bus);
401  }
402}
403
404static void atsam_spi_dma_callback(uint32_t channel, void *arg)
405{
406  atsam_spi_bus *bus = (atsam_spi_bus *)arg;
407
408  --bus->transfer_in_progress;
409
410  if (bus->transfer_in_progress == 0) {
411    const spi_ioc_transfer *msg = bus->msg_current;
412
413    if (msg->delay_usecs != bus->base.delay_usecs) {
414      uint32_t mr;
415      uint32_t mr_dlybcs;
416
417      bus->base.delay_usecs = msg->delay_usecs;
418      mr_dlybcs = SPI_MR_DLYBCS(atsam_calculate_dlybcs(bus));
419      bus->spi_mr = mr_dlybcs | SPI_MR_MSTR | SPI_MR_MODFDIS;
420
421      mr = bus->spi_regs->SPI_MR;
422      mr &= ~SPI_MR_DLYBCS_Msk;
423      mr |= mr_dlybcs;
424      bus->spi_regs->SPI_MR = mr;
425    }
426
427    atsam_spi_copy_back_rx_after_dma_transfer(bus);
428    atsam_spi_setup_transfer(bus);
429  }
430}
431
432static int atsam_spi_transfer(
433  spi_bus *base,
434  const spi_ioc_transfer *msgs,
435  uint32_t msg_count
436)
437{
438  atsam_spi_bus *bus = (atsam_spi_bus *)base;
439
440  bus->msg_cs_change = false;
441  bus->msg_next = &msgs[0];
442  bus->msg_current = NULL;
443  bus->msg_todo = msg_count;
444  bus->msg_error = 0;
445  atsam_spi_setup_transfer(bus);
446  rtems_binary_semaphore_wait(&bus->sem);
447  return bus->msg_error;
448}
449
450
451static void atsam_spi_destroy(spi_bus *base)
452{
453  atsam_spi_bus *bus = (atsam_spi_bus *)base;
454  eXdmadRC rc;
455
456  rc = XDMAD_SetCallback(
457    &XDMAD_Instance,
458    bus->dma_rx_channel,
459    XDMAD_DoNothingCallback,
460    NULL
461  );
462  assert(rc == XDMAD_OK);
463
464  rc = XDMAD_SetCallback(
465    &XDMAD_Instance,
466    bus->dma_tx_channel,
467    XDMAD_DoNothingCallback,
468    NULL
469  );
470  assert(rc == XDMAD_OK);
471
472  XDMAD_FreeChannel(&XDMAD_Instance, bus->dma_rx_channel);
473  XDMAD_FreeChannel(&XDMAD_Instance, bus->dma_tx_channel);
474
475  SPI_Disable(bus->spi_regs);
476  PMC_DisablePeripheral(bus->spi_id);
477
478  rtems_cache_coherent_free(bus->dma_bufs);
479
480  spi_bus_destroy_and_free(&bus->base);
481  rtems_binary_semaphore_destroy(&bus->sem);
482}
483
484static int atsam_spi_setup(spi_bus *base)
485{
486  atsam_spi_bus *bus = (atsam_spi_bus *)base;
487
488  if (
489    bus->base.speed_hz > MAX_SPI_FREQUENCY ||
490    bus->base.bits_per_word < 8 ||
491    bus->base.bits_per_word > 16
492  ) {
493      return -EINVAL;
494  }
495  atsam_configure_spi(bus);
496  return 0;
497}
498
499static void atsam_spi_init_xdma(atsam_spi_bus *bus)
500{
501  sXdmadCfg cfg;
502  uint32_t xdmaInt;
503  uint8_t channel;
504  eXdmadRC rc;
505  uint32_t xdma_cndc;
506
507  bus->dma_bufs = rtems_cache_coherent_allocate(
508    DMA_BUF_DIRS * sizeof(*(bus->dma_bufs)),
509    DMA_DESC_ALLIGNMENT,
510    0
511  );
512  assert(bus->dma_bufs != NULL);
513
514  bus->dma_tx_channel = XDMAD_AllocateChannel(
515    &XDMAD_Instance,
516    XDMAD_TRANSFER_MEMORY,
517    bus->spi_id
518  );
519  assert(bus->dma_tx_channel != XDMAD_ALLOC_FAILED);
520
521  bus->dma_rx_channel = XDMAD_AllocateChannel(
522    &XDMAD_Instance,
523    bus->spi_id,
524    XDMAD_TRANSFER_MEMORY
525  );
526  assert(bus->dma_rx_channel != XDMAD_ALLOC_FAILED);
527
528  rc = XDMAD_SetCallback(
529    &XDMAD_Instance,
530    bus->dma_rx_channel,
531    atsam_spi_dma_callback,
532    bus
533  );
534  assert(rc == XDMAD_OK);
535
536  rc = XDMAD_SetCallback(
537    &XDMAD_Instance,
538    bus->dma_tx_channel,
539    atsam_spi_dma_callback,
540    bus
541  );
542  assert(rc == XDMAD_OK);
543
544  rc = XDMAD_PrepareChannel(&XDMAD_Instance, bus->dma_rx_channel);
545  assert(rc == XDMAD_OK);
546
547  rc = XDMAD_PrepareChannel(&XDMAD_Instance, bus->dma_tx_channel);
548  assert(rc == XDMAD_OK);
549
550  /* Put all relevant interrupts on */
551  xdmaInt =  (
552    XDMAC_CIE_BIE |
553    XDMAC_CIE_DIE |
554    XDMAC_CIE_FIE |
555    XDMAC_CIE_RBIE |
556    XDMAC_CIE_WBIE |
557    XDMAC_CIE_ROIE);
558
559  /* Setup RX */
560  memset(&cfg, 0, sizeof(cfg));
561  channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_RX);
562  cfg.mbr_sa = (uint32_t)&bus->spi_regs->SPI_RDR;
563  cfg.mbr_cfg =
564    XDMAC_CC_TYPE_PER_TRAN |
565    XDMAC_CC_MBSIZE_SINGLE |
566    XDMAC_CC_DSYNC_PER2MEM |
567    XDMAC_CC_CSIZE_CHK_1 |
568    XDMAC_CC_DWIDTH_BYTE |
569    XDMAC_CC_SIF_AHB_IF1 |
570    XDMAC_CC_DIF_AHB_IF1 |
571    XDMAC_CC_SAM_FIXED_AM |
572    XDMAC_CC_DAM_INCREMENTED_AM |
573    XDMAC_CC_PERID(channel);
574  xdma_cndc = XDMAC_CNDC_NDVIEW_NDV0 |
575    XDMAC_CNDC_NDE_DSCR_FETCH_EN |
576    XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
577    XDMAC_CNDC_NDSUP_SRC_PARAMS_UNCHANGED;
578  rc = XDMAD_ConfigureTransfer(
579    &XDMAD_Instance,
580    bus->dma_rx_channel,
581    &cfg,
582    xdma_cndc,
583    (uint32_t) bus->dma_bufs[DMA_BUF_RX].desc,
584    xdmaInt
585  );
586  assert(rc == XDMAD_OK);
587
588  /* Setup TX  */
589  memset(&cfg, 0, sizeof(cfg));
590  channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_TX);
591  cfg.mbr_da = (uint32_t)&bus->spi_regs->SPI_TDR;
592  cfg.mbr_cfg =
593    XDMAC_CC_TYPE_PER_TRAN |
594    XDMAC_CC_MBSIZE_SINGLE |
595    XDMAC_CC_DSYNC_MEM2PER |
596    XDMAC_CC_CSIZE_CHK_1 |
597    XDMAC_CC_DWIDTH_BYTE |
598    XDMAC_CC_SIF_AHB_IF1 |
599    XDMAC_CC_DIF_AHB_IF1 |
600    XDMAC_CC_SAM_INCREMENTED_AM |
601    XDMAC_CC_DAM_FIXED_AM |
602    XDMAC_CC_PERID(channel);
603  xdma_cndc = XDMAC_CNDC_NDVIEW_NDV0 |
604    XDMAC_CNDC_NDE_DSCR_FETCH_EN |
605    XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED |
606    XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED;
607  rc = XDMAD_ConfigureTransfer(
608    &XDMAD_Instance,
609    bus->dma_tx_channel,
610    &cfg,
611    xdma_cndc,
612    (uint32_t) bus->dma_bufs[DMA_BUF_TX].desc,
613    xdmaInt
614  );
615  assert(rc == XDMAD_OK);
616}
617
618int spi_bus_register_atsam(
619  const char *bus_path,
620  const atsam_spi_config *config
621)
622{
623  atsam_spi_bus *bus;
624  size_t i;
625
626  bus = (atsam_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
627  if (bus == NULL) {
628    return -1;
629  }
630
631  bus->base.transfer = atsam_spi_transfer;
632  bus->base.destroy = atsam_spi_destroy;
633  bus->base.setup = atsam_spi_setup;
634  bus->base.max_speed_hz = MAX_SPI_FREQUENCY;
635  bus->base.bits_per_word = 8;
636  bus->base.speed_hz = bus->base.max_speed_hz;
637  bus->base.cs = 1;
638  bus->spi_id = config->spi_peripheral_id;
639  bus->spi_regs = config->spi_regs;
640  bus->chip_select_decode = config->chip_select_decode;
641  bus->peripheral_clk_per_us = BOARD_MCK / 1000000;
642  bus->spi_mr = SPI_MR_MSTR | SPI_MR_MODFDIS;
643
644  for (i = 0; i < RTEMS_ARRAY_SIZE(bus->spi_csr); ++i) {
645    if (config->dlybs_in_ns[i] != 0) {
646      bus->spi_csr[i] |= SPI_DLYBS(config->dlybs_in_ns[i], BOARD_MCK);
647    }
648
649    if (config->dlybct_in_ns[i] != 0) {
650      bus->spi_csr[i] |= SPI_DLYBCT(config->dlybct_in_ns[i], BOARD_MCK);
651    }
652  }
653
654  rtems_binary_semaphore_init(&bus->sem, "ATSAM SPI");
655  PIO_Configure(config->pins, config->pin_count);
656  PMC_EnablePeripheral(config->spi_peripheral_id);
657  atsam_reset_spi(bus);
658  atsam_configure_spi(bus);
659  atsam_spi_init_xdma(bus);
660
661  return spi_bus_register(&bus->base, bus_path);
662}
Note: See TracBrowser for help on using the repository browser.