source: rtems/c/src/lib/libbsp/arm/lpc32xx/misc/i2c.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on Mar 20, 2014 at 9:10:47 PM

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 4.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc32xx_i2c
5 *
6 * @brief I2C support implementation.
7 */
8
9/*
10 * Copyright (c) 2010-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 <rtems.h>
24
25#include <bsp.h>
26#include <bsp/i2c.h>
27
28void lpc32xx_i2c_reset(volatile lpc32xx_i2c *i2c)
29{
30  i2c->ctrl = I2C_CTRL_RESET;
31}
32
33rtems_status_code lpc32xx_i2c_init(
34  volatile lpc32xx_i2c *i2c,
35  unsigned clock_in_hz
36)
37{
38  uint32_t i2cclk = 0;
39
40  if (i2c == &lpc32xx.i2c_1) {
41    i2cclk |= I2CCLK_1_EN | I2CCLK_1_HIGH_DRIVE;
42  } else if (i2c == &lpc32xx.i2c_2) {
43    i2cclk |= I2CCLK_2_EN | I2CCLK_2_HIGH_DRIVE;
44  } else {
45    return RTEMS_INVALID_ID;
46  }
47
48  LPC32XX_I2CCLK_CTRL |= i2cclk;
49
50  lpc32xx_i2c_reset(i2c);
51
52  return lpc32xx_i2c_clock(i2c, clock_in_hz);
53}
54
55rtems_status_code lpc32xx_i2c_clock(
56  volatile lpc32xx_i2c *i2c,
57  unsigned clock_in_hz
58)
59{
60  uint32_t clk_div = lpc32xx_hclk() / clock_in_hz;
61  uint32_t clk_lo = 0;
62  uint32_t clk_hi = 0;
63
64  switch (clock_in_hz) {
65    case 100000:
66      clk_lo = clk_div / 2;
67      break;
68    case 400000:
69      clk_lo = (64 * clk_div) / 100;
70      break;
71    default:
72      return RTEMS_INVALID_CLOCK;
73  }
74
75  clk_hi = clk_div - clk_lo;
76
77  i2c->clk_lo = clk_lo;
78  i2c->clk_hi = clk_hi;
79
80  return RTEMS_SUCCESSFUL;
81}
82
83static rtems_status_code wait_for_transaction_done(volatile lpc32xx_i2c *i2c)
84{
85  uint32_t stat = 0;
86
87  do {
88    stat = i2c->stat;
89  } while ((stat & I2C_STAT_TDI) == 0);
90
91  if ((stat & I2C_STAT_TFE) != 0) {
92    i2c->stat = I2C_STAT_TDI;
93
94    return RTEMS_SUCCESSFUL;
95  } else {
96    lpc32xx_i2c_reset(i2c);
97
98    return RTEMS_IO_ERROR;
99  }
100}
101
102static rtems_status_code tx(volatile lpc32xx_i2c *i2c, uint32_t data)
103{
104  uint32_t stat = 0;
105
106  do {
107    stat = i2c->stat;
108  } while ((stat & (I2C_STAT_TFE | I2C_STAT_TDI)) == 0);
109
110  if ((stat & I2C_STAT_TDI) == 0) {
111    i2c->rx_or_tx = data;
112
113    return RTEMS_SUCCESSFUL;
114  } else {
115    lpc32xx_i2c_reset(i2c);
116
117    return RTEMS_IO_ERROR;
118  }
119}
120
121rtems_status_code lpc32xx_i2c_write_start(
122  volatile lpc32xx_i2c *i2c,
123  unsigned addr
124)
125{
126  return tx(i2c, I2C_TX_ADDR(addr) | I2C_TX_START);
127}
128
129rtems_status_code lpc32xx_i2c_read_start(
130  volatile lpc32xx_i2c *i2c,
131  unsigned addr
132)
133{
134  return tx(i2c, I2C_TX_ADDR(addr) | I2C_TX_START | I2C_TX_READ);
135}
136
137rtems_status_code lpc32xx_i2c_write_with_optional_stop(
138  volatile lpc32xx_i2c *i2c,
139  const uint8_t *out,
140  size_t n,
141  bool stop
142)
143{
144  rtems_status_code sc = RTEMS_SUCCESSFUL;
145  size_t i = 0;
146
147  for (i = 0; i < n - 1 && sc == RTEMS_SUCCESSFUL; ++i) {
148    sc = tx(i2c, out [i]);
149  }
150
151  if (sc == RTEMS_SUCCESSFUL) {
152    uint32_t stop_flag = stop ? I2C_TX_STOP : 0;
153
154    sc = tx(i2c, out [n - 1] | stop_flag);
155  }
156
157  if (stop && sc == RTEMS_SUCCESSFUL) {
158    sc = wait_for_transaction_done(i2c);
159  }
160
161  return sc;
162}
163
164static bool can_tx_for_rx(volatile lpc32xx_i2c *i2c)
165{
166  return (i2c->stat & (I2C_STAT_TFF | I2C_STAT_RFF)) == 0;
167}
168
169static bool can_rx(volatile lpc32xx_i2c *i2c)
170{
171  return (i2c->stat & I2C_STAT_RFE) == 0;
172}
173
174rtems_status_code lpc32xx_i2c_read_with_optional_stop(
175  volatile lpc32xx_i2c *i2c,
176  uint8_t *in,
177  size_t n,
178  bool stop
179)
180{
181  rtems_status_code sc = RTEMS_SUCCESSFUL;
182  size_t last = n - 1;
183  size_t rx = 0;
184  size_t tx = 0;
185
186  if (!stop) {
187    return RTEMS_NOT_IMPLEMENTED;
188  }
189
190  while (rx <= last) {
191    while (tx < last && can_tx_for_rx(i2c)) {
192      i2c->rx_or_tx = 0;
193      ++tx;
194    }
195
196    if (tx == last && can_tx_for_rx(i2c)) {
197      uint32_t stop_flag = stop ? I2C_TX_STOP : 0;
198
199      i2c->rx_or_tx = stop_flag;
200      ++tx;
201    }
202
203    while (rx <= last && can_rx(i2c)) {
204      in [rx] = (uint8_t) i2c->rx_or_tx;
205      ++rx;
206    }
207  }
208
209  if (stop) {
210    sc = wait_for_transaction_done(i2c);
211  }
212
213  return sc;
214}
215
216rtems_status_code lpc32xx_i2c_write_and_read(
217  volatile lpc32xx_i2c *i2c,
218  unsigned addr,
219  const uint8_t *out,
220  size_t out_size,
221  uint8_t *in,
222  size_t in_size
223)
224{
225  rtems_status_code sc = RTEMS_SUCCESSFUL;
226
227  if (out_size > 0) {
228    bool stop = in_size == 0;
229
230    sc = lpc32xx_i2c_write_start(i2c, addr);
231    if (sc != RTEMS_SUCCESSFUL) {
232      return sc;
233    }
234
235    sc = lpc32xx_i2c_write_with_optional_stop(i2c, out, out_size, stop);
236    if (sc != RTEMS_SUCCESSFUL) {
237      return sc;
238    }
239  }
240
241  if (in_size > 0) {
242    sc = lpc32xx_i2c_read_start(i2c, addr);
243    if (sc != RTEMS_SUCCESSFUL) {
244      return sc;
245    }
246
247    lpc32xx_i2c_read_with_optional_stop(i2c, in, in_size, true);
248  }
249
250  return RTEMS_SUCCESSFUL;
251}
Note: See TracBrowser for help on using the repository browser.