source: rtems/bsps/arm/lpc24xx/i2c/i2c.c @ a2dad96

5
Last change on this file since a2dad96 was a2dad96, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 23, 2018 at 7:45:28 AM

bsps: Move I2C drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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