source: rtems/bsps/arm/lpc32xx/i2c/i2c.c @ ba619b7f

Last change on this file since ba619b7f was ba619b7f, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:20

bsps/arm/: Scripted embedded brains header file clean up

Updates #4625.

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