david/ipxe
Archived
1
0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/include/gpxe/i2c.h
Michael Brown 9dccbc0af2 [i2c] Generalise i2c bit-bashing support to addressless devices
Some devices (e.g. the Atmel AT24C11) have no concept of a device
address; they respond to every device address and use this value as
the word address.  Some other devices use part of the device address
field to extend the word address field.

Generalise the i2c bit-bashing support to handle this by defining the
device address length and word address length as properties of an i2c
device.  The word address is assumed to overflow into the device
address field if the address used exceeds the width of the word
address field.

Also add a bus reset mechanism.  i2c chips don't usually have a reset
line, so rebooting the host will not clear any bizarre state that the
chip may be in.  We reset the bus by clocking SCL until we see SDA
high, at which point we know we can generate a start condition and
have it seen by all devices.  We then generate a stop condition to
leave the bus in a known state prior to use.

Finally, add some extra debugging messages to i2c_bit.c.
2008-10-01 19:24:56 +01:00

170 lines
4.0 KiB
C

#ifndef _GPXE_I2C_H
#define _GPXE_I2C_H
/** @file
*
* I2C interface
*
*/
#include <stdint.h>
#include <gpxe/bitbash.h>
/** An I2C device
*
* An I2C device represents a specific slave device on an I2C bus. It
* is accessed via an I2C interface.
*/
struct i2c_device {
/** Address of this device
*
* The actual address sent on the bus will look like
*
* <start> <device address> <word address overflow> <r/w>
*
* The "word address overflow" is any excess bits from the
* word address, i.e. any portion that does not fit within the
* defined word address length.
*/
unsigned int dev_addr;
/** Device address length, in bytes
*
* This is the number of bytes that comprise the device
* address, defined to be the portion that terminates with the
* read/write bit.
*/
unsigned int dev_addr_len;
/** Word adddress length, in bytes
*
* This is the number of bytes that comprise the word address,
* defined to be the portion that starts after the read/write
* bit and ends before the first data byte.
*
* For some devices, this length will be zero (i.e. the word
* address is contained entirely within the "word address
* overflow").
*/
unsigned int word_addr_len;
};
/** An I2C interface
*
* An I2C interface provides access to an I2C bus, via which I2C
* devices may be reached.
*/
struct i2c_interface {
/**
* Read data from I2C device
*
* @v i2c I2C interface
* @v i2cdev I2C device
* @v offset Starting offset within the device
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
int ( * read ) ( struct i2c_interface *i2c, struct i2c_device *i2cdev,
unsigned int offset, uint8_t *data,
unsigned int len );
/**
* Write data to I2C device
*
* @v i2c I2C interface
* @v i2cdev I2C device
* @v offset Starting offset within the device
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
int ( * write ) ( struct i2c_interface *i2c, struct i2c_device *i2cdev,
unsigned int offset, const uint8_t *data,
unsigned int len );
};
/** A bit-bashing I2C interface
*
* This provides a standardised way to construct I2C buses via a
* bit-bashing interface.
*/
struct i2c_bit_basher {
/** I2C interface */
struct i2c_interface i2c;
/** Bit-bashing interface */
struct bit_basher basher;
};
/** Ten-bit address marker
*
* This value is ORed with the I2C device address to indicate a
* ten-bit address format on the bus.
*/
#define I2C_TENBIT_ADDRESS 0x7800
/** An I2C write command */
#define I2C_WRITE 0
/** An I2C read command */
#define I2C_READ 1
/** Bit indices used for I2C bit-bashing interface */
enum {
/** Serial clock */
I2C_BIT_SCL = 0,
/** Serial data */
I2C_BIT_SDA,
};
/** Delay required for bit-bashing operation */
#define I2C_UDELAY 5
/** Maximum number of cycles to use when attempting a bus reset */
#define I2C_RESET_MAX_CYCLES 32
/**
* Check presence of I2C device
*
* @v i2c I2C interface
* @v i2cdev I2C device
* @ret rc Return status code
*
* Checks for the presence of the device on the I2C bus by attempting
* a zero-length write.
*/
static inline int i2c_check_presence ( struct i2c_interface *i2c,
struct i2c_device *i2cdev ) {
return i2c->write ( i2c, i2cdev, 0, NULL, 0 );
}
extern int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
struct bit_basher_operations *bash_op );
/**
* Initialise generic I2C EEPROM device
*
* @v i2cdev I2C device
*/
static inline __always_inline void
init_i2c_eeprom ( struct i2c_device *i2cdev, unsigned int dev_addr ) {
i2cdev->dev_addr = dev_addr;
i2cdev->dev_addr_len = 1;
i2cdev->word_addr_len = 1;
}
/**
* Initialise Atmel AT24C11
*
* @v i2cdev I2C device
*/
static inline __always_inline void
init_at24c11 ( struct i2c_device *i2cdev ) {
/* This chip has no device address; it must be the only chip
* on the bus. The word address is contained entirely within
* the device address field.
*/
i2cdev->dev_addr = 0;
i2cdev->dev_addr_len = 1;
i2cdev->word_addr_len = 0;
}
#endif /* _GPXE_I2C_H */