aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/device/i2c.c83
-rw-r--r--src/include/device/device.h2
-rw-r--r--src/include/device/i2c.h22
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_ */