source: rtems/c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c @ 82dcbc8

4.115
Last change on this file since 82dcbc8 was c468f18b, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 12/15/09 at 15:20:47

add support for LPC32xx

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc24xx_libi2c
5 *
6 * @brief LibI2C bus driver for the I2C modules.
7 */
8
9/*
10 * Copyright (c) 2009
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
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.
20 */
21
22#include <rtems.h>
23
24#include <bsp.h>
25#include <bsp/i2c.h>
26#include <bsp/io.h>
27#include <bsp/irq.h>
28#include <bsp/irq-generic.h>
29#include <bsp/lpc24xx.h>
30#include <bsp/system-clocks.h>
31
32#define RTEMS_STATUS_CHECKS_USE_PRINTK
33
34#include <rtems/status-checks.h>
35
36typedef struct {
37  rtems_libi2c_bus_t bus;
38  volatile lpc24xx_i2c *regs;
39  unsigned index;
40  unsigned config;
41  rtems_vector_number vector;
42  rtems_id state_update;
43  uint8_t * volatile data;
44  uint8_t * volatile end;
45} lpc24xx_i2c_bus_entry;
46
47static void lpc24xx_i2c_handler(void *arg)
48{
49  lpc24xx_i2c_bus_entry *e = arg;
50  volatile lpc24xx_i2c *regs = e->regs;
51  unsigned state = regs->stat;
52  uint8_t *data = e->data;
53  uint8_t *end = e->end;
54  bool notify = true;
55
56  switch (state) {
57    case 0x28U:
58      /* Data has been transmitted successfully */
59      if (data != end) {
60        regs->dat = *data;
61        ++data;
62        regs->conset = LPC24XX_I2C_AA;
63        regs->conclr = LPC24XX_I2C_SI;
64        notify = false;
65        e->data = data;
66      }
67      break;
68    case 0x50U:
69      /* Data has been received */
70      if (data != end) {
71        *data = (uint8_t) regs->dat;
72        ++data;
73        if (data != end) {
74          if (data + 1 != end) {
75            regs->conset = LPC24XX_I2C_AA;
76          } else {
77            regs->conclr = LPC24XX_I2C_AA;
78          }
79          regs->conclr = LPC24XX_I2C_SI;
80          notify = false;
81          e->data = data;
82        } else {
83          /* This is an error and should never happen */
84        }
85      }
86      break;
87    case 0x58U:
88      /* Last data has been received */
89      if (data != end) {
90        *data = (uint8_t) regs->dat;
91      }
92      break;
93    default:
94      /* Do nothing */
95      break;
96  }
97
98  /* Notify task if necessary */
99  if (notify) {
100    bsp_interrupt_vector_disable(e->vector);
101
102    rtems_semaphore_release(e->state_update);
103  }
104}
105
106static rtems_status_code lpc24xx_i2c_wait(lpc24xx_i2c_bus_entry *e)
107{
108  bsp_interrupt_vector_enable(e->vector);
109
110  return rtems_semaphore_obtain(e->state_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
111}
112
113static rtems_status_code lpc24xx_i2c_init(rtems_libi2c_bus_t *bus)
114{
115  rtems_status_code sc = RTEMS_SUCCESSFUL;
116  lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
117  volatile lpc24xx_i2c *regs = e->regs;
118  unsigned cycles = LPC24XX_CCLK / (8U * 100000U * 2U);
119
120  /* Create semaphore */
121  sc = rtems_semaphore_create (
122    rtems_build_name ('I', '2', 'C', '0' + e->index),
123    0,
124    RTEMS_SIMPLE_BINARY_SEMAPHORE,
125    0,
126    &e->state_update
127  );
128  RTEMS_CHECK_SC(sc, "create status update semaphore");
129
130  /* Enable module power */
131  sc = lpc24xx_module_enable(LPC24XX_MODULE_I2C_0 + e->index, LPC24XX_MODULE_CCLK_8);
132  RTEMS_CHECK_SC(sc, "enable module");
133
134  /* IO configuration */
135  sc = lpc24xx_io_config(LPC24XX_MODULE_I2C_0 + e->index, e->config);
136  RTEMS_CHECK_SC(sc, "IO configuration");
137
138  /* Clock high and low duty cycles */
139  regs->sclh = cycles;
140  regs->scll = cycles;
141
142  /* Disable module */
143  regs->conclr = LPC24XX_I2C_EN;
144
145  /* Install interrupt handler and disable this vector */
146  sc = rtems_interrupt_handler_install(
147    e->vector,
148    "I2C",
149    RTEMS_INTERRUPT_UNIQUE,
150    lpc24xx_i2c_handler,
151    e
152  );
153  RTEMS_CHECK_SC(sc, "install interrupt handler");
154  bsp_interrupt_vector_disable(e->vector);
155
156  /* Enable module in master mode */
157  regs->conset = LPC24XX_I2C_EN;
158
159  /* Set self address */
160  regs->adr = 0;
161
162  return RTEMS_SUCCESSFUL;
163}
164
165static rtems_status_code lpc24xx_i2c_send_start(rtems_libi2c_bus_t *bus)
166{
167  rtems_status_code sc = RTEMS_SUCCESSFUL;
168  lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
169  volatile lpc24xx_i2c *regs = e->regs;
170
171  /* Start */
172  regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_AA | LPC24XX_I2C_SI;
173  regs->conset = LPC24XX_I2C_STA;
174
175  /* Wait */
176  sc = lpc24xx_i2c_wait(e);
177  RTEMS_CHECK_SC(sc, "wait for state update");
178
179  return RTEMS_SUCCESSFUL;
180}
181
182static rtems_status_code lpc24xx_i2c_send_stop(rtems_libi2c_bus_t *bus)
183{
184  lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
185  volatile lpc24xx_i2c *regs = e->regs;
186
187  /* Stop */
188  regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA;
189  regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
190
191  return RTEMS_SUCCESSFUL;
192}
193
194static rtems_status_code lpc24xx_i2c_send_addr(
195  rtems_libi2c_bus_t *bus,
196  uint32_t addr,
197  int rw
198)
199{
200  rtems_status_code sc = RTEMS_SUCCESSFUL;
201  lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
202  volatile lpc24xx_i2c *regs = e->regs;
203  unsigned state = regs->stat;
204
205  /* Check state */
206  if (state != 0x8U && state != 0x10U) {
207    return -RTEMS_IO_ERROR;
208  }
209
210  /* Send address */
211  regs->dat = (uint8_t) ((addr << 1U) | ((rw != 0) ? 1U : 0U));
212  regs->conset = LPC24XX_I2C_AA;
213  regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
214
215  /* Wait */
216  sc = lpc24xx_i2c_wait(e);
217  RTEMS_CHECK_SC_RV(sc, "wait for state update");
218
219  /* Check state */
220  state = regs->stat;
221  if (state != 0x18U && state != 0x40U) {
222    return -RTEMS_IO_ERROR;
223  }
224
225  return RTEMS_SUCCESSFUL;
226}
227
228static int lpc24xx_i2c_read(rtems_libi2c_bus_t *bus, unsigned char *in, int n)
229{
230  rtems_status_code sc = RTEMS_SUCCESSFUL;
231  lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
232  volatile lpc24xx_i2c *regs = e->regs;
233  unsigned state = regs->stat;
234  uint8_t *data = in;
235  uint8_t *end = in + n;
236
237  if (n <= 0) {
238    return n;
239  } else if (state != 0x40U) {
240    return -RTEMS_IO_ERROR;
241  }
242
243  /* Setup receive buffer */
244  e->data = data;
245  e->end = end;
246
247  /* Ready to receive data */
248  if (data + 1 != end) {
249    regs->conset = LPC24XX_I2C_AA;
250  } else {
251    regs->conclr = LPC24XX_I2C_AA;
252  }
253  regs->conclr = LPC24XX_I2C_SI;
254
255  /* Wait */
256  sc = lpc24xx_i2c_wait(e);
257  RTEMS_CHECK_SC_RV(sc, "wait for state update");
258
259  /* Check state */
260  state = regs->stat;
261  if (state != 0x58U) {
262    return -RTEMS_IO_ERROR;
263  }
264
265  return n;
266}
267
268static int lpc24xx_i2c_write(
269  rtems_libi2c_bus_t *bus,
270  unsigned char *out,
271  int n
272)
273{
274  rtems_status_code sc = RTEMS_SUCCESSFUL;
275  lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
276  volatile lpc24xx_i2c *regs = e->regs;
277  unsigned state = 0;
278
279  if (n <= 0) {
280    return n;
281  }
282
283  /* Setup transmit buffer */
284  e->data = out + 1;
285  e->end = out + n;
286
287  /* Transmit first byte */
288  regs->dat = *out;
289  regs->conset = LPC24XX_I2C_AA;
290  regs->conclr = LPC24XX_I2C_SI;
291
292  /* Wait */
293  sc = lpc24xx_i2c_wait(e);
294  RTEMS_CHECK_SC_RV(sc, "wait for state update");
295
296  /* Check state */
297  state = regs->stat;
298  if (state != 0x28U) {
299    return -RTEMS_IO_ERROR;
300  }
301
302  return n;
303}
304
305static int lpc24xx_i2c_set_transfer_mode(
306  rtems_libi2c_bus_t *bus,
307  const rtems_libi2c_tfr_mode_t *mode
308)
309{
310  return -RTEMS_NOT_IMPLEMENTED;
311}
312
313static int lpc24xx_i2c_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg)
314{
315  int rv = -1;
316  const rtems_libi2c_tfr_mode_t *tm = (const rtems_libi2c_tfr_mode_t *) arg;
317
318  switch (cmd) {
319    case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
320      rv = lpc24xx_i2c_set_transfer_mode(bus, tm);
321      break;
322    default:
323      rv = -RTEMS_NOT_DEFINED;
324      break;
325  }
326
327  return rv;
328}
329
330static const rtems_libi2c_bus_ops_t lpc24xx_i2c_ops = {
331  .init = lpc24xx_i2c_init,
332  .send_start = lpc24xx_i2c_send_start,
333  .send_stop = lpc24xx_i2c_send_stop,
334  .send_addr = lpc24xx_i2c_send_addr,
335  .read_bytes = lpc24xx_i2c_read,
336  .write_bytes = lpc24xx_i2c_write,
337  .ioctl = lpc24xx_i2c_ioctl
338};
339
340#ifdef LPC24XX_CONFIG_I2C_0
341  static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_0 = {
342    .bus = {
343      .ops = &lpc24xx_i2c_ops,
344      .size = sizeof(lpc24xx_i2c_bus_entry)
345    },
346    .regs = (volatile lpc24xx_i2c *) I2C0_BASE_ADDR,
347    .index = 0,
348    .config = LPC24XX_CONFIG_I2C_0,
349    .vector = LPC24XX_IRQ_I2C_0
350  };
351
352  rtems_libi2c_bus_t * const lpc24xx_i2c_0 =
353    (rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_0;
354#endif
355
356#ifdef LPC24XX_CONFIG_I2C_1
357  static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_1 = {
358    .bus = {
359      .ops = &lpc24xx_i2c_ops,
360      .size = sizeof(lpc24xx_i2c_bus_entry)
361    },
362    .regs = (volatile lpc24xx_i2c *) I2C1_BASE_ADDR,
363    .index = 1,
364    .config = LPC24XX_CONFIG_I2C_1,
365    .vector = LPC24XX_IRQ_I2C_1
366  };
367
368  rtems_libi2c_bus_t * const lpc24xx_i2c_1 =
369    (rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_1;
370#endif
371
372#ifdef LPC24XX_CONFIG_I2C_2
373  static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_2 = {
374    .bus = {
375      .ops = &lpc24xx_i2c_ops,
376      .size = sizeof(lpc24xx_i2c_bus_entry)
377    },
378    .regs = (volatile lpc24xx_i2c *) I2C2_BASE_ADDR,
379    .index = 2,
380    .config = LPC24XX_CONFIG_I2C_2,
381    .vector = LPC24XX_IRQ_I2C_2
382  };
383
384  rtems_libi2c_bus_t * const lpc24xx_i2c_2 =
385    (rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_2;
386#endif
Note: See TracBrowser for help on using the repository browser.