source: rtems/c/src/lib/libbsp/arm/lpc24xx/ssp/ssp.c @ 0e27119

4.115
Last change on this file since 0e27119 was 0e27119, checked in by Joel Sherrill <joel.sherrill@…>, on 10/11/12 at 20:52:18

Use proper 3 line form of license text

  • Property mode set to 100644
File size: 15.8 KB
RevLine 
[29cc1477]1/**
2 * @file
3 *
[ba938b8d]4 * @ingroup lpc24xx_libi2c
[29cc1477]5 *
6 * @brief LibI2C bus driver for the Synchronous Serial Port (SSP).
7 */
8
9/*
10 * Copyright (c) 2008
11 * Embedded Brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * rtems@embedded-brains.de
16 *
[0e27119]17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
[29cc1477]20 */
21
22#include <stdbool.h>
23
24#include <bsp/ssp.h>
25#include <bsp/lpc24xx.h>
26#include <bsp/irq.h>
27#include <bsp/system-clocks.h>
28#include <bsp/dma.h>
[4a6cc2a]29#include <bsp/io.h>
[29cc1477]30
31#define RTEMS_STATUS_CHECKS_USE_PRINTK
32
33#include <rtems/status-checks.h>
34
35#define LPC24XX_SSP_NUMBER 2
36
37#define LPC24XX_SSP_FIFO_SIZE 8
38
39#define LPC24XX_SSP_BAUD_RATE 2000000
40
41typedef enum {
42  LPC24XX_SSP_DMA_INVALID = 0,
43  LPC24XX_SSP_DMA_AVAILABLE = 1,
44  LPC24XX_SSP_DMA_NOT_INITIALIZED = 2,
45  LPC24XX_SSP_DMA_INITIALIZATION = 3,
46  LPC24XX_SSP_DMA_TRANSFER_FLAG = 0x80000000U,
47  LPC24XX_SSP_DMA_WAIT = 1 | LPC24XX_SSP_DMA_TRANSFER_FLAG,
48  LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0 = 2 | LPC24XX_SSP_DMA_TRANSFER_FLAG,
49  LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1 = 3 | LPC24XX_SSP_DMA_TRANSFER_FLAG,
50  LPC24XX_SSP_DMA_ERROR = 4 | LPC24XX_SSP_DMA_TRANSFER_FLAG,
51  LPC24XX_SSP_DMA_DONE = 5 | LPC24XX_SSP_DMA_TRANSFER_FLAG
52} lpc24xx_ssp_dma_status;
53
54typedef struct {
55  rtems_libi2c_bus_t bus;
56  volatile lpc24xx_ssp *regs;
57  unsigned clock;
58  uint32_t idle_char;
59} lpc24xx_ssp_bus_entry;
60
61typedef struct {
62  lpc24xx_ssp_dma_status status;
63  lpc24xx_ssp_bus_entry *bus;
64  rtems_libi2c_read_write_done_t done;
65  int n;
66  void *arg;
67} lpc24xx_ssp_dma_entry;
68
69static lpc24xx_ssp_dma_entry lpc24xx_ssp_dma_data = {
70  .status = LPC24XX_SSP_DMA_NOT_INITIALIZED,
71  .bus = NULL,
72  .done = NULL,
73  .n = 0,
74  .arg = NULL
75};
76
77static uint32_t lpc24xx_ssp_trash = 0;
78
[ba938b8d]79static inline bool lpc24xx_ssp_is_busy(const lpc24xx_ssp_bus_entry *bus)
[29cc1477]80{
81  return lpc24xx_ssp_dma_data.bus == bus
82    && lpc24xx_ssp_dma_data.status != LPC24XX_SSP_DMA_AVAILABLE;
83}
84
[60e5832]85static void lpc24xx_ssp_handler(void *arg)
[29cc1477]86{
87  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) arg;
88  volatile lpc24xx_ssp *regs = e->regs;
89  uint32_t mis = regs->mis;
90  uint32_t icr = 0;
91
[edf846e4]92  if ((mis & SSP_MIS_RORRIS) != 0) {
[29cc1477]93    /* TODO */
[ba938b8d]94    printk("%s: Receiver overrun!\n", __func__);
[29cc1477]95    icr |= SSP_ICR_RORRIS;
96  }
97
98  regs->icr = icr;
99}
100
[60e5832]101static void lpc24xx_ssp_dma_handler(void *arg)
[29cc1477]102{
103  lpc24xx_ssp_dma_entry *e = (lpc24xx_ssp_dma_entry *) arg;
104  lpc24xx_ssp_dma_status status = e->status;
105  uint32_t tc = 0;
106  uint32_t err = 0;
107  int rv = 0;
108
109  /* Return if we are not in a transfer status */
[edf846e4]110  if ((status & LPC24XX_SSP_DMA_TRANSFER_FLAG) == 0) {
[29cc1477]111    return;
112  }
113
114  /* Get interrupt status */
115  tc = GPDMA_INT_TCSTAT;
116  err = GPDMA_INT_ERR_STAT;
117
118  /* Clear interrupt status */
119  GPDMA_INT_TCCLR = tc;
120  GPDMA_INT_ERR_CLR = err;
121
122  /* Change status */
123  if (err == 0) {
124    switch (status) {
125      case LPC24XX_SSP_DMA_WAIT:
[edf846e4]126        if ((tc & (GPDMA_STATUS_CH_0 | GPDMA_STATUS_CH_1)) != 0) {
[29cc1477]127          status = LPC24XX_SSP_DMA_DONE;
[edf846e4]128        } else if ((tc & GPDMA_STATUS_CH_0) != 0) {
[29cc1477]129          status = LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1;
[edf846e4]130        } else if ((tc & GPDMA_STATUS_CH_1) != 0) {
[29cc1477]131          status = LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0;
132        }
133        break;
134      case LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0:
[edf846e4]135        if ((tc & GPDMA_STATUS_CH_1) != 0) {
[29cc1477]136          status = LPC24XX_SSP_DMA_ERROR;
[edf846e4]137        } else if ((tc & GPDMA_STATUS_CH_0) != 0) {
[29cc1477]138          status = LPC24XX_SSP_DMA_DONE;
139        }
140        break;
141      case LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1:
[edf846e4]142        if ((tc & GPDMA_STATUS_CH_0) != 0) {
[29cc1477]143          status = LPC24XX_SSP_DMA_ERROR;
[edf846e4]144        } else if ((tc & GPDMA_STATUS_CH_1) != 0) {
[29cc1477]145          status = LPC24XX_SSP_DMA_DONE;
146        }
147        break;
148      default:
149        status = LPC24XX_SSP_DMA_ERROR;
150        break;
151    }
152  } else {
153    status = LPC24XX_SSP_DMA_ERROR;
154  }
155
156  /* Error cleanup */
157  if (status == LPC24XX_SSP_DMA_ERROR) {
[ba938b8d]158    lpc24xx_dma_channel_disable(0, true);
159    lpc24xx_dma_channel_disable(1, true);
[29cc1477]160    status = LPC24XX_SSP_DMA_DONE;
161    rv = -RTEMS_IO_ERROR;
162  }
163
164  /* Done */
165  if (status == LPC24XX_SSP_DMA_DONE) {
166    status = LPC24XX_SSP_DMA_AVAILABLE;
167    if (e->done != NULL) {
[ba938b8d]168      e->done(rv, e->n, e->arg);
[29cc1477]169      e->done = NULL;
170    }
171  }
172
173  /* Set status */
174  e->status = status;
175}
176
[ba938b8d]177static rtems_status_code lpc24xx_ssp_init(rtems_libi2c_bus_t *bus)
[29cc1477]178{
179  rtems_status_code sc = RTEMS_SUCCESSFUL;
180  rtems_interrupt_level level;
181  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus;
182  volatile lpc24xx_ssp *regs = e->regs;
183  unsigned pclk = lpc24xx_cclk();
184  unsigned pre =
185    ((pclk + LPC24XX_SSP_BAUD_RATE - 1) / LPC24XX_SSP_BAUD_RATE + 1) & ~1U;
[4a6cc2a]186  lpc24xx_module module = LPC24XX_MODULE_SSP_0;
[29cc1477]187  rtems_vector_number vector = UINT32_MAX;
188
189  if (lpc24xx_ssp_dma_data.status == LPC24XX_SSP_DMA_NOT_INITIALIZED) {
190    lpc24xx_ssp_dma_status status = LPC24XX_SSP_DMA_INVALID;
191
192    /* Test and set DMA support status */
[ba938b8d]193    rtems_interrupt_disable(level);
[29cc1477]194    status = lpc24xx_ssp_dma_data.status;
195    if (status == LPC24XX_SSP_DMA_NOT_INITIALIZED) {
196      lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_INITIALIZATION;
197    }
[ba938b8d]198    rtems_interrupt_enable(level);
[29cc1477]199
200    if (status == LPC24XX_SSP_DMA_NOT_INITIALIZED) {
201      /* Install DMA interrupt handler */
202      sc = rtems_interrupt_handler_install(
203        LPC24XX_IRQ_DMA,
204        "SSP DMA",
205        RTEMS_INTERRUPT_SHARED,
206        lpc24xx_ssp_dma_handler,
207        &lpc24xx_ssp_dma_data
208      );
[ba938b8d]209      RTEMS_CHECK_SC(sc, "install DMA interrupt handler");
[29cc1477]210
211      /* Set DMA support status */
212      lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_AVAILABLE;
213    }
214  }
215
216  /* Disable module */
217  regs->cr1 = 0;
218
219  switch ((uintptr_t) regs) {
220    case SSP0_BASE_ADDR:
[4a6cc2a]221      module = LPC24XX_MODULE_SSP_0;
[29cc1477]222      vector = LPC24XX_IRQ_SPI_SSP_0;
223      break;
224    case SSP1_BASE_ADDR:
[4a6cc2a]225      module = LPC24XX_MODULE_SSP_1;
[29cc1477]226      vector = LPC24XX_IRQ_SSP_1;
227      break;
228    default:
229      return RTEMS_IO_ERROR;
230  }
231
[4a6cc2a]232  /* Set clock select */
233  sc = lpc24xx_module_enable(module, LPC24XX_MODULE_PCLK_DEFAULT);
234  RTEMS_CHECK_SC(sc, "enable module clock");
235
[29cc1477]236  /* Set serial clock rate to save value */
[ba938b8d]237  regs->cr0 = SET_SSP_CR0_SCR(0, 255);
[29cc1477]238
239  /* Set clock prescaler */
240  if (pre > 254) {
241    pre = 254;
242  } else if (pre < 2) {
243    pre = 2;
244  }
245  regs->cpsr = pre;
246
247  /* Save clock value */
248  e->clock = pclk / pre;
249
250  /* Enable module and loop back mode */
251  regs->cr1 = SSP_CR1_LBM | SSP_CR1_SSE;
252
253  /* Install interrupt handler */
254  sc = rtems_interrupt_handler_install(
255    vector,
256    "SSP",
257    RTEMS_INTERRUPT_UNIQUE,
258    lpc24xx_ssp_handler,
259    e
260  );
[ba938b8d]261  RTEMS_CHECK_SC(sc, "install interrupt handler");
[29cc1477]262
263  /* Enable receiver overrun interrupts */
264  e->regs->imsc = SSP_IMSC_RORIM;
265
266  return RTEMS_SUCCESSFUL;
267}
268
[ba938b8d]269static rtems_status_code lpc24xx_ssp_send_start(rtems_libi2c_bus_t *bus)
[29cc1477]270{
271  return RTEMS_SUCCESSFUL;
272}
273
[ba938b8d]274static rtems_status_code lpc24xx_ssp_send_stop(rtems_libi2c_bus_t *bus)
[29cc1477]275{
276  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus;
277
278  /* Release DMA support */
279  if (lpc24xx_ssp_dma_data.bus == e) {
280    if (lpc24xx_ssp_dma_data.status == LPC24XX_SSP_DMA_AVAILABLE) {
[ba938b8d]281      lpc24xx_dma_channel_release(0);
282      lpc24xx_dma_channel_release(1);
[29cc1477]283      lpc24xx_ssp_dma_data.bus = NULL;
284    } else {
285      return RTEMS_RESOURCE_IN_USE;
286    }
287  }
288
289  return RTEMS_SUCCESSFUL;
290}
291
292static rtems_status_code lpc24xx_ssp_send_addr(
293  rtems_libi2c_bus_t *bus,
294  uint32_t addr,
295  int rw
296)
297{
298  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus;
299
[ba938b8d]300  if (lpc24xx_ssp_is_busy(e)) {
[29cc1477]301    return RTEMS_RESOURCE_IN_USE;
302  }
303
304  return RTEMS_SUCCESSFUL;
305}
306
307static int lpc24xx_ssp_set_transfer_mode(
308  rtems_libi2c_bus_t *bus,
309  const rtems_libi2c_tfr_mode_t *mode
310)
311{
312  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus;
313  volatile lpc24xx_ssp *regs = e->regs;
314  unsigned clk = e->clock;
315  unsigned br = mode->baudrate;
316  unsigned scr = (clk + br - 1) / br;
317
[ba938b8d]318  if (lpc24xx_ssp_is_busy(e)) {
[29cc1477]319    return -RTEMS_RESOURCE_IN_USE;
320  }
321
322  if (mode->bits_per_char != 8) {
323    return -RTEMS_INVALID_NUMBER;
324  }
325
326  if (mode->lsb_first) {
327    return -RTEMS_INVALID_NUMBER;
328  }
329
330  if (br == 0) {
331    return -RTEMS_INVALID_NUMBER;
332  }
333
334  /* Compute new prescaler if necessary */
335  if (scr > 256 || scr < 1) {
336    unsigned pre = regs->cpsr;
337    unsigned pclk = clk * pre;
338
339    while (scr > 256) {
340      if (pre > 252) {
341        return -RTEMS_INVALID_NUMBER;
342      }
343      pre += 2;
344      clk = pclk / pre;
345      scr = (clk + br - 1) / br;
346    }
347
348    while (scr < 1) {
349      if (pre < 4) {
350        return -RTEMS_INVALID_NUMBER;
351      }
352      pre -= 2;
353      clk = pclk / pre;
354      scr = (clk + br - 1) / br;
355    }
356
357    regs->cpsr = pre;
358    e->clock = clk;
359  }
360
361  /* Adjust SCR */
362  --scr;
363
364  e->idle_char = mode->idle_char;
365
[edf846e4]366  while ((regs->sr & SSP_SR_TFE) == 0) {
[29cc1477]367    /* Wait */
368  }
369
[ba938b8d]370  regs->cr0 = SET_SSP_CR0_DSS(0, 0x7)
371    | SET_SSP_CR0_SCR(0, scr)
[29cc1477]372    | (mode->clock_inv ? SSP_CR0_CPOL : 0)
373    | (mode->clock_phs ? SSP_CR0_CPHA : 0);
374
375  return 0;
376}
377
378static int lpc24xx_ssp_read_write(
379  rtems_libi2c_bus_t *bus,
380  unsigned char *in,
381  const unsigned char *out,
382  int n
383)
384{
385  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus;
386  volatile lpc24xx_ssp *regs = e->regs;
387  int r = 0;
388  int w = 0;
389  int dr = 1;
390  int dw = 1;
391  int m = 0;
392  uint32_t sr = regs->sr;
393  unsigned char trash = 0;
394  unsigned char idle_char = (unsigned char) e->idle_char;
395
[ba938b8d]396  if (lpc24xx_ssp_is_busy(e)) {
[29cc1477]397    return -RTEMS_RESOURCE_IN_USE;
398  }
399
400  if (n < 0) {
401    return -RTEMS_INVALID_SIZE;
402  }
403
404  /* Disable DMA on SSP */
[9647f7fe]405  regs->dmacr = 0;
[29cc1477]406
407  if (in == NULL) {
408    dr = 0;
409    in = &trash;
410  }
411
412  if (out == NULL) {
413    dw = 0;
414    out = &idle_char;
415  }
416
417  /*
418   * Assumption: The transmit and receive FIFOs are empty.  If this assumption
419   * is not true an input buffer overflow may occur or we may never exit the
420   * loop due to data loss.  This is only possible if entities external to this
421   * driver operate on the SSP.
422   */
423
424  while (w < n) {
425    /* FIFO capacity */
426    m = w - r;
427
428    /* Write */
[edf846e4]429    if ((sr & SSP_SR_TNF) != 0 && m < LPC24XX_SSP_FIFO_SIZE) {
[29cc1477]430      regs->dr = *out;
431      ++w;
432      out += dw;
433    }
434
435    /* Read */
[edf846e4]436    if ((sr & SSP_SR_RNE) != 0) {
[29cc1477]437      *in = (unsigned char) regs->dr;
438      ++r;
439      in += dr;
440    }
441
442    /* New status */
443    sr = regs->sr;
444  }
445
446  /* Read outstanding input */
447  while (r < n) {
448    /* Wait */
449    do {
450      sr = regs->sr;
[edf846e4]451    } while ((sr & SSP_SR_RNE) == 0);
[29cc1477]452
453    /* Read */
454    *in = (unsigned char) regs->dr;
455    ++r;
456    in += dr;
457  }
458
459  return n;
460}
461
462static int lpc24xx_ssp_read_write_async(
463  rtems_libi2c_bus_t *bus,
464  unsigned char *in,
465  const unsigned char *out,
466  int n,
467  rtems_libi2c_read_write_done_t done,
468  void *arg
469)
470{
471  rtems_interrupt_level level;
472  lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus;
473  volatile lpc24xx_ssp *ssp = e->regs;
[ba938b8d]474  volatile lpc24xx_dma_channel *receive_channel = GPDMA_CH_BASE_ADDR(0);
475  volatile lpc24xx_dma_channel *transmit_channel = GPDMA_CH_BASE_ADDR(1);
[29cc1477]476  uint32_t di = GPDMA_CH_CTRL_DI;
477  uint32_t si = GPDMA_CH_CTRL_SI;
478
479  if (n < 0 || n > (int) GPDMA_CH_CTRL_TSZ_MAX) {
480    return -RTEMS_INVALID_SIZE;
481  }
482
483  /* Try to reserve DMA support for this bus */
484  if (lpc24xx_ssp_dma_data.bus == NULL) {
[ba938b8d]485    rtems_interrupt_disable(level);
[29cc1477]486    if (lpc24xx_ssp_dma_data.bus == NULL) {
487      lpc24xx_ssp_dma_data.bus = e;
488    }
[ba938b8d]489    rtems_interrupt_enable(level);
[29cc1477]490
491    /* Try to obtain DMA channels */
492    if (lpc24xx_ssp_dma_data.bus == e) {
[ba938b8d]493      rtems_status_code cs0 = lpc24xx_dma_channel_obtain(0);
494      rtems_status_code cs1 = lpc24xx_dma_channel_obtain(1);
[29cc1477]495
[ba938b8d]496      if (cs0 != RTEMS_SUCCESSFUL || cs1 != RTEMS_SUCCESSFUL) {
497        if (cs0 == RTEMS_SUCCESSFUL) {
498          lpc24xx_dma_channel_release(0);
499        }
500        if (cs1 == RTEMS_SUCCESSFUL) {
501          lpc24xx_dma_channel_release(1);
502        }
[29cc1477]503        lpc24xx_ssp_dma_data.bus = NULL;
504      }
505    }
506  }
507
508  /* Check if DMA support is available */
509  if (lpc24xx_ssp_dma_data.bus != e
510    || lpc24xx_ssp_dma_data.status != LPC24XX_SSP_DMA_AVAILABLE) {
511    return -RTEMS_RESOURCE_IN_USE;
512  }
513
514  /* Set DMA support status and parameter */
515  lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_WAIT;
516  lpc24xx_ssp_dma_data.done = done;
517  lpc24xx_ssp_dma_data.n = n;
518  lpc24xx_ssp_dma_data.arg = arg;
519
520  /* Enable DMA on SSP */
521  ssp->dmacr = SSP_DMACR_RXDMAE | SSP_DMACR_TXDMAE;
522
523  /* Receive */
524  if (in != NULL) {
[ba938b8d]525    receive_channel->desc.dest = (uint32_t) in;
[29cc1477]526  } else {
[ba938b8d]527    receive_channel->desc.dest = (uint32_t) &lpc24xx_ssp_trash;
[29cc1477]528    di = 0;
529  }
[ba938b8d]530  receive_channel->desc.src = (uint32_t) &ssp->dr;
531  receive_channel->desc.lli = 0;
532  receive_channel->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n)
533    | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_4)
534    | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_4)
535    | SET_GPDMA_CH_CTRL_SW(0, GPDMA_CH_CTRL_W_8)
536    | SET_GPDMA_CH_CTRL_DW(0, GPDMA_CH_CTRL_W_8)
[29cc1477]537    | GPDMA_CH_CTRL_ITC
538    | di;
[ba938b8d]539  receive_channel->cfg = SET_GPDMA_CH_CFG_SRCPER(0, GPDMA_CH_CFG_PER_SSP1_RX)
540    | SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_PER_TO_MEM_DMA)
[29cc1477]541    | GPDMA_CH_CFG_IE
542    | GPDMA_CH_CFG_ITC
543    | GPDMA_CH_CFG_EN;
544
545  /* Transmit */
546  if (out != NULL) {
[ba938b8d]547    transmit_channel->desc.src = (uint32_t) out;
[29cc1477]548  } else {
[ba938b8d]549    transmit_channel->desc.src = (uint32_t) &e->idle_char;
[29cc1477]550    si = 0;
551  }
[ba938b8d]552  transmit_channel->desc.dest = (uint32_t) &ssp->dr;
553  transmit_channel->desc.lli = 0;
554  transmit_channel->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n)
555    | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_4)
556    | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_4)
557    | SET_GPDMA_CH_CTRL_SW(0, GPDMA_CH_CTRL_W_8)
558    | SET_GPDMA_CH_CTRL_DW(0, GPDMA_CH_CTRL_W_8)
[29cc1477]559    | GPDMA_CH_CTRL_ITC
560    | si;
[ba938b8d]561  transmit_channel->cfg = SET_GPDMA_CH_CFG_DESTPER(0, GPDMA_CH_CFG_PER_SSP1_TX)
562    | SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_PER_DMA)
[29cc1477]563    | GPDMA_CH_CFG_IE
564    | GPDMA_CH_CFG_ITC
565    | GPDMA_CH_CFG_EN;
566
567  return 0;
568}
569
[ba938b8d]570static int lpc24xx_ssp_read(rtems_libi2c_bus_t *bus, unsigned char *in, int n)
[29cc1477]571{
[ba938b8d]572  return lpc24xx_ssp_read_write(bus, in, NULL, n);
[29cc1477]573}
574
575static int lpc24xx_ssp_write(
576  rtems_libi2c_bus_t *bus,
577  unsigned char *out,
578  int n
579)
580{
[ba938b8d]581  return lpc24xx_ssp_read_write(bus, NULL, out, n);
[29cc1477]582}
583
[ba938b8d]584static int lpc24xx_ssp_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg)
[29cc1477]585{
586  int rv = -1;
587  const rtems_libi2c_tfr_mode_t *tm = (const rtems_libi2c_tfr_mode_t *) arg;
588  rtems_libi2c_read_write_t *rw = (rtems_libi2c_read_write_t *) arg;
589  rtems_libi2c_read_write_async_t *rwa =
590    (rtems_libi2c_read_write_async_t *) arg;
591
592  switch (cmd) {
593    case RTEMS_LIBI2C_IOCTL_READ_WRITE:
[ba938b8d]594      rv = lpc24xx_ssp_read_write(bus, rw->rd_buf, rw->wr_buf, rw->byte_cnt);
[29cc1477]595      break;
596    case RTEMS_LIBI2C_IOCTL_READ_WRITE_ASYNC:
597      rv = lpc24xx_ssp_read_write_async(
598        bus,
599        rwa->rd_buf,
600        rwa->wr_buf,
601        rwa->byte_cnt,
602        rwa->done,
603        rwa->arg
604      );
605      break;
606    case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
[ba938b8d]607      rv = lpc24xx_ssp_set_transfer_mode(bus, tm);
[29cc1477]608      break;
609    default:
610      rv = -RTEMS_NOT_DEFINED;
611      break;
612  }
613
614  return rv;
615}
616
617static const rtems_libi2c_bus_ops_t lpc24xx_ssp_ops = {
618  .init = lpc24xx_ssp_init,
619  .send_start = lpc24xx_ssp_send_start,
620  .send_stop = lpc24xx_ssp_send_stop,
621  .send_addr = lpc24xx_ssp_send_addr,
622  .read_bytes = lpc24xx_ssp_read,
623  .write_bytes = lpc24xx_ssp_write,
624  .ioctl = lpc24xx_ssp_ioctl
625};
626
627static lpc24xx_ssp_bus_entry lpc24xx_ssp_bus_table [LPC24XX_SSP_NUMBER] = {
628  {
629    /* SSP 0 */
630    .bus = {
631      .ops = &lpc24xx_ssp_ops,
[ba938b8d]632      .size = sizeof(lpc24xx_ssp_bus_entry)
[29cc1477]633    },
634    .regs = (volatile lpc24xx_ssp *) SSP0_BASE_ADDR,
635    .clock = 0,
636    .idle_char = 0xffffffff
637  }, {
638    /* SSP 1 */
639    .bus = {
640      .ops = &lpc24xx_ssp_ops,
[ba938b8d]641      .size = sizeof(lpc24xx_ssp_bus_entry)
[29cc1477]642    },
643    .regs = (volatile lpc24xx_ssp *) SSP1_BASE_ADDR,
644    .clock = 0,
645    .idle_char = 0xffffffff
646  }
647};
648
649rtems_libi2c_bus_t * const lpc24xx_ssp_0 =
650  (rtems_libi2c_bus_t *) &lpc24xx_ssp_bus_table [0];
651
652rtems_libi2c_bus_t * const lpc24xx_ssp_1 =
653  (rtems_libi2c_bus_t *) &lpc24xx_ssp_bus_table [1];
Note: See TracBrowser for help on using the repository browser.