diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/device/i2c.c | 83 | ||||
-rw-r--r-- | src/include/device/device.h | 2 | ||||
-rw-r--r-- | src/include/device/i2c.h | 22 |
3 files changed, 107 insertions, 0 deletions
diff --git a/src/device/i2c.c b/src/device/i2c.c index 53bfdf0c94..d4670a013c 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -13,7 +13,90 @@ * GNU General Public License for more details. */ +#include <device/device.h> #include <device/i2c.h> +#include <stdint.h> + +#if ENV_RAMSTAGE +/* Return I2C operations for a bus */ +static inline const struct i2c_bus_operations *ops_i2c_bus(struct bus *bus) +{ + if (bus && bus->dev && bus->dev->ops) + return bus->dev->ops->ops_i2c_bus; + return NULL; +} + +int i2c_dev_find_bus(struct device *dev) +{ + const struct i2c_bus_operations *ops; + struct bus *pbus; + + if (!dev) + return -1; + + /* Locate parent bus with I2C controller ops */ + pbus = dev->bus; + while (pbus && pbus->dev && !ops_i2c_bus(pbus)) + if (pbus->dev->bus != pbus) + pbus = pbus->dev->bus; + + /* Check if this I2C controller ops implements dev_to_bus() */ + ops = ops_i2c_bus(pbus); + if (!ops || !ops->dev_to_bus) + return -1; + + /* Use controller ops to determine the bus number */ + return ops->dev_to_bus(pbus->dev); +} + +int i2c_dev_transfer(struct device *dev, struct i2c_seg *segments, int count) +{ + int bus = i2c_dev_find_bus(dev); + if (bus < 0) + return -1; + return i2c_transfer(bus, segments, count); +} + +int i2c_dev_readb(struct device *dev, uint8_t reg, uint8_t *data) +{ + int bus = i2c_dev_find_bus(dev); + if (bus < 0) + return -1; + return i2c_readb(bus, dev->path.i2c.device, reg, data); +} + +int i2c_dev_writeb(struct device *dev, uint8_t reg, uint8_t data) +{ + int bus = i2c_dev_find_bus(dev); + if (bus < 0) + return -1; + return i2c_writeb(bus, dev->path.i2c.device, reg, data); +} + +int i2c_dev_read_bytes(struct device *dev, uint8_t reg, uint8_t *data, int len) +{ + int bus = i2c_dev_find_bus(dev); + if (bus < 0) + return -1; + return i2c_read_bytes(bus, dev->path.i2c.device, reg, data, len); +} + +int i2c_dev_read_raw(struct device *dev, uint8_t *data, int len) +{ + int bus = i2c_dev_find_bus(dev); + if (bus < 0) + return -1; + return i2c_read_raw(bus, dev->path.i2c.device, data, len); +} + +int i2c_dev_write_raw(struct device *dev, uint8_t *data, int len) +{ + int bus = i2c_dev_find_bus(dev); + if (bus < 0) + return -1; + return i2c_write_raw(bus, dev->path.i2c.device, data, len); +} +#endif int i2c_read_field(unsigned bus, uint8_t chip, uint8_t reg, uint8_t *data, uint8_t mask, uint8_t shift) diff --git a/src/include/device/device.h b/src/include/device/device.h index 00ff3d9a07..95fabf42c8 100644 --- a/src/include/device/device.h +++ b/src/include/device/device.h @@ -20,6 +20,7 @@ struct device; typedef struct device * device_t; struct pci_operations; struct pci_bus_operations; +struct i2c_bus_operations; struct smbus_bus_operations; struct pnp_mode_ops; @@ -62,6 +63,7 @@ struct device_operations { const char *(*acpi_name)(device_t dev); #endif const struct pci_operations *ops_pci; + const struct i2c_bus_operations *ops_i2c_bus; const struct smbus_bus_operations *ops_smbus_bus; const struct pci_bus_operations * (*ops_pci_bus)(device_t dev); const struct pnp_mode_ops *ops_pnp_mode; diff --git a/src/include/device/i2c.h b/src/include/device/i2c.h index c8c7b2283d..d8a793c716 100644 --- a/src/include/device/i2c.h +++ b/src/include/device/i2c.h @@ -168,4 +168,26 @@ static inline int i2c_writeb(unsigned bus, uint8_t chip, uint8_t reg, return i2c_transfer(bus, &seg, 1); } +/* I2C bus operation for ramstage drivers */ +struct device; +struct i2c_bus_operations { + /* + * This is an SOC specific method that can be provided to translate the + * 'struct device' for an I2C controller into a unique I2C bus number. + * Returns -1 if the bus number for this device cannot be determined. + */ + int (*dev_to_bus)(struct device *dev); +}; + +/* Return I2C bus number for provided device, -1 if not found */ +int i2c_dev_find_bus(struct device *dev); + +/* Variants of I2C helper functions that take a device instead of bus number */ +int i2c_dev_transfer(struct device *dev, struct i2c_seg *segments, int count); +int i2c_dev_readb(struct device *dev, uint8_t reg, uint8_t *data); +int i2c_dev_writeb(struct device *dev, uint8_t reg, uint8_t data); +int i2c_dev_read_bytes(struct device *dev, uint8_t reg, uint8_t *data, int len); +int i2c_dev_read_raw(struct device *dev, uint8_t *data, int len); +int i2c_dev_write_raw(struct device *dev, uint8_t *data, int len); + #endif /* _DEVICE_I2C_H_ */ |