[b599faa] | 1 | /* I2C bus driver for mpc8540-based boards */ |
---|
| 2 | |
---|
[ac7af4a] | 3 | /* |
---|
[b599faa] | 4 | * Authorship |
---|
| 5 | * ---------- |
---|
| 6 | * This software ('mvme3100' RTEMS BSP) was created by |
---|
| 7 | * |
---|
| 8 | * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, |
---|
| 9 | * Stanford Linear Accelerator Center, Stanford University. |
---|
[ac7af4a] | 10 | * |
---|
[b599faa] | 11 | * Acknowledgement of sponsorship |
---|
| 12 | * ------------------------------ |
---|
| 13 | * The 'mvme3100' BSP was produced by |
---|
| 14 | * the Stanford Linear Accelerator Center, Stanford University, |
---|
| 15 | * under Contract DE-AC03-76SFO0515 with the Department of Energy. |
---|
[ac7af4a] | 16 | * |
---|
[b599faa] | 17 | * Government disclaimer of liability |
---|
| 18 | * ---------------------------------- |
---|
| 19 | * Neither the United States nor the United States Department of Energy, |
---|
| 20 | * nor any of their employees, makes any warranty, express or implied, or |
---|
| 21 | * assumes any legal liability or responsibility for the accuracy, |
---|
| 22 | * completeness, or usefulness of any data, apparatus, product, or process |
---|
| 23 | * disclosed, or represents that its use would not infringe privately owned |
---|
| 24 | * rights. |
---|
[ac7af4a] | 25 | * |
---|
[b599faa] | 26 | * Stanford disclaimer of liability |
---|
| 27 | * -------------------------------- |
---|
| 28 | * Stanford University makes no representations or warranties, express or |
---|
| 29 | * implied, nor assumes any liability for the use of this software. |
---|
[ac7af4a] | 30 | * |
---|
[b599faa] | 31 | * Stanford disclaimer of copyright |
---|
| 32 | * -------------------------------- |
---|
| 33 | * Stanford University, owner of the copyright, hereby disclaims its |
---|
| 34 | * copyright and all other rights in this software. Hence, anyone may |
---|
[ac7af4a] | 35 | * freely use it for any purpose without restriction. |
---|
| 36 | * |
---|
[b599faa] | 37 | * Maintenance of notices |
---|
| 38 | * ---------------------- |
---|
| 39 | * In the interest of clarity regarding the origin and status of this |
---|
| 40 | * SLAC software, this and all the preceding Stanford University notices |
---|
| 41 | * are to remain affixed to any copy or derivative of this software made |
---|
| 42 | * or distributed by the recipient and are to be affixed to any copy of |
---|
| 43 | * software made or distributed by the recipient that contains a copy or |
---|
| 44 | * derivative of this software. |
---|
[ac7af4a] | 45 | * |
---|
[b599faa] | 46 | * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 |
---|
[ac7af4a] | 47 | */ |
---|
[b599faa] | 48 | |
---|
| 49 | /* Note: We maintain base address, IRQ etc. statically and |
---|
| 50 | * globally. We don't bother creating driver-specific |
---|
| 51 | * data or using the bus handle but simply assume |
---|
| 52 | * this is the only 8540/i2c bus in the system. |
---|
| 53 | * Proper support for multiple instances would not |
---|
| 54 | * be very hard to add but I don't see the point... |
---|
| 55 | */ |
---|
| 56 | |
---|
| 57 | #include <rtems.h> |
---|
| 58 | #include <bsp.h> |
---|
| 59 | #include <rtems/libi2c.h> |
---|
| 60 | #include <bsp/irq.h> |
---|
| 61 | #include <libcpu/spr.h> |
---|
| 62 | #include <libcpu/io.h> |
---|
| 63 | #include <rtems/bspIo.h> |
---|
[39046f7] | 64 | #include <rtems/score/sysstate.h> |
---|
[b599faa] | 65 | |
---|
[731abf4] | 66 | #include <bsp/mpc8540_i2c_busdrv.h> |
---|
[b599faa] | 67 | |
---|
[9b763110] | 68 | #define STATIC static |
---|
[b599faa] | 69 | |
---|
| 70 | /* I2C controller register definitions */ |
---|
| 71 | #define I2CADR 0x3000 |
---|
| 72 | #define I2CFDR 0x3004 |
---|
| 73 | #define I2CCR 0x3008 |
---|
| 74 | #define I2CCR_MEN (1<<(7-0)) |
---|
| 75 | #define I2CCR_MIEN (1<<(7-1)) |
---|
| 76 | #define I2CCR_MSTA (1<<(7-2)) |
---|
| 77 | #define I2CCR_MTX (1<<(7-3)) |
---|
| 78 | #define I2CCR_TXAK (1<<(7-4)) |
---|
| 79 | #define I2CCR_RSTA (1<<(7-5)) |
---|
| 80 | #define I2CCR_BCST (1<<(7-7)) |
---|
| 81 | #define I2CSR 0x300c |
---|
| 82 | #define I2CSR_MCF (1<<(7-0)) |
---|
| 83 | #define I2CSR_MAAS (1<<(7-1)) |
---|
| 84 | #define I2CSR_MBB (1<<(7-2)) |
---|
| 85 | #define I2CSR_MAL (1<<(7-3)) |
---|
| 86 | #define I2CSR_BCSTM (1<<(7-4)) |
---|
| 87 | #define I2CSR_SRW (1<<(7-5)) |
---|
| 88 | #define I2CSR_MIF (1<<(7-6)) |
---|
| 89 | #define I2CSR_RXAK (1<<(7-7)) |
---|
| 90 | #define I2CDR 0x3010 |
---|
| 91 | #define I2CDFSRR 0x3014 |
---|
| 92 | |
---|
| 93 | SPR_RO(TBRL) |
---|
| 94 | |
---|
| 95 | /********* Global Variables **********/ |
---|
| 96 | |
---|
| 97 | /* |
---|
| 98 | * Semaphore for synchronizing accessing task |
---|
| 99 | * with the (slow) hardware operation. |
---|
| 100 | * Task takes semaphore and blocks, ISR releases. |
---|
| 101 | */ |
---|
| 102 | static rtems_id syncsem = 0; |
---|
| 103 | |
---|
[6771a9e7] | 104 | static inline int ok_to_block(void) |
---|
[b599faa] | 105 | { |
---|
| 106 | return syncsem && _System_state_Is_up( _System_state_Get() ); |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | /* |
---|
| 110 | * Wild guess for 0.2 s; this timeout is effective |
---|
| 111 | * in polling mode; during early init we don't know |
---|
| 112 | * the system clock rate yet - it's one of the things |
---|
| 113 | * we have to read from VPD -- via i2c. |
---|
| 114 | */ |
---|
| 115 | |
---|
| 116 | static uint32_t poll_timeout = 333333333/8/5; |
---|
| 117 | |
---|
| 118 | /********* Primitives ****************/ |
---|
| 119 | |
---|
| 120 | static inline uint8_t |
---|
| 121 | i2c_rd(unsigned reg) |
---|
| 122 | { |
---|
| 123 | return in_8( (volatile uint8_t *)(BSP_8540_CCSR_BASE + reg) ); |
---|
| 124 | } |
---|
| 125 | |
---|
| 126 | static inline void |
---|
| 127 | i2c_wr(unsigned reg, uint8_t val) |
---|
| 128 | { |
---|
| 129 | out_8( (volatile uint8_t *)(BSP_8540_CCSR_BASE + reg), val ); |
---|
| 130 | } |
---|
| 131 | |
---|
| 132 | static inline void |
---|
| 133 | i2c_set(unsigned reg, uint8_t val) |
---|
| 134 | { |
---|
| 135 | i2c_wr( reg, i2c_rd( reg ) | val ); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | static inline void |
---|
| 139 | i2c_clr(unsigned reg, uint8_t val) |
---|
| 140 | { |
---|
| 141 | i2c_wr( reg, i2c_rd( reg ) & ~val ); |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | /********* Helper Routines ***********/ |
---|
| 145 | |
---|
| 146 | /* Synchronize (wait) for a condition on the |
---|
| 147 | * i2c bus. Wait for START or STOP to be complete |
---|
| 148 | * or wait for a byte-transfer. |
---|
| 149 | * The latter is much slower (9 bit times vs. 1/2 |
---|
| 150 | * in the former cases). |
---|
| 151 | * |
---|
| 152 | * If the system is up (and we may block) then |
---|
| 153 | * this routine attempts to block the current |
---|
| 154 | * task rather than busy-waiting. |
---|
| 155 | * |
---|
| 156 | * NOTE: waiting for START/STOP always requires |
---|
| 157 | * polling. |
---|
| 158 | */ |
---|
| 159 | |
---|
| 160 | /* wait until i2c status reg AND mask == cond */ |
---|
| 161 | static rtems_status_code |
---|
| 162 | i2c_wait( uint8_t msk, uint8_t cond ) |
---|
| 163 | { |
---|
| 164 | uint32_t then; |
---|
| 165 | rtems_status_code sc; |
---|
| 166 | static int warn = 0; |
---|
| 167 | |
---|
| 168 | if ( I2CSR_MIF == msk && ok_to_block() ) { |
---|
| 169 | /* block on semaphore only if system is up and sema initialized */ |
---|
| 170 | sc = rtems_semaphore_obtain( syncsem, RTEMS_WAIT, 100 ); |
---|
| 171 | if ( RTEMS_SUCCESSFUL != sc ) |
---|
| 172 | return sc; |
---|
| 173 | } else { |
---|
| 174 | /* system not up (no SEMA yet ) or waiting on something other |
---|
| 175 | * than MIF |
---|
| 176 | */ |
---|
| 177 | if ( I2CSR_MIF == msk && _System_state_Is_up( _System_state_Get() ) ) { |
---|
| 178 | if ( warn < 8 || ! (warn & 0x1f) ) |
---|
| 179 | printk("WARNING: i2c bus driver running in polled mode -- should initialize properly!\n"); |
---|
| 180 | warn++; |
---|
| 181 | } |
---|
| 182 | |
---|
| 183 | then = _read_TBRL(); |
---|
| 184 | do { |
---|
| 185 | /* poll for .2 seconds */ |
---|
| 186 | if ( (_read_TBRL() - then) > poll_timeout ) |
---|
| 187 | return RTEMS_TIMEOUT; |
---|
| 188 | } while ( (msk & i2c_rd( I2CSR )) != cond ); |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | return RTEMS_SUCCESSFUL; |
---|
| 192 | } |
---|
| 193 | |
---|
| 194 | /* |
---|
| 195 | * multi-byte transfer |
---|
| 196 | * - set transfer direction (master read or master write) |
---|
| 197 | * - transfer byte |
---|
| 198 | * - wait/synchronize |
---|
| 199 | * - check for ACK |
---|
| 200 | * |
---|
| 201 | * RETURNS: number of bytes transferred or negative error code. |
---|
| 202 | */ |
---|
| 203 | |
---|
| 204 | STATIC int |
---|
| 205 | i2c_xfer(int rw, uint8_t *buf, int len) |
---|
| 206 | { |
---|
| 207 | int i; |
---|
| 208 | rtems_status_code sc; |
---|
[ac7af4a] | 209 | |
---|
[b599faa] | 210 | if ( rw ) { |
---|
| 211 | i2c_clr( I2CCR, I2CCR_MTX ); |
---|
| 212 | } else { |
---|
| 213 | i2c_set( I2CCR, I2CCR_MTX ); |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | for ( i = 0; i< len; i++ ) { |
---|
| 217 | i2c_clr( I2CSR, I2CSR_MIF ); |
---|
| 218 | /* Enable interrupts if necessary */ |
---|
| 219 | if ( ok_to_block() ) |
---|
| 220 | i2c_set( I2CCR, I2CCR_MIEN ); |
---|
| 221 | if ( rw ) { |
---|
| 222 | buf[i] = i2c_rd( I2CDR ); |
---|
| 223 | } else { |
---|
| 224 | i2c_wr( I2CDR, buf[i] ); |
---|
| 225 | } |
---|
| 226 | if ( RTEMS_SUCCESSFUL != (sc = i2c_wait( I2CSR_MIF, I2CSR_MIF )) ) |
---|
| 227 | return -sc; |
---|
| 228 | if ( (I2CSR_RXAK & i2c_rd( I2CSR )) ) { |
---|
| 229 | /* NO ACK */ |
---|
| 230 | return -RTEMS_IO_ERROR; |
---|
| 231 | } |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | return i; |
---|
| 235 | } |
---|
| 236 | |
---|
[ac7af4a] | 237 | /* |
---|
[b599faa] | 238 | * This bus controller gives us lagging data, i.e., |
---|
| 239 | * when we read a byte from the data reg then that |
---|
| 240 | * issues a read cycle on the bus and gives us the |
---|
| 241 | * byte from the *previous* read cycle :-( |
---|
| 242 | * |
---|
| 243 | * This makes it impossible to properly terminate |
---|
| 244 | * a read transaction w/o knowing ahead of time |
---|
| 245 | * how many bytes are going to be read (API decouples |
---|
| 246 | * 'START'/'STOP' from 'READ') since we would have to |
---|
| 247 | * set TXAK when reading the next-to-last byte |
---|
| 248 | * (i.e., when the last byte is read on the i2c bus). |
---|
| 249 | * |
---|
| 250 | * Hence, (if we are reading) we must do a dummy |
---|
| 251 | * read-cycle here -- hopefully |
---|
| 252 | * that has no side-effects! (i.e., EEPROM drivers should |
---|
| 253 | * reposition file pointers after issuing STOP) |
---|
| 254 | * |
---|
| 255 | */ |
---|
| 256 | |
---|
| 257 | static void |
---|
[6771a9e7] | 258 | rd1byte_noack(void) |
---|
[b599faa] | 259 | { |
---|
| 260 | uint8_t dum; |
---|
| 261 | uint8_t ccr; |
---|
| 262 | |
---|
| 263 | /* If we are in reading state then read one more |
---|
| 264 | * byte w/o acknowledge |
---|
| 265 | */ |
---|
| 266 | |
---|
| 267 | ccr = i2c_rd (I2CCR ); |
---|
| 268 | |
---|
| 269 | if ( ! ( I2CCR_MTX & ccr ) ) { |
---|
| 270 | i2c_wr( I2CCR, ccr | I2CCR_TXAK ); |
---|
| 271 | i2c_xfer(1, &dum, 1); |
---|
| 272 | /* restore original TXAK bit setting */ |
---|
| 273 | i2c_clr( I2CCR, (I2CCR_TXAK & ccr) ); |
---|
| 274 | } |
---|
| 275 | } |
---|
| 276 | |
---|
| 277 | |
---|
| 278 | /********* ISR ***********************/ |
---|
| 279 | |
---|
| 280 | static void i2c_isr(rtems_irq_hdl_param arg) |
---|
| 281 | { |
---|
| 282 | /* disable irq */ |
---|
| 283 | i2c_clr( I2CCR, I2CCR_MIEN ); |
---|
| 284 | /* release task */ |
---|
| 285 | rtems_semaphore_release( syncsem ); |
---|
| 286 | } |
---|
| 287 | |
---|
| 288 | /********* IIC Bus Driver Ops ********/ |
---|
| 289 | |
---|
| 290 | STATIC rtems_status_code |
---|
| 291 | i2c_init(rtems_libi2c_bus_t *bh) |
---|
| 292 | { |
---|
| 293 | rtems_status_code sc; |
---|
| 294 | |
---|
| 295 | /* compute more accurate timeout */ |
---|
| 296 | if ( BSP_bus_frequency && BSP_time_base_divisor ) |
---|
| 297 | poll_timeout = BSP_bus_frequency/BSP_time_base_divisor*1000/5; |
---|
| 298 | |
---|
| 299 | i2c_clr( I2CCR, I2CCR_MEN ); |
---|
| 300 | i2c_set( I2CCR, I2CCR_MEN ); |
---|
| 301 | |
---|
| 302 | i2c_wr( I2CADR, 0 ); |
---|
| 303 | |
---|
| 304 | /* leave motload settings for divisor and filter registers */ |
---|
| 305 | |
---|
| 306 | if ( SYSTEM_STATE_BEFORE_MULTITASKING <= _System_state_Get() && !syncsem ) { |
---|
| 307 | sc = rtems_semaphore_create( |
---|
| 308 | rtems_build_name('i','2','c','b'), |
---|
| 309 | 0, |
---|
| 310 | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_LOCAL, |
---|
| 311 | 0, |
---|
| 312 | &syncsem); |
---|
| 313 | if ( RTEMS_SUCCESSFUL == sc ) { |
---|
| 314 | rtems_irq_connect_data xxx; |
---|
| 315 | xxx.name = BSP_I2C_IRQ; |
---|
| 316 | xxx.on = 0; |
---|
| 317 | xxx.off = 0; |
---|
| 318 | xxx.isOn = 0; |
---|
| 319 | xxx.hdl = i2c_isr; |
---|
| 320 | xxx.handle = 0; |
---|
| 321 | if ( ! BSP_install_rtems_irq_handler( &xxx ) ) { |
---|
| 322 | printk("Unable to install i2c ISR -- falling back to polling mode\n"); |
---|
| 323 | rtems_semaphore_delete( syncsem ); |
---|
| 324 | /* fall back to polling mode */ |
---|
| 325 | syncsem = 0; |
---|
| 326 | } |
---|
| 327 | } else { |
---|
| 328 | syncsem = 0; |
---|
| 329 | } |
---|
| 330 | } |
---|
| 331 | |
---|
| 332 | return RTEMS_SUCCESSFUL; |
---|
| 333 | } |
---|
| 334 | |
---|
| 335 | STATIC rtems_status_code |
---|
| 336 | i2c_start(rtems_libi2c_bus_t *bh) |
---|
| 337 | { |
---|
| 338 | uint8_t v; |
---|
| 339 | rtems_status_code sc = RTEMS_SUCCESSFUL; |
---|
| 340 | |
---|
| 341 | v = i2c_rd( I2CCR ); |
---|
| 342 | if ( I2CCR_MSTA & v ) { |
---|
| 343 | /* RESTART */ |
---|
| 344 | rd1byte_noack(); |
---|
| 345 | v |= I2CCR_RSTA; |
---|
| 346 | } else { |
---|
| 347 | v |= I2CCR_MSTA; |
---|
| 348 | } |
---|
| 349 | i2c_wr( I2CCR, v ); |
---|
| 350 | |
---|
| 351 | /* On MBB we can only poll-wait (no IRQ is generated) |
---|
| 352 | * and this is also much faster than reading a byte |
---|
| 353 | * (1/2-bit time) so the overhead of an IRQ may not |
---|
| 354 | * be justified. |
---|
| 355 | * OTOH, we can put this off into the 'send_addr' routine |
---|
| 356 | * |
---|
| 357 | |
---|
| 358 | sc = i2c_wait( I2CSR_MBB, I2CSR_MBB ); |
---|
| 359 | */ |
---|
| 360 | |
---|
| 361 | return sc; |
---|
| 362 | } |
---|
| 363 | |
---|
| 364 | STATIC rtems_status_code |
---|
| 365 | i2c_stop(rtems_libi2c_bus_t *bh) |
---|
| 366 | { |
---|
| 367 | rd1byte_noack(); |
---|
| 368 | |
---|
| 369 | /* STOP */ |
---|
| 370 | i2c_clr( I2CCR, I2CCR_TXAK | I2CCR_MSTA ); |
---|
| 371 | |
---|
| 372 | /* FIXME: should we really spend 1/2 bit-time polling |
---|
| 373 | * or should we just go ahead and hope noone |
---|
| 374 | * else will get a chance to do something to |
---|
| 375 | * the bus until the STOP completes? |
---|
| 376 | */ |
---|
| 377 | return i2c_wait( I2CSR_MBB, 0 ); |
---|
| 378 | } |
---|
| 379 | |
---|
| 380 | STATIC rtems_status_code |
---|
| 381 | i2c_send_addr(rtems_libi2c_bus_t *bh, uint32_t addr, int rw) |
---|
| 382 | { |
---|
| 383 | uint8_t buf[2]; |
---|
| 384 | int l = 0; |
---|
| 385 | uint8_t read_mask = rw ? 1 : 0; |
---|
| 386 | rtems_status_code sc; |
---|
| 387 | |
---|
| 388 | /* Make sure we are started; (i2c_start() didn't bother to wait |
---|
| 389 | * so we do it here - some time already has expired. |
---|
| 390 | */ |
---|
| 391 | sc = i2c_wait( I2CSR_MBB, I2CSR_MBB ); |
---|
| 392 | |
---|
| 393 | if ( RTEMS_SUCCESSFUL != sc ) |
---|
| 394 | return sc; |
---|
| 395 | |
---|
| 396 | if ( addr > 0x7f ) { |
---|
| 397 | /* 10-bit request; 1st address byte is 0b11110<b9><b8><r/w> */ |
---|
| 398 | buf[l] = 0xf0 | ((addr >> 7) & 0x06) | read_mask; |
---|
| 399 | read_mask = 0; |
---|
| 400 | l++; |
---|
| 401 | buf[l] = addr & 0xff; |
---|
| 402 | } else { |
---|
| 403 | buf[l] = (addr << 1) | read_mask; |
---|
| 404 | l++; |
---|
| 405 | } |
---|
| 406 | |
---|
| 407 | /* |
---|
| 408 | * After sending a an address for reading we must |
---|
| 409 | * read a dummy byte (this actually clocks the first real |
---|
| 410 | * byte on the i2c bus and makes it available in the |
---|
| 411 | * data register so that the first 'read_bytes' operation |
---|
| 412 | * obtains the byte we clock in here [and starts clocking |
---|
| 413 | * the second byte]) to overcome the pipeline |
---|
| 414 | * delay in the hardware (I don't like this design) :-(. |
---|
| 415 | */ |
---|
| 416 | sc = i2c_xfer( 0, buf, l ); |
---|
| 417 | if ( rw && l == sc ) { |
---|
| 418 | sc = i2c_xfer( 1, buf, 1 ); |
---|
| 419 | } |
---|
| 420 | return sc >=0 ? RTEMS_SUCCESSFUL : -sc; |
---|
| 421 | } |
---|
| 422 | |
---|
| 423 | STATIC int |
---|
| 424 | i2c_read_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len) |
---|
| 425 | { |
---|
| 426 | return i2c_xfer( 1, buf, len ); |
---|
| 427 | } |
---|
| 428 | |
---|
| 429 | STATIC int |
---|
| 430 | i2c_write_bytes(rtems_libi2c_bus_t *bh, unsigned char *buf, int len) |
---|
| 431 | { |
---|
| 432 | return i2c_xfer( 0, buf, len ); |
---|
| 433 | } |
---|
| 434 | |
---|
| 435 | /********* Driver Glue Vars **********/ |
---|
| 436 | |
---|
| 437 | static rtems_libi2c_bus_ops_t myops = { |
---|
| 438 | init: i2c_init, |
---|
| 439 | send_start: i2c_start, |
---|
| 440 | send_stop: i2c_stop, |
---|
| 441 | send_addr: i2c_send_addr, |
---|
| 442 | read_bytes: i2c_read_bytes, |
---|
| 443 | write_bytes: i2c_write_bytes, |
---|
| 444 | }; |
---|
| 445 | |
---|
| 446 | static rtems_libi2c_bus_t my_bus_tbl = { |
---|
| 447 | ops: &myops, |
---|
| 448 | size: sizeof(my_bus_tbl), |
---|
| 449 | }; |
---|
| 450 | |
---|
| 451 | /********* Global Driver Handle ******/ |
---|
| 452 | |
---|
| 453 | rtems_libi2c_bus_t *mpc8540_i2c_bus_descriptor = &my_bus_tbl; |
---|