source: rtems/c/src/lib/libbsp/arm/raspberrypi/i2c/i2c.c @ 70e8abf

5
Last change on this file since 70e8abf was 70e8abf, checked in by Gedare Bloom <gedare@…>, on Jan 19, 2017 at 8:34:18 PM

raspberrypi: use signed int for return variable

Closes #2873.

  • Property mode set to 100644
File size: 11.6 KB
Line 
1/**
2 * @file i2c.c
3 *
4 * @ingroup raspberrypi_i2c
5 *
6 * @brief Support for the I2C bus on the Raspberry Pi GPIO P1 header (model A/B)
7 *        and GPIO J8 header on model B+.
8 */
9
10/*
11 *  Copyright (c) 2014-2015 Andre Marques <andre.lousa.marques at gmail.com>
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18/*
19 * STATUS:
20 * - 10-bit slave addressing untested
21 */
22
23#include <bsp.h>
24#include <bsp/raspberrypi.h>
25#include <bsp/gpio.h>
26#include <bsp/rpi-gpio.h>
27#include <bsp/irq.h>
28#include <bsp/i2c.h>
29#include <assert.h>
30
31#define TRANSFER_COUNT(buffer_size) (buffer_size + 0xFFFE) / 0xFFFF
32
33#define ADJUST_TRANSFER_SIZE(transfer_count, remaining_bytes) \
34  transfer_count > 1 ? 0xFFFF : (remaining_bytes & 0xFFFF)
35
36#define I2C_POLLING(condition)                  \
37  while ( condition ) {                         \
38    ;                                           \
39  }
40
41/**
42 * @brief Object containing relevant information about an I2C bus.
43 *
44 * Encapsulates relevant data for a I2C bus transfer.
45 */
46typedef struct
47{
48  i2c_bus base;
49  uint32_t input_clock;
50  rtems_id task_id;
51
52  /* Remaining bytes to read/write on the current bus transfer. */
53  uint32_t remaining_bytes;
54  /* Each transfer has a limit of 0xFFFF bytes, hence larger transfers
55   * have to be divided. Each transfer implies a stop condition, signaled
56   * automatically by the BSC controller. */
57  uint32_t remaining_transfers;
58
59  uint8_t *current_buffer;
60  uint32_t current_buffer_size;
61
62  bool read_transfer;
63} rpi_i2c_bus;
64
65static int rpi_i2c_bus_transfer(rpi_i2c_bus *bus)
66{
67  while ( bus->remaining_bytes >= 1 ) {
68    /* If reading. */
69    if ( bus->read_transfer ) {
70      /* Poll RXD bit until there is data on the RX FIFO to read. */
71      I2C_POLLING((BCM2835_REG(BCM2835_I2C_S) & (1 << 5)) == 0);
72
73      /* Read data from the RX FIFO. */
74      (*(uint8_t *) bus->current_buffer) = BCM2835_REG(BCM2835_I2C_FIFO) & 0xFF;
75
76      ++bus->current_buffer;
77
78      /* Check for acknowledgment or clock stretching errors. */
79      if (
80          (BCM2835_REG(BCM2835_I2C_S) & (1 << 8)) ||
81          (BCM2835_REG(BCM2835_I2C_S) & (1 << 9))
82      ) {
83        return -EIO;
84      }
85    }
86    /* If writing. */
87    else {
88      /* If using the I2C bus in interrupt-driven mode. */
89#if I2C_IO_MODE == 1
90      /* Generate interrupts on the TXW bit condition. */
91      BCM2835_REG(BCM2835_I2C_C) |= (1 << 9);
92
93      /* Sleep until the TX FIFO has free space for a new write. */
94      bus->task_id = rtems_task_self();
95      if (
96          rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout) !=
97          RTEMS_SUCCESSFUL
98      ) {
99        rtems_event_transient_clear();
100
101        return -ETIMEDOUT;
102      }
103
104      /* If using the bus in polling mode. */
105#else
106      /* Poll TXW bit until there is space available to write. */
107      I2C_POLLING((BCM2835_REG(BCM2835_I2C_S) & (1 << 2)) == 0);
108#endif
109
110      /* Write data to the TX FIFO. */
111      BCM2835_REG(BCM2835_I2C_FIFO) = (*(uint8_t *) bus->current_buffer);
112
113      ++bus->current_buffer;
114
115      /* Check for acknowledgment or clock stretching errors. */
116      if (
117          (BCM2835_REG(BCM2835_I2C_S) & (1 << 8)) ||
118          (BCM2835_REG(BCM2835_I2C_S) & (1 << 9))
119      ) {
120        return -EIO;
121      }
122    }
123
124    --bus->remaining_bytes;
125    --bus->current_buffer_size;
126  }
127
128  return 0;
129}
130
131static int rpi_i2c_setup_transfer(rpi_i2c_bus *bus)
132{
133  int rv;
134
135  while ( bus->remaining_transfers > 0 ) {
136    /* Setup the byte size of the current transfer. */
137    bus->remaining_bytes = ADJUST_TRANSFER_SIZE(
138                             bus->remaining_transfers,
139                             bus->current_buffer_size
140                           );
141
142    /* Set the DLEN register, which specifies how many data packets
143     * will be transferred. */
144    BCM2835_REG(BCM2835_I2C_DLEN) = bus->remaining_bytes;
145
146    /* Clear the acknowledgment and clock stretching error status. */
147    BCM2835_REG(BCM2835_I2C_S) |= (3 << 8);
148
149    /* Send start bit. */
150    BCM2835_REG(BCM2835_I2C_C) |= (1 << 7);
151
152    /* Check for an acknowledgment error. */
153    if ( (BCM2835_REG(BCM2835_I2C_S) & (1 << 8)) != 0 ) {
154      return -EIO;
155    }
156
157    rv = rpi_i2c_bus_transfer(bus);
158
159    if ( rv < 0 ) {
160      return rv;
161    }
162
163    /* Wait for the current transfer to finish. */
164
165    /* If using the I2C bus in interrupt-driven mode. */
166#if I2C_IO_MODE == 1
167    /* Generate interrupts on the DONE bit condition. */
168    BCM2835_REG(BCM2835_I2C_C) |= (1 << 8);
169
170    if (
171        rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout) !=
172        RTEMS_SUCCESSFUL
173    ) {
174      rtems_event_transient_clear();
175
176      return -ETIMEDOUT;
177    }
178    /* If using the bus in polling mode. */
179#else
180    /* Poll DONE bit until all data has been sent. */
181    I2C_POLLING((BCM2835_REG(BCM2835_I2C_S) & (1 << 1)) == 0);
182#endif
183
184    --bus->remaining_transfers;
185  }
186
187  return 0;
188}
189
190/* Handler function that is called on any I2C interrupt.
191 *
192 * There are 3 situations that can generate an interrupt:
193 *
194 * 1. Transfer (read/write) complete;
195 * 2. The TX FIFO has space for more data (during a write transfer);
196 * 3. The RX FIFO is full.
197 *
198 * Because the I2C FIFO has a 16 byte size, the 3. situation is not
199 * as useful to many applications as knowing that at least 1 byte can
200 * be read from the RX FIFO. For that reason this information is
201 * got through polling the RXD bit even in interrupt-driven mode.
202 *
203 * This leaves only 2 interrupts to be caught. At any given time
204 * when no I2C bus transfer is taking place no I2C interrupts are
205 * generated, and they do they are only enabled one at a time:
206 *
207 * - When trying to write, the 2. interrupt is enabled to signal that
208 *   data can be written on the TX FIFO, avoiding data loss in case
209 *   it is full. When caught the handler disables that interrupt from
210 *   being generated and sends a waking event to the transfer task,
211 *   which will allow the transfer process to continue
212 *   (by writing to the TX FIFO);
213 *
214 * - When the transfer is done on the Raspberry side, the 1. interrupt is
215 *   enabled for the device to signal it has finished the transfer as
216 *   well. When caught the handler disables that interrupt from being
217 *   generated and sends a waking event to the transfer task, marking
218 *   the end of the transfer.
219 */
220#if I2C_IO_MODE == 1
221static void i2c_handler(void *arg)
222{
223  rpi_i2c_bus *bus = (rpi_i2c_bus *) arg;
224
225  /* If the current enabled interrupt is on the TXW condition, disable it. */
226  if ( (BCM2835_REG(BCM2835_I2C_C) & (1 << 9)) ) {
227    BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 9);
228  }
229  /* If the current enabled interrupt is on the DONE condition, disable it. */
230  else if ( (BCM2835_REG(BCM2835_I2C_C) & (1 << 8)) ) {
231    BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 8);
232  }
233
234  /* Allow the transfer process to continue. */
235  rtems_event_transient_send(bus->task_id);
236}
237#endif
238
239static int rpi_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
240{
241  rpi_i2c_bus *bus = (rpi_i2c_bus *) base;
242  int rv = 0;
243  uint32_t i;
244
245  /* Perform an initial parse through the messages for the I2C_M_RECV_LEN flag,
246   * which the Pi seems to not support and the I2C framework expects the bus
247   * to provide as part of the I2C_FUNC_I2C functionality.
248   *
249   * It states that the slave device sends an initial byte containing the size
250   * of the transfer, and for this to work the Pi will likely require two
251   * transfers, with a stop-start condition in-between. */
252  for ( i = 0; i < msg_count; ++i ) {
253    if ( msgs[i].flags & I2C_M_RECV_LEN ) {
254      return -EINVAL;
255    }
256  }
257
258  for ( i = 0; i < msg_count; ++i ) {
259    /* Clear FIFOs. */
260    BCM2835_REG(BCM2835_I2C_C) |= (3 << 4);
261
262    /* Setup transfer. */
263    bus->current_buffer = msgs[i].buf;
264    bus->current_buffer_size = msgs[i].len;
265    bus->remaining_transfers = TRANSFER_COUNT(bus->current_buffer_size);
266
267    /* If the slave uses 10-bit addressing. */
268    if ( msgs[i].flags & I2C_M_TEN ) {
269      /* Write the 8 least-significative bits of the slave address
270       * to the bus FIFO. */
271      BCM2835_REG(BCM2835_I2C_FIFO) = msgs[i].addr & 0xFF;
272
273      /* Address slave device, with the 2 most-significative bits at the end. */
274      BCM2835_REG(BCM2835_I2C_A) = (0x1E << 2) | (msgs[i].addr >> 8);
275    }
276    /* If using the regular 7-bit slave addressing. */
277    else {
278      /* Address slave device. */
279      BCM2835_REG(BCM2835_I2C_A) = msgs[i].addr;
280    }
281
282    if ( msgs[i].flags & I2C_M_RD ) {
283      /* If the slave uses 10-bit addressing. */
284      if ( msgs[i].flags & I2C_M_TEN ) {
285        /* 10-bit addressing setup for a read transfer. */
286        BCM2835_REG(BCM2835_I2C_DLEN) = 1;
287
288        /* Set write bit. */
289        BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 0);
290
291        /* Send start bit. */
292        BCM2835_REG(BCM2835_I2C_C) |= (1 << 7);
293
294        /* Poll the TA bit until the transfer has started. */
295        I2C_POLLING((BCM2835_REG(BCM2835_I2C_S) & (1 << 0)) == 0);
296      }
297
298      /* Set read bit. */
299      BCM2835_REG(BCM2835_I2C_C) |= (1 << 0);
300
301      bus->read_transfer = true;
302    }
303    else if ( msgs[i].flags == 0 || msgs[i].flags == I2C_M_TEN ) {
304      /* If the slave uses 10-bit addressing. */
305      if ( msgs[i].flags & I2C_M_TEN ) {
306        /* 10-bit addressing setup for a write transfer. */
307        bus->current_buffer_size += 1;
308
309        bus->remaining_transfers = TRANSFER_COUNT(bus->current_buffer_size);
310      }
311
312      /* Set write bit. */
313      BCM2835_REG(BCM2835_I2C_C) &= ~(1 << 0);
314
315      bus->read_transfer = false;
316    }
317
318    rv = rpi_i2c_setup_transfer(bus);
319
320    if ( rv < 0 ) {
321      return rv;
322    }
323  }
324
325  return rv;
326}
327
328/* Calculates a clock divider to be used with the BSC core clock rate
329 * to set a I2C clock rate the closest (<=) to a desired frequency. */
330static int rpi_i2c_set_clock(i2c_bus *base, unsigned long clock)
331{
332  rpi_i2c_bus *bus = (rpi_i2c_bus *) base;
333  uint32_t clock_rate;
334  uint16_t divider;
335
336  /* Calculates an initial clock divider. */
337  divider = BSC_CORE_CLK_HZ / clock;
338
339  clock_rate = BSC_CORE_CLK_HZ / divider;
340
341  /* If the resulting clock rate is greater than desired, try the next greater
342   * divider. */
343  while ( clock_rate > clock ) {
344    ++divider;
345
346    clock_rate = BSC_CORE_CLK_HZ / divider;
347  }
348
349  /* Set clock divider. */
350  BCM2835_REG(BCM2835_I2C_DIV) = divider;
351
352  bus->input_clock = clock_rate;
353
354  return 0;
355}
356
357static void rpi_i2c_destroy(i2c_bus *base)
358{
359  rpi_i2c_bus *bus = (rpi_i2c_bus *) base;
360
361  i2c_bus_destroy_and_free(&bus->base);
362}
363
364int rpi_i2c_register_bus(
365  const char *bus_path,
366  uint32_t bus_clock
367) {
368#if I2C_IO_MODE == 1
369  rtems_status_code sc;
370#endif
371  rpi_i2c_bus *bus;
372  int rv;
373
374  bus = (rpi_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
375
376  if ( bus == NULL ) {
377    return -1;
378  }
379
380  /* Enable the I2C BSC interface. */
381  BCM2835_REG(BCM2835_I2C_C) |= (1 << 15);
382
383  /* If the access to the bus is configured to be interrupt-driven. */
384#if I2C_IO_MODE == 1
385  bus->task_id = rtems_task_self();
386
387  sc = rtems_interrupt_handler_install(
388         BCM2835_IRQ_ID_I2C,
389         NULL,
390         RTEMS_INTERRUPT_UNIQUE,
391         (rtems_interrupt_handler) i2c_handler,
392         bus
393       );
394
395  if ( sc != RTEMS_SUCCESSFUL ) {
396    return -EIO;
397  }
398#endif
399
400  rv = rpi_i2c_set_clock(&bus->base, bus_clock);
401
402  if ( rv < 0 ) {
403    (*bus->base.destroy)(&bus->base);
404
405    return -1;
406  }
407
408  bus->base.transfer = rpi_i2c_transfer;
409  bus->base.set_clock = rpi_i2c_set_clock;
410  bus->base.destroy = rpi_i2c_destroy;
411  bus->base.functionality = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
412
413  return i2c_bus_register(&bus->base, bus_path);
414}
415
416void rpi_i2c_init(void)
417{
418  /* Enable the I2C interface on the Raspberry Pi. */
419  rtems_gpio_initialize();
420
421  assert ( rpi_gpio_select_i2c() == RTEMS_SUCCESSFUL );
422}
Note: See TracBrowser for help on using the repository browser.