#define I2C_MAX_OFFSET_LEN 4
+/* Useful debugging function */
+void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
+{
+ int i;
+
+ for (i = 0; i < nmsgs; i++) {
+ struct i2c_msg *m = &msg[i];
+
+ printf(" %s %x len=%x", m->flags & I2C_M_RD ? "R" : "W",
+ msg->addr, msg->len);
+ if (!(m->flags & I2C_M_RD))
+ printf(": %x", m->buf[0]);
+ printf("\n");
+ }
+}
+
/**
* i2c_setup_offset() - Set up a new message with a chip offset
*
static int i2c_read_bytewise(struct udevice *dev, uint offset,
uint8_t *buffer, int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
static int i2c_write_bytewise(struct udevice *dev, uint offset,
const uint8_t *buffer, int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
int len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
}
}
+int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+ struct udevice *bus = dev_get_parent(dev);
+ struct dm_i2c_ops *ops = i2c_get_ops(bus);
+
+ if (!ops->xfer)
+ return -ENOSYS;
+
+ return ops->xfer(bus, msg, nmsgs);
+}
+
+int dm_i2c_reg_read(struct udevice *dev, uint offset)
+{
+ uint8_t val;
+ int ret;
+
+ ret = dm_i2c_read(dev, offset, &val, 1);
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+
+int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
+{
+ uint8_t val = value;
+
+ return dm_i2c_write(dev, offset, &val, 1);
+}
+
/**
* i2c_probe_chip() - probe for a chip on a bus
*
static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
- struct dm_i2c_chip chip;
+ struct dm_i2c_chip *chip;
char name[30], *str;
struct udevice *dev;
int ret;
snprintf(name, sizeof(name), "generic_%x", chip_addr);
str = strdup(name);
+ if (!str)
+ return -ENOMEM;
ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev);
debug("%s: device_bind_driver: ret=%d\n", __func__, ret);
if (ret)
goto err_bind;
/* Tell the device what we know about it */
- memset(&chip, '\0', sizeof(chip));
- chip.chip_addr = chip_addr;
- chip.offset_len = offset_len;
- ret = device_probe_child(dev, &chip);
- debug("%s: device_probe_child: ret=%d\n", __func__, ret);
+ chip = dev_get_parent_platdata(dev);
+ chip->chip_addr = chip_addr;
+ chip->offset_len = offset_len;
+ ret = device_probe(dev);
+ debug("%s: device_probe: ret=%d\n", __func__, ret);
if (ret)
goto err_probe;
return 0;
err_probe:
+ /*
+ * If the device failed to probe, unbind it. There is nothing there
+ * on the bus so we don't want to leave it lying around
+ */
device_unbind(dev);
err_bind:
free(str);
bus->name, chip_addr);
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
- struct dm_i2c_chip store;
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
int ret;
- if (!chip) {
- chip = &store;
- i2c_chip_ofdata_to_platdata(gd->fdt_blob,
- dev->of_offset, chip);
- }
if (chip->chip_addr == chip_addr) {
ret = device_probe(dev);
debug("found, ret=%d\n", ret);
return ret;
}
-int i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+int dm_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
- struct dm_i2c_bus *i2c = bus->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
int ret;
/*
return 0;
}
-/*
- * i2c_get_bus_speed:
- *
- * Returns speed of selected I2C bus in Hz
- */
-int i2c_get_bus_speed(struct udevice *bus)
+int dm_i2c_get_bus_speed(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
- struct dm_i2c_bus *i2c = bus->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
if (!ops->get_bus_speed)
return i2c->speed_hz;
int i2c_set_chip_flags(struct udevice *dev, uint flags)
{
struct udevice *bus = dev->parent;
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
int ret;
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
*flagsp = chip->flags;
int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
{
- struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
if (offset_len > I2C_MAX_OFFSET_LEN)
return -EINVAL;
return 0;
}
+int i2c_get_chip_offset_len(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+
+ return chip->offset_len;
+}
+
int i2c_deblock(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
int i2c_chip_ofdata_to_platdata(const void *blob, int node,
struct dm_i2c_chip *chip)
{
- chip->offset_len = 1; /* default */
+ chip->offset_len = fdtdec_get_int(gd->fdt_blob, node,
+ "u-boot,i2c-offset-len", 1);
chip->flags = 0;
chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
if (chip->chip_addr == -1) {
static int i2c_post_probe(struct udevice *dev)
{
- struct dm_i2c_bus *i2c = dev->uclass_priv;
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency", 100000);
- return i2c_set_bus_speed(dev, i2c->speed_hz);
+ return dm_i2c_set_bus_speed(dev, i2c->speed_hz);
}
-int i2c_post_bind(struct udevice *dev)
+static int i2c_post_bind(struct udevice *dev)
{
/* Scan the bus for devices */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
+static int i2c_child_post_bind(struct udevice *dev)
+{
+ struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
+
+ if (dev->of_offset == -1)
+ return 0;
+
+ return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
+}
+
UCLASS_DRIVER(i2c) = {
.id = UCLASS_I2C,
.name = "i2c",
.flags = DM_UC_FLAG_SEQ_ALIAS,
- .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
.post_bind = i2c_post_bind,
.post_probe = i2c_post_probe,
+ .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+ .per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
+ .child_post_bind = i2c_child_post_bind,
};
UCLASS_DRIVER(i2c_generic) = {