[7edabaf] | 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. | |
---|
[7edabaf] | 15 | | | |
---|
| 16 | +-----------------------------------------------------------------+ |
---|
| 17 | | this file contains the MPC83xx SPI driver | |
---|
| 18 | | NOTE: it uses the same API as the I2C driver | |
---|
| 19 | \*===============================================================*/ |
---|
| 20 | #include <stdlib.h> |
---|
| 21 | #include <bsp.h> |
---|
| 22 | #include <bsp/irq.h> |
---|
| 23 | #include <mpc83xx/mpc83xx.h> |
---|
| 24 | #include <mpc83xx/mpc83xx_spidrv.h> |
---|
| 25 | #include <rtems/error.h> |
---|
| 26 | #include <rtems/bspIo.h> |
---|
| 27 | #include <errno.h> |
---|
| 28 | #include <rtems/libi2c.h> |
---|
| 29 | |
---|
| 30 | #undef DEBUG |
---|
| 31 | |
---|
| 32 | /*=========================================================================*\ |
---|
| 33 | | Function: | |
---|
| 34 | \*-------------------------------------------------------------------------*/ |
---|
| 35 | static rtems_status_code mpc83xx_spi_baud_to_mode |
---|
| 36 | ( |
---|
| 37 | /*-------------------------------------------------------------------------*\ |
---|
| 38 | | Purpose: | |
---|
| 39 | | determine proper divider value | |
---|
| 40 | +---------------------------------------------------------------------------+ |
---|
| 41 | | Input Parameters: | |
---|
| 42 | \*-------------------------------------------------------------------------*/ |
---|
| 43 | uint32_t baudrate, /* desired baudrate */ |
---|
[42bf1b9] | 44 | uint32_t base_frq, /* input frequency */ |
---|
[7edabaf] | 45 | uint32_t *spimode /* result value */ |
---|
| 46 | ) |
---|
| 47 | /*-------------------------------------------------------------------------*\ |
---|
| 48 | | Return Value: | |
---|
| 49 | | o = ok or error code | |
---|
| 50 | \*=========================================================================*/ |
---|
| 51 | { |
---|
| 52 | uint32_t divider; |
---|
| 53 | uint32_t tmpmode = 0; |
---|
| 54 | /* |
---|
| 55 | * determine clock divider and DIV16 bit |
---|
| 56 | */ |
---|
[42bf1b9] | 57 | divider = (base_frq+baudrate-1)/baudrate; |
---|
[7edabaf] | 58 | if (divider > 64) { |
---|
| 59 | tmpmode = MPC83XX_SPIMODE_DIV16; |
---|
| 60 | divider /= 16; |
---|
| 61 | } |
---|
| 62 | if ((divider < 1) || |
---|
| 63 | (divider > 64)) { |
---|
| 64 | return RTEMS_INVALID_NUMBER; |
---|
| 65 | } |
---|
| 66 | else { |
---|
| 67 | tmpmode |= MPC83XX_SPIMODE_PM(divider/4-1); |
---|
| 68 | } |
---|
| 69 | *spimode = tmpmode; |
---|
| 70 | return RTEMS_SUCCESSFUL; |
---|
| 71 | } |
---|
| 72 | |
---|
| 73 | /*=========================================================================*\ |
---|
| 74 | | Function: | |
---|
| 75 | \*-------------------------------------------------------------------------*/ |
---|
| 76 | static rtems_status_code mpc83xx_spi_char_mode |
---|
| 77 | ( |
---|
| 78 | /*-------------------------------------------------------------------------*\ |
---|
| 79 | | Purpose: | |
---|
| 80 | | determine proper value for character size | |
---|
| 81 | +---------------------------------------------------------------------------+ |
---|
| 82 | | Input Parameters: | |
---|
| 83 | \*-------------------------------------------------------------------------*/ |
---|
| 84 | mpc83xx_spi_softc_t *softc_ptr, /* handle */ |
---|
| 85 | uint32_t bits_per_char, /* bits per character */ |
---|
[39d08d55] | 86 | bool lsb_first, /* TRUE: send LSB first */ |
---|
[7edabaf] | 87 | uint32_t *spimode /* result value */ |
---|
| 88 | ) |
---|
| 89 | /*-------------------------------------------------------------------------*\ |
---|
| 90 | | Return Value: | |
---|
| 91 | | o = ok or error code | |
---|
| 92 | \*=========================================================================*/ |
---|
| 93 | { |
---|
| 94 | uint32_t tmpmode; |
---|
| 95 | |
---|
| 96 | if (bits_per_char == 32) { |
---|
| 97 | tmpmode = 0; |
---|
| 98 | softc_ptr->bytes_per_char = 4; |
---|
| 99 | softc_ptr->bit_shift = 0; |
---|
| 100 | } |
---|
| 101 | else { |
---|
| 102 | if (lsb_first) { |
---|
| 103 | /* |
---|
[359e537] | 104 | * non-reversed data (LSB first): 4..16 bits valid |
---|
[7edabaf] | 105 | * always aligned to bit 16 of data register |
---|
| 106 | */ |
---|
| 107 | if ((bits_per_char >= 4) && |
---|
| 108 | (bits_per_char <= 16)) { |
---|
| 109 | tmpmode = MPC83XX_SPIMODE_LEN( bits_per_char-1); |
---|
| 110 | softc_ptr->bytes_per_char = (bits_per_char > 8) ? 2 : 1; |
---|
| 111 | softc_ptr->bit_shift = 16-bits_per_char; |
---|
| 112 | } |
---|
| 113 | else { |
---|
| 114 | return RTEMS_INVALID_NUMBER; |
---|
| 115 | } |
---|
| 116 | } |
---|
| 117 | else { |
---|
| 118 | /* |
---|
| 119 | * reversed data (MSB first): only 8/16/32 bits valid, |
---|
| 120 | * always in lowest bits of data register |
---|
| 121 | */ |
---|
| 122 | if (bits_per_char == 8) { |
---|
| 123 | tmpmode = MPC83XX_SPIMODE_LEN(8-1); |
---|
| 124 | softc_ptr->bytes_per_char = 1; |
---|
| 125 | softc_ptr->bit_shift = 0; |
---|
| 126 | } |
---|
| 127 | else if (bits_per_char == 16) { |
---|
| 128 | tmpmode = MPC83XX_SPIMODE_LEN(16-1); |
---|
| 129 | softc_ptr->bytes_per_char = 2; |
---|
| 130 | softc_ptr->bit_shift = 0; |
---|
| 131 | } |
---|
| 132 | else { |
---|
| 133 | return RTEMS_INVALID_NUMBER; |
---|
| 134 | } |
---|
| 135 | } |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | *spimode = tmpmode; |
---|
| 139 | return 0; |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | /*=========================================================================*\ |
---|
| 143 | | Function: | |
---|
| 144 | \*-------------------------------------------------------------------------*/ |
---|
| 145 | static int mpc83xx_spi_wait |
---|
| 146 | ( |
---|
| 147 | /*-------------------------------------------------------------------------*\ |
---|
| 148 | | Purpose: | |
---|
| 149 | | wait for spi to become idle | |
---|
| 150 | +---------------------------------------------------------------------------+ |
---|
| 151 | | Input Parameters: | |
---|
| 152 | \*-------------------------------------------------------------------------*/ |
---|
| 153 | mpc83xx_spi_softc_t *softc_ptr, /* handle */ |
---|
| 154 | uint32_t irq_mask, /* irq mask to use */ |
---|
| 155 | uint32_t desired_status, /* desired status word */ |
---|
| 156 | uint32_t status_mask /* status word mask */ |
---|
| 157 | ) |
---|
| 158 | /*-------------------------------------------------------------------------*\ |
---|
| 159 | | Return Value: | |
---|
| 160 | | o = ok or error code | |
---|
| 161 | \*=========================================================================*/ |
---|
| 162 | { |
---|
| 163 | uint32_t act_status; |
---|
| 164 | rtems_status_code rc; |
---|
| 165 | uint32_t tout; |
---|
| 166 | |
---|
| 167 | #if defined(DEBUG) |
---|
| 168 | printk("mpc83xx_spi_wait called... "); |
---|
| 169 | #endif |
---|
| 170 | if (softc_ptr->initialized) { |
---|
| 171 | /* |
---|
| 172 | * allow interrupts, when receiver is not empty |
---|
| 173 | */ |
---|
| 174 | softc_ptr->reg_ptr->spim = irq_mask; |
---|
| 175 | rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100); |
---|
| 176 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 177 | return rc; |
---|
| 178 | } |
---|
| 179 | } |
---|
| 180 | else { |
---|
| 181 | tout = 0; |
---|
| 182 | do { |
---|
| 183 | if (tout++ > 1000000) { |
---|
| 184 | #if defined(DEBUG) |
---|
| 185 | printk("... exit with RTEMS_TIMEOUT\r\n"); |
---|
| 186 | #endif |
---|
| 187 | return RTEMS_TIMEOUT; |
---|
| 188 | } |
---|
| 189 | /* |
---|
| 190 | * wait for SPI to terminate |
---|
| 191 | */ |
---|
| 192 | } while (!(softc_ptr->reg_ptr->spie & MPC83XX_SPIE_NE)); |
---|
| 193 | } |
---|
| 194 | |
---|
| 195 | act_status = softc_ptr->reg_ptr->spie; |
---|
| 196 | if ((act_status & status_mask)!= desired_status) { |
---|
| 197 | #if defined(DEBUG) |
---|
| 198 | printk("... exit with RTEMS_IO_ERROR," |
---|
| 199 | "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n", |
---|
| 200 | act_status,status_mask,desired_status); |
---|
| 201 | #endif |
---|
| 202 | return RTEMS_IO_ERROR; |
---|
| 203 | } |
---|
| 204 | #if defined(DEBUG) |
---|
| 205 | printk("... exit OK\r\n"); |
---|
| 206 | #endif |
---|
| 207 | return RTEMS_SUCCESSFUL; |
---|
| 208 | } |
---|
| 209 | |
---|
| 210 | /*=========================================================================*\ |
---|
| 211 | | Function: | |
---|
| 212 | \*-------------------------------------------------------------------------*/ |
---|
| 213 | static void mpc83xx_spi_irq_handler |
---|
| 214 | ( |
---|
| 215 | /*-------------------------------------------------------------------------*\ |
---|
| 216 | | Purpose: | |
---|
| 217 | | handle interrupts | |
---|
| 218 | +---------------------------------------------------------------------------+ |
---|
| 219 | | Input Parameters: | |
---|
| 220 | \*-------------------------------------------------------------------------*/ |
---|
| 221 | rtems_irq_hdl_param handle /* handle, is softc_ptr structure */ |
---|
| 222 | ) |
---|
| 223 | /*-------------------------------------------------------------------------*\ |
---|
| 224 | | Return Value: | |
---|
| 225 | | <none> | |
---|
| 226 | \*=========================================================================*/ |
---|
| 227 | { |
---|
| 228 | mpc83xx_spi_softc_t *softc_ptr = (mpc83xx_spi_softc_t *)handle; |
---|
[359e537] | 229 | |
---|
[7edabaf] | 230 | /* |
---|
[359e537] | 231 | * disable interrupt mask |
---|
[7edabaf] | 232 | */ |
---|
| 233 | softc_ptr->reg_ptr->spim = 0; |
---|
| 234 | if (softc_ptr->initialized) { |
---|
| 235 | rtems_semaphore_release(softc_ptr->irq_sema_id); |
---|
[359e537] | 236 | } |
---|
[7edabaf] | 237 | } |
---|
| 238 | |
---|
| 239 | /*=========================================================================*\ |
---|
| 240 | | Function: | |
---|
| 241 | \*-------------------------------------------------------------------------*/ |
---|
| 242 | static void mpc83xx_spi_irq_on_off |
---|
| 243 | ( |
---|
| 244 | /*-------------------------------------------------------------------------*\ |
---|
| 245 | | Purpose: | |
---|
| 246 | | enable/disable interrupts (void, handled at different position) | |
---|
| 247 | +---------------------------------------------------------------------------+ |
---|
| 248 | | Input Parameters: | |
---|
| 249 | \*-------------------------------------------------------------------------*/ |
---|
| 250 | const |
---|
| 251 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 252 | ) |
---|
| 253 | /*-------------------------------------------------------------------------*\ |
---|
| 254 | | Return Value: | |
---|
| 255 | | <none> | |
---|
| 256 | \*=========================================================================*/ |
---|
| 257 | { |
---|
| 258 | } |
---|
| 259 | |
---|
| 260 | |
---|
| 261 | /*=========================================================================*\ |
---|
| 262 | | Function: | |
---|
| 263 | \*-------------------------------------------------------------------------*/ |
---|
| 264 | static int mpc83xx_spi_irq_isOn |
---|
| 265 | ( |
---|
| 266 | /*-------------------------------------------------------------------------*\ |
---|
| 267 | | Purpose: | |
---|
| 268 | | check state of interrupts, void, done differently | |
---|
| 269 | +---------------------------------------------------------------------------+ |
---|
| 270 | | Input Parameters: | |
---|
| 271 | \*-------------------------------------------------------------------------*/ |
---|
| 272 | const |
---|
| 273 | rtems_irq_connect_data *irq_conn_data /* irq connect data */ |
---|
| 274 | ) |
---|
| 275 | /*-------------------------------------------------------------------------*\ |
---|
| 276 | | Return Value: | |
---|
| 277 | | TRUE, if enabled | |
---|
| 278 | \*=========================================================================*/ |
---|
| 279 | { |
---|
| 280 | return (TRUE); |
---|
| 281 | } |
---|
| 282 | |
---|
| 283 | /*=========================================================================*\ |
---|
| 284 | | Function: | |
---|
| 285 | \*-------------------------------------------------------------------------*/ |
---|
| 286 | static void mpc83xx_spi_install_irq_handler |
---|
| 287 | ( |
---|
| 288 | /*-------------------------------------------------------------------------*\ |
---|
| 289 | | Purpose: | |
---|
| 290 | | (un-)install the interrupt handler | |
---|
| 291 | +---------------------------------------------------------------------------+ |
---|
| 292 | | Input Parameters: | |
---|
| 293 | \*-------------------------------------------------------------------------*/ |
---|
| 294 | mpc83xx_spi_softc_t *softc_ptr, /* ptr to control structure */ |
---|
| 295 | int install /* TRUE: install, FALSE: remove */ |
---|
| 296 | ) |
---|
| 297 | /*-------------------------------------------------------------------------*\ |
---|
| 298 | | Return Value: | |
---|
| 299 | | <none> | |
---|
| 300 | \*=========================================================================*/ |
---|
| 301 | { |
---|
| 302 | rtems_status_code rc = RTEMS_SUCCESSFUL; |
---|
| 303 | |
---|
| 304 | rtems_irq_connect_data irq_conn_data = { |
---|
| 305 | softc_ptr->irq_number, |
---|
| 306 | mpc83xx_spi_irq_handler, /* rtems_irq_hdl */ |
---|
| 307 | (rtems_irq_hdl_param)softc_ptr, /* (rtems_irq_hdl_param) */ |
---|
| 308 | mpc83xx_spi_irq_on_off, /* (rtems_irq_enable) */ |
---|
| 309 | mpc83xx_spi_irq_on_off, /* (rtems_irq_disable) */ |
---|
| 310 | mpc83xx_spi_irq_isOn /* (rtems_irq_is_enabled) */ |
---|
| 311 | }; |
---|
| 312 | |
---|
| 313 | /* |
---|
| 314 | * (un-)install handler for SPI device |
---|
| 315 | */ |
---|
| 316 | if (install) { |
---|
| 317 | /* |
---|
| 318 | * create semaphore for IRQ synchronization |
---|
| 319 | */ |
---|
| 320 | rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'), |
---|
| 321 | 0, |
---|
[359e537] | 322 | RTEMS_FIFO |
---|
[7edabaf] | 323 | | RTEMS_SIMPLE_BINARY_SEMAPHORE, |
---|
| 324 | 0, |
---|
| 325 | &softc_ptr->irq_sema_id); |
---|
| 326 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 327 | rtems_panic("SPI: cannot create semaphore"); |
---|
| 328 | } |
---|
| 329 | if (!BSP_install_rtems_irq_handler (&irq_conn_data)) { |
---|
| 330 | rtems_panic("SPI: cannot install IRQ handler"); |
---|
| 331 | } |
---|
| 332 | } |
---|
| 333 | else { |
---|
| 334 | if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) { |
---|
| 335 | rtems_panic("SPI: cannot uninstall IRQ handler"); |
---|
| 336 | } |
---|
| 337 | /* |
---|
| 338 | * delete sync semaphore |
---|
| 339 | */ |
---|
| 340 | if (softc_ptr->irq_sema_id != 0) { |
---|
| 341 | rc = rtems_semaphore_delete(softc_ptr->irq_sema_id); |
---|
| 342 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 343 | rtems_panic("SPI: cannot delete semaphore"); |
---|
| 344 | } |
---|
| 345 | } |
---|
| 346 | } |
---|
| 347 | } |
---|
| 348 | |
---|
| 349 | /*=========================================================================*\ |
---|
| 350 | | Function: | |
---|
| 351 | \*-------------------------------------------------------------------------*/ |
---|
| 352 | rtems_status_code mpc83xx_spi_init |
---|
| 353 | ( |
---|
| 354 | /*-------------------------------------------------------------------------*\ |
---|
| 355 | | Purpose: | |
---|
| 356 | | initialize the driver | |
---|
| 357 | +---------------------------------------------------------------------------+ |
---|
| 358 | | Input Parameters: | |
---|
| 359 | \*-------------------------------------------------------------------------*/ |
---|
| 360 | rtems_libi2c_bus_t *bh /* bus specifier structure */ |
---|
| 361 | ) |
---|
| 362 | /*-------------------------------------------------------------------------*\ |
---|
| 363 | | Return Value: | |
---|
| 364 | | o = ok or error code | |
---|
| 365 | \*=========================================================================*/ |
---|
| 366 | { |
---|
| 367 | mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc); |
---|
| 368 | #if defined(DEBUG) |
---|
| 369 | printk("mpc83xx_spi_init called... "); |
---|
| 370 | #endif |
---|
| 371 | /* |
---|
| 372 | * init HW registers: |
---|
| 373 | */ |
---|
| 374 | /* |
---|
| 375 | * FIXME: set default mode in SPIM |
---|
| 376 | */ |
---|
[359e537] | 377 | |
---|
[7edabaf] | 378 | /* |
---|
| 379 | * init interrupt stuff |
---|
| 380 | */ |
---|
| 381 | mpc83xx_spi_install_irq_handler(softc_ptr,TRUE); |
---|
| 382 | |
---|
| 383 | /* |
---|
| 384 | * mark, that we have initialized |
---|
| 385 | */ |
---|
| 386 | softc_ptr->initialized = TRUE; |
---|
| 387 | #if defined(DEBUG) |
---|
| 388 | printk("... exit OK\r\n"); |
---|
| 389 | #endif |
---|
| 390 | return RTEMS_SUCCESSFUL; |
---|
| 391 | } |
---|
| 392 | |
---|
| 393 | /*=========================================================================*\ |
---|
| 394 | | Function: | |
---|
| 395 | \*-------------------------------------------------------------------------*/ |
---|
| 396 | int mpc83xx_spi_read_write_bytes |
---|
| 397 | ( |
---|
| 398 | /*-------------------------------------------------------------------------*\ |
---|
| 399 | | Purpose: | |
---|
| 400 | | transmit/receive some bytes from SPI device | |
---|
| 401 | +---------------------------------------------------------------------------+ |
---|
| 402 | | Input Parameters: | |
---|
| 403 | \*-------------------------------------------------------------------------*/ |
---|
| 404 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 405 | unsigned char *rbuf, /* buffer to store bytes */ |
---|
| 406 | const unsigned char *tbuf, /* buffer to send bytes */ |
---|
| 407 | int len /* number of bytes to transceive */ |
---|
| 408 | ) |
---|
| 409 | /*-------------------------------------------------------------------------*\ |
---|
| 410 | | Return Value: | |
---|
| 411 | | number of bytes received or (negative) error code | |
---|
| 412 | \*=========================================================================*/ |
---|
| 413 | { |
---|
| 414 | mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc); |
---|
| 415 | rtems_status_code rc; |
---|
| 416 | int bc = 0; |
---|
| 417 | int bytes_per_char = softc_ptr->bytes_per_char; |
---|
[359e537] | 418 | int bit_shift = softc_ptr->bit_shift; |
---|
[7edabaf] | 419 | uint32_t spird_val; |
---|
| 420 | |
---|
| 421 | #if defined(DEBUG) |
---|
| 422 | printk("mpc83xx_spi_read_write_bytes called... "); |
---|
| 423 | #endif |
---|
| 424 | |
---|
| 425 | while (len > bytes_per_char-1) { |
---|
| 426 | len -= bytes_per_char; |
---|
| 427 | /* |
---|
| 428 | * mark last byte in SPCOM |
---|
| 429 | */ |
---|
| 430 | #if defined(USE_LAST_BIT) |
---|
| 431 | softc_ptr->reg_ptr->spcom = (len < bytes_per_char) ? MPC83XX_SPCOM_LST : 0; |
---|
| 432 | #else |
---|
| 433 | softc_ptr->reg_ptr->spcom = 0; |
---|
| 434 | #endif |
---|
| 435 | if (tbuf == NULL) { |
---|
| 436 | /* |
---|
[574fb67] | 437 | * perform idle char write to read byte |
---|
[7edabaf] | 438 | */ |
---|
[574fb67] | 439 | softc_ptr->reg_ptr->spitd = softc_ptr->idle_char << bit_shift; |
---|
[7edabaf] | 440 | } |
---|
| 441 | else { |
---|
| 442 | switch(bytes_per_char) { |
---|
| 443 | case 1: |
---|
| 444 | softc_ptr->reg_ptr->spitd = (*(uint8_t *)tbuf) << bit_shift; |
---|
| 445 | break; |
---|
| 446 | case 2: |
---|
| 447 | softc_ptr->reg_ptr->spitd = (*(uint16_t *)tbuf) << bit_shift; |
---|
| 448 | break; |
---|
| 449 | case 4: |
---|
| 450 | softc_ptr->reg_ptr->spitd = (*(uint32_t *)tbuf) << bit_shift; |
---|
| 451 | break; |
---|
| 452 | } |
---|
| 453 | tbuf += softc_ptr->bytes_per_char; |
---|
| 454 | } |
---|
| 455 | /* |
---|
| 456 | * wait 'til end of transfer |
---|
| 457 | */ |
---|
| 458 | #if defined(USE_LAST_BIT) |
---|
| 459 | rc = mpc83xx_spi_wait(softc_ptr, |
---|
[359e537] | 460 | ((len == 0) |
---|
| 461 | ? MPC83XX_SPIE_LT |
---|
[7edabaf] | 462 | : MPC83XX_SPIE_NE), |
---|
[359e537] | 463 | ((len == 0) |
---|
| 464 | ? MPC83XX_SPIE_LT |
---|
[7edabaf] | 465 | : MPC83XX_SPIE_NF) |
---|
| 466 | | MPC83XX_SPIE_NE, |
---|
| 467 | MPC83XX_SPIE_LT |
---|
| 468 | | MPC83XX_SPIE_OV |
---|
| 469 | | MPC83XX_SPIE_UN |
---|
| 470 | | MPC83XX_SPIE_NE |
---|
| 471 | | MPC83XX_SPIE_NF); |
---|
| 472 | if (len == 0) { |
---|
| 473 | /* |
---|
| 474 | * clear the "last transfer complete" event |
---|
| 475 | */ |
---|
| 476 | softc_ptr->reg_ptr->spie = MPC83XX_SPIE_LT; |
---|
| 477 | } |
---|
| 478 | #else |
---|
| 479 | rc = mpc83xx_spi_wait(softc_ptr, |
---|
| 480 | MPC83XX_SPIE_NE, |
---|
| 481 | MPC83XX_SPIE_NF |
---|
| 482 | | MPC83XX_SPIE_NE, |
---|
| 483 | MPC83XX_SPIE_OV |
---|
| 484 | | MPC83XX_SPIE_UN |
---|
| 485 | | MPC83XX_SPIE_NE |
---|
| 486 | | MPC83XX_SPIE_NF); |
---|
| 487 | #endif |
---|
| 488 | if (rc != RTEMS_SUCCESSFUL) { |
---|
| 489 | #if defined(DEBUG) |
---|
| 490 | printk("... exit rc=%d\r\n",-rc); |
---|
| 491 | #endif |
---|
| 492 | return -rc; |
---|
| 493 | } |
---|
| 494 | spird_val = softc_ptr->reg_ptr->spird; |
---|
| 495 | if (rbuf != NULL) { |
---|
| 496 | switch(bytes_per_char) { |
---|
| 497 | case 1: |
---|
| 498 | (*(uint8_t *)rbuf) = spird_val >> bit_shift; |
---|
| 499 | break; |
---|
| 500 | case 2: |
---|
| 501 | (*(uint16_t *)rbuf) = spird_val >> bit_shift; |
---|
| 502 | break; |
---|
| 503 | case 4: |
---|
| 504 | (*(uint32_t *)rbuf) = spird_val >> bit_shift; |
---|
| 505 | break; |
---|
| 506 | } |
---|
| 507 | rbuf += bytes_per_char; |
---|
| 508 | } |
---|
| 509 | bc += bytes_per_char; |
---|
| 510 | } |
---|
| 511 | #if defined(DEBUG) |
---|
| 512 | printk("... exit OK, rc=%d\r\n",bc); |
---|
| 513 | #endif |
---|
| 514 | return bc; |
---|
| 515 | } |
---|
| 516 | |
---|
| 517 | /*=========================================================================*\ |
---|
| 518 | | Function: | |
---|
| 519 | \*-------------------------------------------------------------------------*/ |
---|
| 520 | int mpc83xx_spi_read_bytes |
---|
| 521 | ( |
---|
| 522 | /*-------------------------------------------------------------------------*\ |
---|
| 523 | | Purpose: | |
---|
| 524 | | receive some bytes from SPI device | |
---|
| 525 | +---------------------------------------------------------------------------+ |
---|
| 526 | | Input Parameters: | |
---|
| 527 | \*-------------------------------------------------------------------------*/ |
---|
| 528 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 529 | unsigned char *buf, /* buffer to store bytes */ |
---|
| 530 | int len /* number of bytes to receive */ |
---|
| 531 | ) |
---|
| 532 | /*-------------------------------------------------------------------------*\ |
---|
| 533 | | Return Value: | |
---|
| 534 | | number of bytes received or (negative) error code | |
---|
| 535 | \*=========================================================================*/ |
---|
| 536 | { |
---|
| 537 | return mpc83xx_spi_read_write_bytes(bh,buf,NULL,len); |
---|
| 538 | } |
---|
| 539 | |
---|
| 540 | /*=========================================================================*\ |
---|
| 541 | | Function: | |
---|
| 542 | \*-------------------------------------------------------------------------*/ |
---|
| 543 | int mpc83xx_spi_write_bytes |
---|
| 544 | ( |
---|
| 545 | /*-------------------------------------------------------------------------*\ |
---|
| 546 | | Purpose: | |
---|
| 547 | | send some bytes to SPI device | |
---|
| 548 | +---------------------------------------------------------------------------+ |
---|
| 549 | | Input Parameters: | |
---|
| 550 | \*-------------------------------------------------------------------------*/ |
---|
| 551 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 552 | unsigned char *buf, /* buffer to send */ |
---|
| 553 | int len /* number of bytes to send */ |
---|
| 554 | |
---|
| 555 | ) |
---|
| 556 | /*-------------------------------------------------------------------------*\ |
---|
| 557 | | Return Value: | |
---|
| 558 | | number of bytes sent or (negative) error code | |
---|
| 559 | \*=========================================================================*/ |
---|
| 560 | { |
---|
| 561 | return mpc83xx_spi_read_write_bytes(bh,NULL,buf,len); |
---|
| 562 | } |
---|
| 563 | |
---|
| 564 | /*=========================================================================*\ |
---|
| 565 | | Function: | |
---|
| 566 | \*-------------------------------------------------------------------------*/ |
---|
| 567 | rtems_status_code mpc83xx_spi_set_tfr_mode |
---|
| 568 | ( |
---|
| 569 | /*-------------------------------------------------------------------------*\ |
---|
| 570 | | Purpose: | |
---|
| 571 | | set SPI to desired baudrate/clock mode/character mode | |
---|
| 572 | +---------------------------------------------------------------------------+ |
---|
| 573 | | Input Parameters: | |
---|
| 574 | \*-------------------------------------------------------------------------*/ |
---|
| 575 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 576 | const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */ |
---|
| 577 | ) |
---|
| 578 | /*-------------------------------------------------------------------------*\ |
---|
| 579 | | Return Value: | |
---|
| 580 | | rtems_status_code | |
---|
| 581 | \*=========================================================================*/ |
---|
| 582 | { |
---|
| 583 | mpc83xx_spi_softc_t *softc_ptr = &(((mpc83xx_spi_desc_t *)(bh))->softc); |
---|
| 584 | uint32_t spimode_baud,spimode; |
---|
| 585 | rtems_status_code rc = RTEMS_SUCCESSFUL; |
---|
[574fb67] | 586 | |
---|
| 587 | /* Set idle character */ |
---|
| 588 | softc_ptr->idle_char = tfr_mode->idle_char; |
---|
| 589 | |
---|
[7edabaf] | 590 | /* |
---|
| 591 | * FIXME: set proper mode |
---|
| 592 | */ |
---|
| 593 | if (rc == RTEMS_SUCCESSFUL) { |
---|
[42bf1b9] | 594 | rc = mpc83xx_spi_baud_to_mode(tfr_mode->baudrate, |
---|
| 595 | softc_ptr->base_frq, |
---|
| 596 | &spimode_baud); |
---|
[7edabaf] | 597 | } |
---|
| 598 | if (rc == RTEMS_SUCCESSFUL) { |
---|
| 599 | rc = mpc83xx_spi_char_mode(softc_ptr, |
---|
| 600 | tfr_mode->bits_per_char, |
---|
| 601 | tfr_mode->lsb_first, |
---|
| 602 | &spimode); |
---|
| 603 | } |
---|
| 604 | if (rc == RTEMS_SUCCESSFUL) { |
---|
| 605 | spimode |= spimode_baud; |
---|
| 606 | spimode |= MPC83XX_SPIMODE_M_S; /* set master mode */ |
---|
| 607 | if (!tfr_mode->lsb_first) { |
---|
| 608 | spimode |= MPC83XX_SPIMODE_REV; |
---|
| 609 | } |
---|
| 610 | if (tfr_mode->clock_inv) { |
---|
| 611 | spimode |= MPC83XX_SPIMODE_CI; |
---|
| 612 | } |
---|
| 613 | if (tfr_mode->clock_phs) { |
---|
| 614 | spimode |= MPC83XX_SPIMODE_CP; |
---|
| 615 | } |
---|
| 616 | } |
---|
[359e537] | 617 | |
---|
[7edabaf] | 618 | if (rc == RTEMS_SUCCESSFUL) { |
---|
| 619 | /* |
---|
| 620 | * disable SPI |
---|
| 621 | */ |
---|
| 622 | softc_ptr->reg_ptr->spmode &= ~MPC83XX_SPIMODE_EN; |
---|
| 623 | /* |
---|
| 624 | * set new mode and reenable SPI |
---|
| 625 | */ |
---|
| 626 | softc_ptr->reg_ptr->spmode = spimode | MPC83XX_SPIMODE_EN; |
---|
| 627 | } |
---|
| 628 | return rc; |
---|
| 629 | } |
---|
| 630 | |
---|
| 631 | |
---|
| 632 | /*=========================================================================*\ |
---|
| 633 | | Function: | |
---|
| 634 | \*-------------------------------------------------------------------------*/ |
---|
| 635 | int mpc83xx_spi_ioctl |
---|
| 636 | ( |
---|
| 637 | /*-------------------------------------------------------------------------*\ |
---|
| 638 | | Purpose: | |
---|
| 639 | | perform selected ioctl function for SPI | |
---|
| 640 | +---------------------------------------------------------------------------+ |
---|
| 641 | | Input Parameters: | |
---|
| 642 | \*-------------------------------------------------------------------------*/ |
---|
| 643 | rtems_libi2c_bus_t *bh, /* bus specifier structure */ |
---|
| 644 | int cmd, /* ioctl command code */ |
---|
| 645 | void *arg /* additional argument array */ |
---|
| 646 | ) |
---|
| 647 | /*-------------------------------------------------------------------------*\ |
---|
| 648 | | Return Value: | |
---|
| 649 | | rtems_status_code | |
---|
| 650 | \*=========================================================================*/ |
---|
| 651 | { |
---|
| 652 | int ret_val = -1; |
---|
| 653 | |
---|
| 654 | switch(cmd) { |
---|
| 655 | case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: |
---|
[359e537] | 656 | ret_val = |
---|
[7edabaf] | 657 | -mpc83xx_spi_set_tfr_mode(bh, |
---|
| 658 | (const rtems_libi2c_tfr_mode_t *)arg); |
---|
| 659 | break; |
---|
| 660 | case RTEMS_LIBI2C_IOCTL_READ_WRITE: |
---|
[359e537] | 661 | ret_val = |
---|
[7edabaf] | 662 | mpc83xx_spi_read_write_bytes(bh, |
---|
| 663 | ((rtems_libi2c_read_write_t *)arg)->rd_buf, |
---|
| 664 | ((rtems_libi2c_read_write_t *)arg)->wr_buf, |
---|
| 665 | ((rtems_libi2c_read_write_t *)arg)->byte_cnt); |
---|
| 666 | break; |
---|
| 667 | default: |
---|
| 668 | ret_val = -RTEMS_NOT_DEFINED; |
---|
| 669 | break; |
---|
| 670 | } |
---|
| 671 | return ret_val; |
---|
| 672 | } |
---|
| 673 | |
---|
| 674 | |
---|
| 675 | |
---|