[267c7c5] | 1 | /*===============================================================*\ |
---|
| 2 | | Project: RTEMS support for MPC83xx | |
---|
| 3 | +-----------------------------------------------------------------+ |
---|
| 4 | | Copyright (c) 2007 | |
---|
| 5 | | Embedded Brains GmbH | |
---|
| 6 | | Obere Lagerstr. 30 | |
---|
| 7 | | D-82178 Puchheim | |
---|
| 8 | | Germany | |
---|
| 9 | | rtems@embedded-brains.de | |
---|
| 10 | +-----------------------------------------------------------------+ |
---|
| 11 | | The license and distribution terms for this file may be | |
---|
| 12 | | found in the file LICENSE in this distribution or at | |
---|
| 13 | | | |
---|
[c499856] | 14 | | http://www.rtems.org/license/LICENSE. | |
---|
[267c7c5] | 15 | | | |
---|
| 16 | +-----------------------------------------------------------------+ |
---|
| 17 | | this file contains the MPC83xx I2C driver | |
---|
| 18 | \*===============================================================*/ |
---|
| 19 | #include <stdlib.h> |
---|
| 20 | #include <bsp.h> |
---|
| 21 | #include <bsp/irq.h> |
---|
[28fb9059] | 22 | #include <mpc83xx/mpc83xx_i2cdrv.h> |
---|
[267c7c5] | 23 | #include <rtems/error.h> |
---|
| 24 | #include <rtems/bspIo.h> |
---|
| 25 | #include <errno.h> |
---|
| 26 | #include <rtems/libi2c.h> |
---|
| 27 | |
---|
[e0abba9e] | 28 | #undef DEBUG |
---|
[267c7c5] | 29 | |
---|
[e5a79e54] | 30 | #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H) |
---|
[fe5d5048] | 31 | #define I2CCR_MEN (1 << 7) /* module enable */ |
---|
| 32 | #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H) |
---|
| 33 | #define I2CCR_MDIS (1 << 7) /* module disable */ |
---|
| 34 | #endif |
---|
| 35 | #define I2CCR_MIEN (1 << 6) /* module interrupt enable */ |
---|
| 36 | #define I2CCR_MSTA (1 << 5) /* 0->1 generates a start condiiton, 1->0 a stop */ |
---|
| 37 | #define I2CCR_MTX (1 << 4) /* 0 = receive mode, 1 = transmit mode */ |
---|
| 38 | #define I2CCR_TXAK (1 << 3) /* 0 = send ack 1 = send nak during receive */ |
---|
| 39 | #define I2CCR_RSTA (1 << 2) /* 1 = send repeated start condition */ |
---|
| 40 | #define I2CCR_BCST (1 << 0) /* 0 = disable 1 = enable broadcast accept */ |
---|
| 41 | |
---|
| 42 | #define I2CSR_MCF (1 << 7) /* data transfer (0=transfer in progres) */ |
---|
| 43 | #define I2CSR_MAAS (1 << 6) /* addessed as slave */ |
---|
| 44 | #define I2CSR_MBB (1 << 5) /* bus busy */ |
---|
| 45 | #define I2CSR_MAL (1 << 4) /* arbitration lost */ |
---|
| 46 | #define I2CSR_BCSTM (1 << 3) /* broadcast match */ |
---|
| 47 | #define I2CSR_SRW (1 << 2) /* slave read/write */ |
---|
| 48 | #define I2CSR_MIF (1 << 1) /* module interrupt */ |
---|
| 49 | #define I2CSR_RXAK (1 << 0) /* receive acknowledge */ |
---|
| 50 | |
---|
[267c7c5] | 51 | /*=========================================================================*\ |
---|
| 52 | | Function: | |
---|
| 53 | \*-------------------------------------------------------------------------*/ |
---|
[42bf1b9] | 54 | static rtems_status_code mpc83xx_i2c_find_clock_divider |
---|
[267c7c5] | 55 | ( |
---|
| 56 | /*-------------------------------------------------------------------------*\ |
---|
| 57 | | Purpose: | |
---|
| 58 | | determine proper divider value | |
---|
| 59 | +---------------------------------------------------------------------------+ |
---|
| 60 | | Input Parameters: | |
---|
| 61 | \*-------------------------------------------------------------------------*/ |
---|
| 62 | uint8_t *result, /* result value */ |
---|
| 63 | int divider /* requested divider */ |
---|
| 64 | ) |
---|
| 65 | /*-------------------------------------------------------------------------*\ |
---|
| 66 | | Return Value: | |
---|
| 67 | | o = ok or error code | |
---|
| 68 | \*=========================================================================*/ |
---|
| 69 | { |
---|
| 70 | int i; |
---|
| 71 | int fdr_val; |
---|
[42bf1b9] | 72 | rtems_status_code sc = RTEMS_SUCCESSFUL; |
---|
[267c7c5] | 73 | struct { |
---|
| 74 | int divider; |
---|
| 75 | int fdr_val; |
---|
| 76 | } dividers[] ={ |
---|
[e5a79e54] | 77 | #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H) |
---|
[359e537] | 78 | { 256,0x20 }, { 288,0x21 }, { 320,0x22 }, { 352,0x23 }, |
---|
[267c7c5] | 79 | { 384,0x00 }, { 416,0x01 }, { 448,0x25 }, { 480,0x02 }, |
---|
| 80 | { 512,0x26 }, { 576,0x03 }, { 640,0x04 }, { 704,0x05 }, |
---|
| 81 | { 768,0x29 }, { 832,0x06 }, { 896,0x2a }, { 1024,0x07 }, |
---|
| 82 | { 1152,0x08 }, { 1280,0x09 }, { 1536,0x0A }, { 1792,0x2E }, |
---|
| 83 | { 1920,0x0B }, { 2048,0x2F }, { 2304,0x0C }, { 2560,0x0D }, |
---|
| 84 | { 3072,0x0E }, { 3584,0x32 }, { 3840,0x0F }, { 4096,0x33 }, |
---|
| 85 | { 4608,0x10 }, { 5120,0x11 }, { 6144,0x12 }, { 7168,0x36 }, |
---|
| 86 | { 7680,0x13 }, { 8192,0x37 }, { 9216,0x14 }, {10240,0x15 }, |
---|
| 87 | {12288,0x16 }, {14336,0x3A }, {15360,0x17 }, {16384,0x3B }, |
---|
| 88 | {18432,0x18 }, {20480,0x19 }, {24576,0x1A }, {28672,0x3E }, |
---|
| 89 | {30720,0x1B }, {32768,0x3F }, {36864,0x1C }, {40960,0x1D }, |
---|
| 90 | {49152,0x1E }, {61440,0x1F } |
---|
[fe5d5048] | 91 | #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H) |
---|
| 92 | { 768, 0x31 } |
---|
| 93 | #endif |
---|
[267c7c5] | 94 | }; |
---|
| 95 | |
---|
[42bf1b9] | 96 | if (divider <= 0) { |
---|
| 97 | sc = RTEMS_INVALID_NUMBER; |
---|
[267c7c5] | 98 | } |
---|
[42bf1b9] | 99 | |
---|
| 100 | if (sc == RTEMS_SUCCESSFUL) { |
---|
| 101 | sc = RTEMS_INVALID_NUMBER; |
---|
| 102 | for (i = 0, fdr_val = -1; i < sizeof(dividers)/sizeof(dividers[0]); i++) { |
---|
| 103 | fdr_val = dividers[i].fdr_val; |
---|
| 104 | if (dividers[i].divider >= divider) |
---|
| 105 | { |
---|
| 106 | sc = RTEMS_SUCCESSFUL; |
---|
| 107 | *result = fdr_val; |
---|
| 108 | break; |
---|
| 109 | } |
---|
| 110 | } |
---|
| 111 | } |
---|
| 112 | return sc; |
---|
[267c7c5] | 113 | } |
---|
| 114 | |
---|
| 115 | /*=========================================================================*\ |
---|
| 116 | | Function: | |
---|
| 117 | \*-------------------------------------------------------------------------*/ |
---|
| 118 | static int mpc83xx_i2c_wait |
---|
| 119 | ( |
---|
| 120 | /*-------------------------------------------------------------------------*\ |
---|
| 121 | | Purpose: | |
---|
| 122 | | wait for i2c to become idle | |
---|
| 123 | +---------------------------------------------------------------------------+ |
---|
| 124 | | Input Parameters: | |
---|
| 125 | \*-------------------------------------------------------------------------*/ |
---|
| 126 | mpc83xx_i2c_softc_t *softc_ptr, /* handle */ |
---|
| 127 | uint8_t desired_status, /* desired status word */ |
---|
| 128 | uint8_t status_mask /* status word mask */ |
---|
| 129 | ) |
---|
| 130 | /*-------------------------------------------------------------------------*\ |
---|
| 131 | | Return Value: | |
---|
| 132 | | o = ok or error code | |
---|
| 133 | \*=========================================================================*/ |
---|
| 134 | { |
---|
| 135 | uint8_t act_status; |
---|
| 136 | rtems_status_code rc; |
---|
| 137 | uint32_t tout; |
---|
| 138 | |
---|
| 139 | #if defined(DEBUG) |
---|
| 140 | printk("mpc83xx_i2c_wait called... "); |
---|
| 141 | #endif |
---|
| 142 | |
---|
| 143 | if (softc_ptr->initialized) { |
---|
[55a685b] | 144 | /* |
---|
[359e537] | 145 | * enable interrupt mask |
---|
[55a685b] | 146 | */ |
---|
[fe5d5048] | 147 | softc_ptr->reg_ptr->i2ccr |= I2CCR_MIEN; |
---|
[267c7c5] | 148 | rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100); |
---|
| 149 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 150 | return rc; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | else { |
---|
| 154 | tout = 0; |
---|
| 155 | do { |
---|
| 156 | if (tout++ > 1000000) { |
---|
| 157 | #if defined(DEBUG) |
---|
| 158 | printk("... exit with RTEMS_TIMEOUT\r\n"); |
---|
| 159 | #endif |
---|
| 160 | return RTEMS_TIMEOUT; |
---|
| 161 | } |
---|
[fe5d5048] | 162 | } while (!(softc_ptr->reg_ptr->i2csr & I2CSR_MIF)); |
---|
[267c7c5] | 163 | } |
---|
[fe5d5048] | 164 | softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MIEN; |
---|
[267c7c5] | 165 | |
---|
[55a685b] | 166 | act_status = softc_ptr->reg_ptr->i2csr; |
---|
| 167 | if ((act_status & status_mask) != desired_status) { |
---|
[267c7c5] | 168 | #if defined(DEBUG) |
---|
| 169 | printk("... exit with RTEMS_IO_ERROR\r\n"); |
---|
| 170 | #endif |
---|
| 171 | return RTEMS_IO_ERROR; |
---|
| 172 | } |
---|
| 173 | #if defined(DEBUG) |
---|
| 174 | printk("... exit OK\r\n"); |
---|
| 175 | #endif |
---|
| 176 | return RTEMS_SUCCESSFUL; |
---|
| 177 | } |
---|
| 178 | |
---|
[55a685b] | 179 | /*=========================================================================*\ |
---|
| 180 | | Function: | |
---|
| 181 | \*-------------------------------------------------------------------------*/ |
---|
| 182 | static void mpc83xx_i2c_irq_handler |
---|
| 183 | ( |
---|
| 184 | /*-------------------------------------------------------------------------*\ |
---|
| 185 | | Purpose: | |
---|
| 186 | | handle interrupts | |
---|
| 187 | +---------------------------------------------------------------------------+ |
---|
| 188 | | Input Parameters: | |
---|
| 189 | \*-------------------------------------------------------------------------*/ |
---|
| 190 | rtems_irq_hdl_param handle /* handle, is softc_ptr structure */ |
---|
| 191 | ) |
---|
| 192 | /*-------------------------------------------------------------------------*\ |
---|
| 193 | | Return Value: | |
---|
| 194 | | <none> | |
---|
| 195 | \*=========================================================================*/ |
---|
| 196 | { |
---|
| 197 | mpc83xx_i2c_softc_t *softc_ptr = (mpc83xx_i2c_softc_t *)handle; |
---|
[359e537] | 198 | |
---|
[4b23c94] | 199 | /* |
---|
| 200 | * clear IRQ flag |
---|
| 201 | */ |
---|
[e5a79e54] | 202 | #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H) |
---|
[6d9059f] | 203 | softc_ptr->reg_ptr->i2csr &= ~I2CSR_MIF; |
---|
| 204 | #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H) |
---|
| 205 | softc_ptr->reg_ptr->i2csr = I2CSR_MIF; |
---|
| 206 | #endif |
---|
[4b23c94] | 207 | |
---|
[55a685b] | 208 | /* |
---|
[359e537] | 209 | * disable interrupt mask |
---|
[55a685b] | 210 | */ |
---|
[fe5d5048] | 211 | softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MIEN; |
---|
[55a685b] | 212 | if (softc_ptr->initialized) { |
---|
| 213 | rtems_semaphore_release(softc_ptr->irq_sema_id); |
---|
[359e537] | 214 | } |
---|
[55a685b] | 215 | } |
---|
| 216 | |
---|
| 217 | /*=========================================================================*\ |
---|
| 218 | | Function: | |
---|
| 219 | \*-------------------------------------------------------------------------*/ |
---|
| 220 | static void mpc83xx_i2c_irq_on_off |
---|
| 221 | ( |
---|
| 222 | /*-------------------------------------------------------------------------*\ |
---|
| 223 | | Purpose: | |
---|
| 224 | | enable/disable interrupts (void, handled at different position) | |
---|
| 225 | +---------------------------------------------------------------------------+ |
---|
| 226 | | Input Parameters: | |
---|
| 227 | \*-------------------------------------------------------------------------*/ |
---|
| 228 | const |
---|
| 229 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 230 | ) |
---|
| 231 | /*-------------------------------------------------------------------------*\ |
---|
| 232 | | Return Value: | |
---|
| 233 | | <none> | |
---|
| 234 | \*=========================================================================*/ |
---|
| 235 | { |
---|
| 236 | } |
---|
| 237 | |
---|
| 238 | |
---|
| 239 | /*=========================================================================*\ |
---|
| 240 | | Function: | |
---|
| 241 | \*-------------------------------------------------------------------------*/ |
---|
| 242 | static int mpc83xx_i2c_irq_isOn |
---|
| 243 | ( |
---|
| 244 | /*-------------------------------------------------------------------------*\ |
---|
| 245 | | Purpose: | |
---|
| 246 | | check state of interrupts, void, done differently | |
---|
| 247 | +---------------------------------------------------------------------------+ |
---|
| 248 | | Input Parameters: | |
---|
| 249 | \*-------------------------------------------------------------------------*/ |
---|
| 250 | const |
---|
| 251 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 252 | ) |
---|
| 253 | /*-------------------------------------------------------------------------*\ |
---|
| 254 | | Return Value: | |
---|
| 255 | | TRUE, if enabled | |
---|
| 256 | \*=========================================================================*/ |
---|
| 257 | { |
---|
| 258 | return (TRUE); |
---|
| 259 | } |
---|
| 260 | |
---|
| 261 | /*=========================================================================*\ |
---|
| 262 | | Function: | |
---|
| 263 | \*-------------------------------------------------------------------------*/ |
---|
| 264 | static void mpc83xx_i2c_install_irq_handler |
---|
| 265 | ( |
---|
| 266 | /*-------------------------------------------------------------------------*\ |
---|
| 267 | | Purpose: | |
---|
| 268 | | (un-)install the interrupt handler | |
---|
| 269 | +---------------------------------------------------------------------------+ |
---|
| 270 | | Input Parameters: | |
---|
| 271 | \*-------------------------------------------------------------------------*/ |
---|
| 272 | mpc83xx_i2c_softc_t *softc_ptr, /* ptr to control structure */ |
---|
| 273 | int install /* TRUE: install, FALSE: remove */ |
---|
| 274 | ) |
---|
| 275 | /*-------------------------------------------------------------------------*\ |
---|
| 276 | | Return Value: | |
---|
| 277 | | <none> | |
---|
| 278 | \*=========================================================================*/ |
---|
| 279 | { |
---|
| 280 | rtems_status_code rc = RTEMS_SUCCESSFUL; |
---|
| 281 | |
---|
| 282 | rtems_irq_connect_data irq_conn_data = { |
---|
| 283 | softc_ptr->irq_number, |
---|
| 284 | mpc83xx_i2c_irq_handler, /* rtems_irq_hdl */ |
---|
| 285 | (rtems_irq_hdl_param)softc_ptr, /* (rtems_irq_hdl_param) */ |
---|
| 286 | mpc83xx_i2c_irq_on_off, /* (rtems_irq_enable) */ |
---|
| 287 | mpc83xx_i2c_irq_on_off, /* (rtems_irq_disable) */ |
---|
| 288 | mpc83xx_i2c_irq_isOn /* (rtems_irq_is_enabled) */ |
---|
| 289 | }; |
---|
| 290 | |
---|
| 291 | /* |
---|
| 292 | * (un-)install handler for I2C device |
---|
| 293 | */ |
---|
| 294 | if (install) { |
---|
| 295 | /* |
---|
| 296 | * create semaphore for IRQ synchronization |
---|
| 297 | */ |
---|
| 298 | rc = rtems_semaphore_create(rtems_build_name('i','2','c','s'), |
---|
| 299 | 0, |
---|
[359e537] | 300 | RTEMS_FIFO |
---|
[55a685b] | 301 | | RTEMS_SIMPLE_BINARY_SEMAPHORE, |
---|
| 302 | 0, |
---|
| 303 | &softc_ptr->irq_sema_id); |
---|
| 304 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 305 | rtems_panic("I2C: cannot create semaphore"); |
---|
| 306 | } |
---|
| 307 | if (!BSP_install_rtems_irq_handler (&irq_conn_data)) { |
---|
| 308 | rtems_panic("I2C: cannot install IRQ handler"); |
---|
| 309 | } |
---|
| 310 | } |
---|
| 311 | else { |
---|
| 312 | if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) { |
---|
| 313 | rtems_panic("I2C: cannot uninstall IRQ handler"); |
---|
| 314 | } |
---|
| 315 | /* |
---|
| 316 | * delete sync semaphore |
---|
| 317 | */ |
---|
| 318 | if (softc_ptr->irq_sema_id != 0) { |
---|
| 319 | rc = rtems_semaphore_delete(softc_ptr->irq_sema_id); |
---|
| 320 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 321 | rtems_panic("I2C: cannot delete semaphore"); |
---|
| 322 | } |
---|
| 323 | } |
---|
| 324 | } |
---|
| 325 | } |
---|
| 326 | |
---|
[267c7c5] | 327 | /*=========================================================================*\ |
---|
| 328 | | Function: | |
---|
| 329 | \*-------------------------------------------------------------------------*/ |
---|
| 330 | static rtems_status_code mpc83xx_i2c_init |
---|
| 331 | ( |
---|
| 332 | /*-------------------------------------------------------------------------*\ |
---|
| 333 | | Purpose: | |
---|
| 334 | | initialize the driver | |
---|
| 335 | +---------------------------------------------------------------------------+ |
---|
| 336 | | Input Parameters: | |
---|
| 337 | \*-------------------------------------------------------------------------*/ |
---|
| 338 | rtems_libi2c_bus_t *bh /* bus specifier structure */ |
---|
| 339 | ) |
---|
| 340 | /*-------------------------------------------------------------------------*\ |
---|
| 341 | | Return Value: | |
---|
| 342 | | o = ok or error code | |
---|
| 343 | \*=========================================================================*/ |
---|
| 344 | { |
---|
| 345 | mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc); |
---|
| 346 | uint8_t fdr_val; |
---|
| 347 | int errval; |
---|
| 348 | #if defined(DEBUG) |
---|
| 349 | printk("mpc83xx_i2c_init called... "); |
---|
| 350 | #endif |
---|
| 351 | /* |
---|
| 352 | * init HW registers |
---|
| 353 | */ |
---|
| 354 | /* |
---|
| 355 | * init frequency divider to 100kHz |
---|
| 356 | */ |
---|
| 357 | errval = mpc83xx_i2c_find_clock_divider(&fdr_val, |
---|
[42bf1b9] | 358 | softc_ptr->base_frq/100000); |
---|
[267c7c5] | 359 | if (errval != 0) { |
---|
| 360 | return errval; |
---|
| 361 | } |
---|
| 362 | softc_ptr->reg_ptr->i2cfdr = fdr_val; |
---|
| 363 | /* |
---|
| 364 | * init digital filter sampling rate |
---|
| 365 | */ |
---|
| 366 | softc_ptr->reg_ptr->i2cdfsrr = 0x10 ; /* no special filtering needed */ |
---|
| 367 | /* |
---|
[55a685b] | 368 | * set own slave address to broadcast (0x00) |
---|
[267c7c5] | 369 | */ |
---|
[359e537] | 370 | softc_ptr->reg_ptr->i2cadr = 0x00 ; |
---|
[267c7c5] | 371 | |
---|
| 372 | /* |
---|
| 373 | * set control register to module enable |
---|
| 374 | */ |
---|
[e5a79e54] | 375 | #if defined(LIBBSP_POWERPC_GEN83XX_BSP_H) |
---|
[fe5d5048] | 376 | softc_ptr->reg_ptr->i2ccr = I2CCR_MEN; |
---|
| 377 | #elif defined(LIBBSP_POWERPC_MPC55XXEVB_BSP_H) |
---|
| 378 | softc_ptr->reg_ptr->i2ccr = 0; |
---|
| 379 | #endif |
---|
[359e537] | 380 | |
---|
[267c7c5] | 381 | /* |
---|
[55a685b] | 382 | * init interrupt stuff |
---|
| 383 | */ |
---|
| 384 | mpc83xx_i2c_install_irq_handler(softc_ptr,TRUE); |
---|
| 385 | |
---|
[267c7c5] | 386 | /* |
---|
[55a685b] | 387 | * mark, that we have initialized |
---|
[267c7c5] | 388 | */ |
---|
[55a685b] | 389 | softc_ptr->initialized = TRUE; |
---|
[267c7c5] | 390 | #if defined(DEBUG) |
---|
| 391 | printk("... exit OK\r\n"); |
---|
| 392 | #endif |
---|
| 393 | return RTEMS_SUCCESSFUL; |
---|
| 394 | } |
---|
| 395 | |
---|
| 396 | /*=========================================================================*\ |
---|
| 397 | | Function: | |
---|
| 398 | \*-------------------------------------------------------------------------*/ |
---|
| 399 | static rtems_status_code mpc83xx_i2c_send_start |
---|
| 400 | ( |
---|
| 401 | /*-------------------------------------------------------------------------*\ |
---|
| 402 | | Purpose: | |
---|
| 403 | | send a start condition to bus | |
---|
| 404 | +---------------------------------------------------------------------------+ |
---|
| 405 | | Input Parameters: | |
---|
| 406 | \*-------------------------------------------------------------------------*/ |
---|
| 407 | rtems_libi2c_bus_t *bh /* bus specifier structure */ |
---|
| 408 | ) |
---|
| 409 | /*-------------------------------------------------------------------------*\ |
---|
| 410 | | Return Value: | |
---|
| 411 | | o = ok or error code | |
---|
| 412 | \*=========================================================================*/ |
---|
| 413 | { |
---|
| 414 | mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc); |
---|
| 415 | |
---|
| 416 | #if defined(DEBUG) |
---|
| 417 | printk("mpc83xx_i2c_send_start called... "); |
---|
| 418 | #endif |
---|
[fe5d5048] | 419 | if (0 != (softc_ptr->reg_ptr->i2ccr & I2CCR_MSTA)) { |
---|
[267c7c5] | 420 | /* |
---|
[359e537] | 421 | * already started, so send a "repeated start" |
---|
[267c7c5] | 422 | */ |
---|
[fe5d5048] | 423 | softc_ptr->reg_ptr->i2ccr |= I2CCR_RSTA; |
---|
[267c7c5] | 424 | } |
---|
| 425 | else { |
---|
[fe5d5048] | 426 | softc_ptr->reg_ptr->i2ccr |= I2CCR_MSTA; |
---|
[267c7c5] | 427 | } |
---|
| 428 | |
---|
| 429 | #if defined(DEBUG) |
---|
| 430 | printk("... exit OK\r\n"); |
---|
| 431 | #endif |
---|
| 432 | return 0; |
---|
| 433 | } |
---|
| 434 | |
---|
| 435 | /*=========================================================================*\ |
---|
| 436 | | Function: | |
---|
| 437 | \*-------------------------------------------------------------------------*/ |
---|
| 438 | static rtems_status_code mpc83xx_i2c_send_stop |
---|
| 439 | ( |
---|
| 440 | /*-------------------------------------------------------------------------*\ |
---|
| 441 | | Purpose: | |
---|
| 442 | | send a stop condition to bus | |
---|
| 443 | +---------------------------------------------------------------------------+ |
---|
| 444 | | Input Parameters: | |
---|
| 445 | \*-------------------------------------------------------------------------*/ |
---|
| 446 | rtems_libi2c_bus_t *bh /* bus specifier structure */ |
---|
| 447 | ) |
---|
| 448 | /*-------------------------------------------------------------------------*\ |
---|
| 449 | | Return Value: | |
---|
| 450 | | o = ok or error code | |
---|
| 451 | \*=========================================================================*/ |
---|
| 452 | { |
---|
| 453 | mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc); |
---|
| 454 | |
---|
| 455 | #if defined(DEBUG) |
---|
| 456 | printk("mpc83xx_i2c_send_stop called... "); |
---|
| 457 | #endif |
---|
[fe5d5048] | 458 | softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MSTA; |
---|
[39dfbe16] | 459 | /* |
---|
| 460 | * wait, 'til stop has been executed |
---|
| 461 | */ |
---|
[fe5d5048] | 462 | while (0 != (softc_ptr->reg_ptr->i2csr & I2CSR_MBB)) { |
---|
[39dfbe16] | 463 | rtems_task_wake_after(RTEMS_YIELD_PROCESSOR); |
---|
| 464 | } |
---|
[267c7c5] | 465 | #if defined(DEBUG) |
---|
| 466 | printk("... exit OK\r\n"); |
---|
| 467 | #endif |
---|
| 468 | return 0; |
---|
| 469 | } |
---|
| 470 | |
---|
| 471 | /*=========================================================================*\ |
---|
| 472 | | Function: | |
---|
| 473 | \*-------------------------------------------------------------------------*/ |
---|
| 474 | static rtems_status_code mpc83xx_i2c_send_addr |
---|
| 475 | ( |
---|
| 476 | /*-------------------------------------------------------------------------*\ |
---|
| 477 | | Purpose: | |
---|
| 478 | | address a slave device on the bus | |
---|
| 479 | +---------------------------------------------------------------------------+ |
---|
| 480 | | Input Parameters: | |
---|
| 481 | \*-------------------------------------------------------------------------*/ |
---|
| 482 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 483 | uint32_t addr, /* address to send on bus */ |
---|
| 484 | int rw /* 0=write,1=read */ |
---|
| 485 | ) |
---|
| 486 | /*-------------------------------------------------------------------------*\ |
---|
| 487 | | Return Value: | |
---|
| 488 | | o = ok or error code | |
---|
| 489 | \*=========================================================================*/ |
---|
| 490 | { |
---|
| 491 | mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc); |
---|
| 492 | uint8_t addr_byte; |
---|
| 493 | rtems_status_code rc; |
---|
| 494 | |
---|
| 495 | #if defined(DEBUG) |
---|
| 496 | printk("mpc83xx_i2c_send_addr called... "); |
---|
| 497 | #endif |
---|
[fe5d5048] | 498 | softc_ptr->reg_ptr->i2ccr |= I2CCR_MTX; |
---|
[267c7c5] | 499 | /* |
---|
| 500 | * determine, whether short or long address is needed, determine rd/wr |
---|
| 501 | */ |
---|
| 502 | if (addr > 0x7f) { |
---|
[359e537] | 503 | addr_byte = (0xf0 |
---|
[267c7c5] | 504 | | ((addr >> 7) & 0x06) |
---|
| 505 | | ((rw) ? 1 : 0)); |
---|
| 506 | /* |
---|
[359e537] | 507 | * send first byte |
---|
[267c7c5] | 508 | */ |
---|
| 509 | softc_ptr->reg_ptr->i2cdr = addr_byte; |
---|
| 510 | /* |
---|
| 511 | * wait for successful transfer |
---|
| 512 | */ |
---|
[fe5d5048] | 513 | rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | I2CSR_RXAK); |
---|
[267c7c5] | 514 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 515 | #if defined(DEBUG) |
---|
| 516 | printk("... exit rc=%d\r\n",rc); |
---|
| 517 | #endif |
---|
| 518 | return rc; |
---|
| 519 | } |
---|
| 520 | } |
---|
| 521 | /* |
---|
[359e537] | 522 | * send (final) byte |
---|
[267c7c5] | 523 | */ |
---|
[359e537] | 524 | addr_byte = ((addr << 1) |
---|
[267c7c5] | 525 | | ((rw) ? 1 : 0)); |
---|
| 526 | |
---|
| 527 | softc_ptr->reg_ptr->i2cdr = addr_byte; |
---|
| 528 | /* |
---|
| 529 | * wait for successful transfer |
---|
| 530 | */ |
---|
[fe5d5048] | 531 | rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | I2CSR_RXAK); |
---|
[267c7c5] | 532 | |
---|
| 533 | #if defined(DEBUG) |
---|
| 534 | printk("... exit rc=%d\r\n",rc); |
---|
| 535 | #endif |
---|
| 536 | return rc; |
---|
| 537 | } |
---|
| 538 | |
---|
| 539 | /*=========================================================================*\ |
---|
| 540 | | Function: | |
---|
| 541 | \*-------------------------------------------------------------------------*/ |
---|
| 542 | static int mpc83xx_i2c_read_bytes |
---|
| 543 | ( |
---|
| 544 | /*-------------------------------------------------------------------------*\ |
---|
| 545 | | Purpose: | |
---|
| 546 | | receive some bytes from I2C device | |
---|
| 547 | +---------------------------------------------------------------------------+ |
---|
| 548 | | Input Parameters: | |
---|
| 549 | \*-------------------------------------------------------------------------*/ |
---|
| 550 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 551 | unsigned char *buf, /* buffer to store bytes */ |
---|
| 552 | int len /* number of bytes to receive */ |
---|
| 553 | ) |
---|
| 554 | /*-------------------------------------------------------------------------*\ |
---|
| 555 | | Return Value: | |
---|
| 556 | | number of bytes received or (negative) error code | |
---|
| 557 | \*=========================================================================*/ |
---|
| 558 | { |
---|
| 559 | mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc); |
---|
| 560 | rtems_status_code rc; |
---|
| 561 | unsigned char *p = buf; |
---|
| 562 | |
---|
| 563 | #if defined(DEBUG) |
---|
| 564 | printk("mpc83xx_i2c_read_bytes called... "); |
---|
| 565 | #endif |
---|
[fe5d5048] | 566 | softc_ptr->reg_ptr->i2ccr &= ~I2CCR_MTX; |
---|
| 567 | softc_ptr->reg_ptr->i2ccr &= ~I2CCR_TXAK; |
---|
[42bf1b9] | 568 | /* |
---|
[359e537] | 569 | * FIXME: do we need to deactivate TXAK from the start, |
---|
[42bf1b9] | 570 | * when only one byte is to be received? |
---|
| 571 | */ |
---|
[267c7c5] | 572 | /* |
---|
| 573 | * we need a dummy transfer here to start the first read |
---|
| 574 | */ |
---|
[339646e] | 575 | softc_ptr->reg_ptr->i2cdr; |
---|
[267c7c5] | 576 | |
---|
| 577 | while (len-- > 0) { |
---|
| 578 | if (len == 0) { |
---|
| 579 | /* |
---|
| 580 | * last byte is not acknowledged |
---|
| 581 | */ |
---|
[fe5d5048] | 582 | softc_ptr->reg_ptr->i2ccr |= I2CCR_TXAK; |
---|
[267c7c5] | 583 | } |
---|
| 584 | /* |
---|
| 585 | * wait 'til end of transfer |
---|
| 586 | */ |
---|
[fe5d5048] | 587 | rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF); |
---|
[267c7c5] | 588 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 589 | #if defined(DEBUG) |
---|
| 590 | printk("... exit rc=%d\r\n",-rc); |
---|
| 591 | #endif |
---|
| 592 | return -rc; |
---|
| 593 | } |
---|
| 594 | *p++ = softc_ptr->reg_ptr->i2cdr; |
---|
[359e537] | 595 | |
---|
[267c7c5] | 596 | } |
---|
[4b23c94] | 597 | |
---|
| 598 | /* |
---|
| 599 | * wait 'til end of last transfer |
---|
| 600 | */ |
---|
[fe5d5048] | 601 | rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF); |
---|
[4b23c94] | 602 | |
---|
[267c7c5] | 603 | #if defined(DEBUG) |
---|
| 604 | printk("... exit OK, rc=%d\r\n",p-buf); |
---|
| 605 | #endif |
---|
| 606 | return p - buf; |
---|
| 607 | } |
---|
| 608 | |
---|
| 609 | /*=========================================================================*\ |
---|
| 610 | | Function: | |
---|
| 611 | \*-------------------------------------------------------------------------*/ |
---|
| 612 | static int mpc83xx_i2c_write_bytes |
---|
| 613 | ( |
---|
| 614 | /*-------------------------------------------------------------------------*\ |
---|
| 615 | | Purpose: | |
---|
| 616 | | send some bytes to I2C device | |
---|
| 617 | +---------------------------------------------------------------------------+ |
---|
| 618 | | Input Parameters: | |
---|
| 619 | \*-------------------------------------------------------------------------*/ |
---|
| 620 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 621 | unsigned char *buf, /* buffer to send */ |
---|
| 622 | int len /* number of bytes to send */ |
---|
| 623 | |
---|
| 624 | ) |
---|
| 625 | /*-------------------------------------------------------------------------*\ |
---|
| 626 | | Return Value: | |
---|
| 627 | | number of bytes sent or (negative) error code | |
---|
| 628 | \*=========================================================================*/ |
---|
| 629 | { |
---|
| 630 | mpc83xx_i2c_softc_t *softc_ptr = &(((mpc83xx_i2c_desc_t *)(bh))->softc); |
---|
| 631 | rtems_status_code rc; |
---|
| 632 | unsigned char *p = buf; |
---|
| 633 | |
---|
| 634 | #if defined(DEBUG) |
---|
| 635 | printk("mpc83xx_i2c_write_bytes called... "); |
---|
| 636 | #endif |
---|
[359e537] | 637 | softc_ptr->reg_ptr->i2ccr = |
---|
[fe5d5048] | 638 | (softc_ptr->reg_ptr->i2ccr & ~I2CCR_TXAK) | I2CCR_MTX; |
---|
[267c7c5] | 639 | while (len-- > 0) { |
---|
[fe5d5048] | 640 | int rxack = len != 0 ? I2CSR_RXAK : 0; |
---|
| 641 | |
---|
[267c7c5] | 642 | softc_ptr->reg_ptr->i2cdr = *p++; |
---|
| 643 | /* |
---|
| 644 | * wait 'til end of transfer |
---|
| 645 | */ |
---|
[fe5d5048] | 646 | rc = mpc83xx_i2c_wait(softc_ptr, I2CSR_MCF, I2CSR_MCF | rxack); |
---|
[267c7c5] | 647 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 648 | #if defined(DEBUG) |
---|
| 649 | printk("... exit rc=%d\r\n",-rc); |
---|
| 650 | #endif |
---|
| 651 | return -rc; |
---|
| 652 | } |
---|
| 653 | } |
---|
| 654 | #if defined(DEBUG) |
---|
| 655 | printk("... exit OK, rc=%d\r\n",p-buf); |
---|
| 656 | #endif |
---|
| 657 | return p - buf; |
---|
| 658 | } |
---|
| 659 | |
---|
| 660 | rtems_libi2c_bus_ops_t mpc83xx_i2c_ops = { |
---|
[574fb67] | 661 | .init = mpc83xx_i2c_init, |
---|
| 662 | .send_start = mpc83xx_i2c_send_start, |
---|
| 663 | .send_stop = mpc83xx_i2c_send_stop, |
---|
| 664 | .send_addr = mpc83xx_i2c_send_addr, |
---|
| 665 | .read_bytes = mpc83xx_i2c_read_bytes, |
---|
| 666 | .write_bytes = mpc83xx_i2c_write_bytes, |
---|
[267c7c5] | 667 | }; |
---|
| 668 | |
---|