File indexing completed on 2025-05-11 08:23:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <rtems.h>
0037
0038 #include <bsp.h>
0039 #include <bsp/i2c.h>
0040
0041 void lpc32xx_i2c_reset(volatile lpc32xx_i2c *i2c)
0042 {
0043 i2c->ctrl = I2C_CTRL_RESET;
0044 }
0045
0046 rtems_status_code lpc32xx_i2c_init(
0047 volatile lpc32xx_i2c *i2c,
0048 unsigned clock_in_hz
0049 )
0050 {
0051 uint32_t i2cclk = 0;
0052
0053 if (i2c == &lpc32xx.i2c_1) {
0054 i2cclk |= I2CCLK_1_EN | I2CCLK_1_HIGH_DRIVE;
0055 } else if (i2c == &lpc32xx.i2c_2) {
0056 i2cclk |= I2CCLK_2_EN | I2CCLK_2_HIGH_DRIVE;
0057 } else {
0058 return RTEMS_INVALID_ID;
0059 }
0060
0061 LPC32XX_I2CCLK_CTRL |= i2cclk;
0062
0063 lpc32xx_i2c_reset(i2c);
0064
0065 return lpc32xx_i2c_clock(i2c, clock_in_hz);
0066 }
0067
0068 rtems_status_code lpc32xx_i2c_clock(
0069 volatile lpc32xx_i2c *i2c,
0070 unsigned clock_in_hz
0071 )
0072 {
0073 uint32_t clk_div = lpc32xx_hclk() / clock_in_hz;
0074 uint32_t clk_lo = 0;
0075 uint32_t clk_hi = 0;
0076
0077 switch (clock_in_hz) {
0078 case 100000:
0079 clk_lo = clk_div / 2;
0080 break;
0081 case 400000:
0082 clk_lo = (64 * clk_div) / 100;
0083 break;
0084 default:
0085 return RTEMS_INVALID_CLOCK;
0086 }
0087
0088 clk_hi = clk_div - clk_lo;
0089
0090 i2c->clk_lo = clk_lo;
0091 i2c->clk_hi = clk_hi;
0092
0093 return RTEMS_SUCCESSFUL;
0094 }
0095
0096 static rtems_status_code wait_for_transaction_done(volatile lpc32xx_i2c *i2c)
0097 {
0098 uint32_t stat = 0;
0099
0100 do {
0101 stat = i2c->stat;
0102 } while ((stat & I2C_STAT_TDI) == 0);
0103
0104 if ((stat & I2C_STAT_TFE) != 0) {
0105 i2c->stat = I2C_STAT_TDI;
0106
0107 return RTEMS_SUCCESSFUL;
0108 } else {
0109 lpc32xx_i2c_reset(i2c);
0110
0111 return RTEMS_IO_ERROR;
0112 }
0113 }
0114
0115 static rtems_status_code tx(volatile lpc32xx_i2c *i2c, uint32_t data)
0116 {
0117 uint32_t stat = 0;
0118
0119 do {
0120 stat = i2c->stat;
0121 } while ((stat & (I2C_STAT_TFE | I2C_STAT_TDI)) == 0);
0122
0123 if ((stat & I2C_STAT_TDI) == 0) {
0124 i2c->rx_or_tx = data;
0125
0126 return RTEMS_SUCCESSFUL;
0127 } else {
0128 lpc32xx_i2c_reset(i2c);
0129
0130 return RTEMS_IO_ERROR;
0131 }
0132 }
0133
0134 rtems_status_code lpc32xx_i2c_write_start(
0135 volatile lpc32xx_i2c *i2c,
0136 unsigned addr
0137 )
0138 {
0139 return tx(i2c, I2C_TX_ADDR(addr) | I2C_TX_START);
0140 }
0141
0142 rtems_status_code lpc32xx_i2c_read_start(
0143 volatile lpc32xx_i2c *i2c,
0144 unsigned addr
0145 )
0146 {
0147 return tx(i2c, I2C_TX_ADDR(addr) | I2C_TX_START | I2C_TX_READ);
0148 }
0149
0150 rtems_status_code lpc32xx_i2c_write_with_optional_stop(
0151 volatile lpc32xx_i2c *i2c,
0152 const uint8_t *out,
0153 size_t n,
0154 bool stop
0155 )
0156 {
0157 rtems_status_code sc = RTEMS_SUCCESSFUL;
0158 size_t i = 0;
0159
0160 for (i = 0; i < n - 1 && sc == RTEMS_SUCCESSFUL; ++i) {
0161 sc = tx(i2c, out [i]);
0162 }
0163
0164 if (sc == RTEMS_SUCCESSFUL) {
0165 uint32_t stop_flag = stop ? I2C_TX_STOP : 0;
0166
0167 sc = tx(i2c, out [n - 1] | stop_flag);
0168 }
0169
0170 if (stop && sc == RTEMS_SUCCESSFUL) {
0171 sc = wait_for_transaction_done(i2c);
0172 }
0173
0174 return sc;
0175 }
0176
0177 static bool can_tx_for_rx(volatile lpc32xx_i2c *i2c)
0178 {
0179 return (i2c->stat & (I2C_STAT_TFF | I2C_STAT_RFF)) == 0;
0180 }
0181
0182 static bool can_rx(volatile lpc32xx_i2c *i2c)
0183 {
0184 return (i2c->stat & I2C_STAT_RFE) == 0;
0185 }
0186
0187 rtems_status_code lpc32xx_i2c_read_with_optional_stop(
0188 volatile lpc32xx_i2c *i2c,
0189 uint8_t *in,
0190 size_t n,
0191 bool stop
0192 )
0193 {
0194 rtems_status_code sc = RTEMS_SUCCESSFUL;
0195 size_t last = n - 1;
0196 size_t rx = 0;
0197 size_t tx = 0;
0198
0199 if (!stop) {
0200 return RTEMS_NOT_IMPLEMENTED;
0201 }
0202
0203 while (rx <= last) {
0204 while (tx < last && can_tx_for_rx(i2c)) {
0205 i2c->rx_or_tx = 0;
0206 ++tx;
0207 }
0208
0209 if (tx == last && can_tx_for_rx(i2c)) {
0210 uint32_t stop_flag = stop ? I2C_TX_STOP : 0;
0211
0212 i2c->rx_or_tx = stop_flag;
0213 ++tx;
0214 }
0215
0216 while (rx <= last && can_rx(i2c)) {
0217 in [rx] = (uint8_t) i2c->rx_or_tx;
0218 ++rx;
0219 }
0220 }
0221
0222 if (stop) {
0223 sc = wait_for_transaction_done(i2c);
0224 }
0225
0226 return sc;
0227 }
0228
0229 rtems_status_code lpc32xx_i2c_write_and_read(
0230 volatile lpc32xx_i2c *i2c,
0231 unsigned addr,
0232 const uint8_t *out,
0233 size_t out_size,
0234 uint8_t *in,
0235 size_t in_size
0236 )
0237 {
0238 rtems_status_code sc = RTEMS_SUCCESSFUL;
0239
0240 if (out_size > 0) {
0241 bool stop = in_size == 0;
0242
0243 sc = lpc32xx_i2c_write_start(i2c, addr);
0244 if (sc != RTEMS_SUCCESSFUL) {
0245 return sc;
0246 }
0247
0248 sc = lpc32xx_i2c_write_with_optional_stop(i2c, out, out_size, stop);
0249 if (sc != RTEMS_SUCCESSFUL) {
0250 return sc;
0251 }
0252 }
0253
0254 if (in_size > 0) {
0255 sc = lpc32xx_i2c_read_start(i2c, addr);
0256 if (sc != RTEMS_SUCCESSFUL) {
0257 return sc;
0258 }
0259
0260 lpc32xx_i2c_read_with_optional_stop(i2c, in, in_size, true);
0261 }
0262
0263 return RTEMS_SUCCESSFUL;
0264 }