#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
-#ifdef CONFIG_DM_GPIO
+#if CONFIG_IS_ENABLED(DM_GPIO)
#include <asm/gpio.h>
#endif
static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
uint8_t offset_buf[], struct i2c_msg *msg)
{
- int offset_len;
+ int offset_len = chip->offset_len;
msg->addr = chip->chip_addr;
+ if (chip->chip_addr_offset_mask)
+ msg->addr |= (offset >> (8 * offset_len)) &
+ chip->chip_addr_offset_mask;
msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
msg->len = chip->offset_len;
msg->buf = offset_buf;
- if (!chip->offset_len)
+ if (!offset_len)
return -EADDRNOTAVAIL;
- assert(chip->offset_len <= I2C_MAX_OFFSET_LEN);
- offset_len = chip->offset_len;
+ assert(offset_len <= I2C_MAX_OFFSET_LEN);
+
while (offset_len--)
*offset_buf++ = offset >> (8 * offset_len);
if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
return -EINVAL;
ptr = msg + 1;
- ptr->addr = chip->chip_addr;
+ ptr->addr = msg->addr;
ptr->flags = msg->flags | I2C_M_RD;
ptr->len = 1;
ptr->buf = &buffer[i];
ptr++;
if (len) {
- ptr->addr = chip->chip_addr;
+ ptr->addr = msg->addr;
ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
ptr->flags |= I2C_M_RD;
ptr->len = len;
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
int ret;
- if (chip->chip_addr == chip_addr) {
+ if (chip->chip_addr == (chip_addr &
+ ~chip->chip_addr_offset_mask)) {
ret = device_probe(dev);
debug("found, ret=%d\n", ret);
if (ret)
debug("Cannot find I2C bus %d\n", busnum);
return ret;
}
+
+ /* detect the presence of the chip on the bus */
+ ret = i2c_probe_chip(bus, chip_addr, 0);
+ debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
+ chip_addr, ret);
+ if (ret) {
+ debug("Cannot detect I2C chip %02x on bus %d\n", chip_addr,
+ busnum);
+ return ret;
+ }
+
ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
if (ret) {
debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
return chip->offset_len;
}
-#ifdef CONFIG_DM_GPIO
+int i2c_set_chip_addr_offset_mask(struct udevice *dev, uint mask)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+
+ chip->chip_addr_offset_mask = mask;
+
+ return 0;
+}
+
+uint i2c_get_chip_addr_offset_mask(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+
+ return chip->chip_addr_offset_mask;
+}
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
{
if (bit)
{
return -ENOSYS;
}
-#endif // CONFIG_DM_GPIO
+#endif /* DM_GPIO */
int i2c_deblock(struct udevice *bus)
{
return ops->deblock(bus);
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip)
{
int addr;
}
#endif
+static int i2c_pre_probe(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
+ unsigned int max = 0;
+ ofnode node;
+ int ret;
+
+ i2c->max_transaction_bytes = 0;
+ dev_for_each_subnode(node, dev) {
+ ret = ofnode_read_u32(node,
+ "u-boot,i2c-transaction-bytes",
+ &max);
+ if (!ret && max > i2c->max_transaction_bytes)
+ i2c->max_transaction_bytes = max;
+ }
+
+ debug("%s: I2C bus: %s max transaction bytes: %d\n", __func__,
+ dev->name, i2c->max_transaction_bytes);
+#endif
+ return 0;
+}
+
static int i2c_post_probe(struct udevice *dev)
{
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
- i2c->speed_hz = dev_read_u32_default(dev, "clock-frequency", 100000);
+ i2c->speed_hz = dev_read_u32_default(dev, "clock-frequency",
+ I2C_SPEED_STANDARD_RATE);
return dm_i2c_set_bus_speed(dev, i2c->speed_hz);
#else
static int i2c_child_post_bind(struct udevice *dev)
{
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
if (!dev_of_valid(dev))
#endif
}
+struct i2c_priv {
+ int max_id;
+};
+
+static int i2c_post_bind(struct udevice *dev)
+{
+ struct uclass *class = dev->uclass;
+ struct i2c_priv *priv = class->priv;
+ int ret = 0;
+
+ /* Just for sure */
+ if (!priv)
+ return -ENOMEM;
+
+ debug("%s: %s, req_seq=%d\n", __func__, dev->name, dev->req_seq);
+
+ /* if there is no alias ID, use the first free */
+ if (dev->req_seq == -1)
+ dev->req_seq = ++priv->max_id;
+
+ debug("%s: %s, new req_seq=%d\n", __func__, dev->name, dev->req_seq);
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ ret = dm_scan_fdt_dev(dev);
+#endif
+ return ret;
+}
+
+int i2c_uclass_init(struct uclass *class)
+{
+ struct i2c_priv *priv = class->priv;
+
+ /* Just for sure */
+ if (!priv)
+ return -ENOMEM;
+
+ /* Get the last allocated alias. */
+ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA))
+ priv->max_id = dev_read_alias_highest_id("i2c");
+ else
+ priv->max_id = -1;
+
+ debug("%s: highest alias id is %d\n", __func__, priv->max_id);
+
+ return 0;
+}
+
UCLASS_DRIVER(i2c) = {
.id = UCLASS_I2C,
.name = "i2c",
.flags = DM_UC_FLAG_SEQ_ALIAS,
-#if CONFIG_IS_ENABLED(OF_CONTROL)
- .post_bind = dm_scan_fdt_dev,
-#endif
+ .post_bind = i2c_post_bind,
+ .init = i2c_uclass_init,
+ .priv_auto_alloc_size = sizeof(struct i2c_priv),
+ .pre_probe = i2c_pre_probe,
.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),