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

4.115
Last change on this file since 18a0c56 was 18a0c56, checked in by Sebastian Huber <sebastian.huber@…>, on 08/08/11 at 12:33:22

2011-08-08 Sebastian Huber <sebastian.huber@…>

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