📄 mcfmbus.c
字号:
/* MCF5206e MBUS module (I2C bus) driver * * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia * Author: Victor V. Vengerov <vvv@oktet.ru> * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * * http://www.rtems.com/license/LICENSE. * * @(#) $Id: mcfmbus.c,v 1.2.2.1 2003/09/04 18:45:44 joel Exp $ */#include "mcf5206/mcfmbus.h"#include "mcf5206/mcf5206e.h"#include "i2c.h"/* Events of I2C machine */typedef enum i2c_event { EVENT_NONE, /* Spurious event */ EVENT_TRANSFER, /* Start new transfer */ EVENT_NEXTMSG, /* Start processing of next message in transfer */ EVENT_ACK, /* Sending finished with ACK */ EVENT_NACK, /* Sending finished with NACK */ EVENT_TIMEOUT, /* Timeout occured */ EVENT_DATA_RECV, /* Data received */ EVENT_ARB_LOST, /* Arbitration lost */ EVENT_SLAVE /* Addressed as a slave */} i2c_event;static mcfmbus *mbus;/*** Auxillary primitives ***//* Change state of finite state machine */#define next_state(bus,new_state) \ do { \ (bus)->state = (new_state); \ } while (0)/* Initiate start condition on the I2C bus */#define mcfmbus_start(bus) \ do { \ *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MSTA; \ } while (0)/* Initiate stop condition on the I2C bus */#define mcfmbus_stop(bus) \ do { \ *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MSTA; \ } while (0)/* Initiate repeat start condition on the I2C bus */#define mcfmbus_rstart(bus) \ do { \ *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_RSTA; \ } while (0)/* Send byte to the bus */#define mcfmbus_send(bus,byte) \ do { \ *MCF5206E_MBDR((bus)->base) = (byte); \ } while (0)/* Set transmit mode */#define mcfmbus_tx_mode(bus) \ do { \ *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_MTX; \ } while (0)/* Set receive mode */#define mcfmbus_rx_mode(bus) \ do { \ *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_MTX; \ (void)*MCF5206E_MBDR((bus)->base); \ } while (0)/* Transmit acknowledge when byte received */#define mcfmbus_send_ack(bus) \ do { \ *MCF5206E_MBCR((bus)->base) &= ~MCF5206E_MBCR_TXAK; \ } while (0)/* DO NOT transmit acknowledge when byte received */#define mcfmbus_send_nack(bus) \ do { \ *MCF5206E_MBCR((bus)->base) |= MCF5206E_MBCR_TXAK; \ } while (0)#define mcfmbus_error(bus,err_status) \ do { \ do { \ (bus)->cmsg->status = (err_status); \ (bus)->cmsg++; \ } while (((bus)->cmsg - (bus)->msg < (bus)->nmsg) && \ ((bus)->cmsg->flags & I2C_MSG_ERRSKIP)); \ bus->cmsg--; \ } while (0)/* mcfmbus_get_event -- * Read MBUS module status register, determine interrupt reason and * return appropriate event. * * PARAMETERS: * bus - pointer to MBUS module descriptor structure * * RETURNS: * event code */static i2c_eventmcfmbus_get_event(mcfmbus *bus){ i2c_event event; rtems_unsigned8 status, control; rtems_interrupt_level level; rtems_interrupt_disable(level); status = *MCF5206E_MBSR(bus->base); control = *MCF5206E_MBCR(bus->base); if (status & MCF5206E_MBSR_MIF) /* Interrupt occured */ { if (status & MCF5206E_MBSR_MAAS) { event = EVENT_SLAVE; *MCF5206E_MBCR(bus->base) = control; /* To clear Addressed As Slave condition */ } else if (status & MCF5206E_MBSR_MAL) /* Arbitration lost */ { *MCF5206E_MBSR(bus->base) = status & ~MCF5206E_MBSR_MAL; event = EVENT_ARB_LOST; } else if (control & MCF5206E_MBCR_MTX) /* Trasmit mode */ { if (status & MCF5206E_MBSR_RXAK) event = EVENT_NACK; else event = EVENT_ACK; } else /* Received */ { event = EVENT_DATA_RECV; } /* Clear interrupt condition */ *MCF5206E_MBSR(bus->base) &= ~MCF5206E_MBSR_MIF; } else { event = EVENT_NONE; } rtems_interrupt_enable(level); return event;}static voidmcfmbus_machine_error(mcfmbus *bus, i2c_event event){ return;}/* mcfmbus_machine -- * finite state machine for I2C bus protocol * * PARAMETERS: * bus - pointer to ColdFire MBUS descriptor structure * event - I2C event * * RETURNS: * none */static voidmcfmbus_machine(mcfmbus *bus, i2c_event event){ rtems_unsigned8 b; switch (bus->state) { case STATE_IDLE: switch (event) { case EVENT_NEXTMSG: /* Start new message processing */ bus->cmsg++; /* FALLTHRU */ case EVENT_TRANSFER: /* Initiate new transfer */ if (bus->cmsg - bus->msg >= bus->nmsg) { mcfmbus_stop(bus); next_state(bus, STATE_IDLE); bus->msg = bus->cmsg = NULL; bus->nmsg = bus->byte = 0; bus->done(bus->done_arg); break; } /* Initiate START or REPEATED START condition on the bus */ if (event == EVENT_TRANSFER) { mcfmbus_start(bus); } else /* (event == EVENT_NEXTMSG) */ { mcfmbus_rstart(bus); } bus->byte = 0; mcfmbus_tx_mode(bus); /* Initiate slave address sending */ if (bus->cmsg->flags & I2C_MSG_ADDR_10) { i2c_address a = bus->cmsg->addr; b = 0xf0 | (((a >> 8) & 0x03) << 1); if (bus->cmsg->flags & I2C_MSG_WR) { mcfmbus_send(bus, b); next_state(bus, STATE_ADDR_1_W); } else { mcfmbus_send(bus, b | 1); next_state(bus, STATE_ADDR_1_R); } } else { b = (bus->cmsg->addr & ~0x01); if (bus->cmsg->flags & I2C_MSG_WR) { next_state(bus, STATE_SENDING); } else { next_state(bus, STATE_ADDR_7); b |= 1; } mcfmbus_send(bus, b); } break; default: mcfmbus_machine_error(bus, event); break; } break; case STATE_ADDR_7: switch (event) { case EVENT_ACK: mcfmbus_rx_mode(bus); if (bus->cmsg->len <= 1) mcfmbus_send_nack(bus); else mcfmbus_send_ack(bus); next_state(bus, STATE_RECEIVING); break; case EVENT_NACK: mcfmbus_error(bus, I2C_NO_DEVICE); next_state(bus, STATE_IDLE); mcfmbus_machine(bus, EVENT_NEXTMSG); break; case EVENT_ARB_LOST: mcfmbus_error(bus, I2C_ARBITRATION_LOST); next_state(bus, STATE_IDLE); mcfmbus_machine(bus, EVENT_NEXTMSG); break; default: mcfmbus_machine_error(bus, event); break; } break; case STATE_ADDR_1_R: case STATE_ADDR_1_W: switch (event) { case EVENT_ACK: { rtems_unsigned8 b = (bus->cmsg->addr & 0xff); mcfmbus_send(bus, b); if (bus->state == STATE_ADDR_1_W) { next_state(bus, STATE_SENDING); } else { i2c_address a; mcfmbus_rstart(bus); mcfmbus_tx_mode(bus); a = bus->cmsg->addr; b = 0xf0 | (((a >> 8) & 0x03) << 1) | 1; mcfmbus_send(bus, b); next_state(bus, STATE_ADDR_7); } break; } case EVENT_NACK: mcfmbus_error(bus, I2C_NO_DEVICE); next_state(bus, STATE_IDLE); mcfmbus_machine(bus, EVENT_NEXTMSG);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -