Hi Simon,
On Tue, 11 Nov 2014 10:46:24 -0700 Simon Glass <[email protected]> wrote: > The uclass implements the same operations as the current I2C framework but > makes some changes to make it fit driver model better: > > - Remove the chip address from API calls > - Remove the address length from API calls > - Remove concept of 'current' I2C bus > - Drop all existing init functions > > Signed-off-by: Simon Glass <[email protected]> > --- > > Changes in v2: > - Fix cihp typo > - Implement generic I2C devices to allow 'i2c probe' on unknown devices > - Return the probed device from i2c_probe() > - Set the bus speed after the bus is probed > - Add some debugging for generic I2C device binding > - Add a 'deblock' method to recover an I2C bus stuck in mid-transaction > - Add a helper function to find a chip on a particular bus number [snip] > + > +int i2c_read(struct udevice *dev, uint addr, uint8_t *buffer, int len) > +{ > + struct dm_i2c_chip *chip = dev_get_parentdata(dev); > + struct udevice *bus = dev_get_parent(dev); > + struct dm_i2c_ops *ops = i2c_get_ops(bus); > + > + if (!ops->read) > + return -ENOSYS; > + > + return ops->read(bus, chip->chip_addr, addr, chip->addr_len, buffer, > + len); > +} > + > +int i2c_write(struct udevice *dev, uint addr, const uint8_t *buffer, int len) > +{ > + struct dm_i2c_chip *chip = dev_get_parentdata(dev); > + struct udevice *bus = dev_get_parent(dev); > + struct dm_i2c_ops *ops = i2c_get_ops(bus); > + > + if (!ops->write) > + return -ENOSYS; > + > + return ops->write(bus, chip->chip_addr, addr, chip->addr_len, buffer, > + len); > +} This seems inconsistent with "struct dm_i2c_ops". In this function, the address length(chip->addr_len) is passed to the forth argument of ops->write(). You should compare it with "struct dm_i2c_ops" in include/i2c.h It says that the third argument is alen. BTW, address_offset within the chip and data are treated in the same way in I2C bus. Should we pass them separately to each driver? I mean, can we put the offset address and data in the buffer? > + > +int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp) > +{ > + struct udevice *dev; > + > + debug("%s: Searching bus '%s' for address %02x: ", __func__, > + 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); > + 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); > + if (ret) > + return ret; > + *devp = dev; > + return 0; > + } If "chip" is "NULL", i2c_chip_ofdata_to_platdata() is called to create struct dm_i2c_chip, but it is not thrown away soon. It is not efficient. If we use device_probe_child() instead of device_probe(), I think we can re-use it. I mean, if (chip->chip_addr == chip_addr) { ret = device_probe_child(dev, chip); Perhaps, we can remove sandbox_i2c_child_pre_probe(). > + } > + debug("not found\n"); > + return i2c_bind_driver(bus, chip_addr, devp); > +} If no chip-device is found at the specified chip_addr, the last line calls i2c_bind_driver(). Why? The i2c_bind_driver() tries to create a "generic" chip. What is this "generic" chip? Besides, i2c_bind_driver() tries to probe the created generic chip, but it always fails in i2c_chip_ofdata_to_platdata() because the generic chip does not have "reg" property I could not understand at all what this code wants to do. > +} > + > +int i2c_probe(struct udevice *bus, uint chip_addr, struct udevice **devp) > +{ > + struct dm_i2c_ops *ops = i2c_get_ops(bus); > + int ret; > + > + *devp = NULL; > + if (!ops->probe) > + return -ENODEV; > + > + /* First probe that chip */ > + ret = ops->probe(bus, chip_addr); > + debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name, > + chip_addr, ret); > + if (ret) > + return ret; Is the "ops->probe" responsible to probe child devices? (At least, sandbox_i2c probes its children) > + /* The chip was found, see if we have a driver, and probe it */ > + ret = i2c_get_chip(bus, chip_addr, devp); > + debug("%s: i2c_get_chip: ret=%d\n", __func__, ret); > + if (!ret || ret != -ENODEV) > + return ret; > + > + return i2c_bind_driver(bus, chip_addr, devp); > +} If so, why do we need to call i2c_get_chip() and probe it again? > +int 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; > + int ret; > + > + if (ops->set_bus_speed) { > + ret = ops->set_bus_speed(bus, speed); > + if (ret) > + return ret; > + } > + i2c->speed_hz = speed; > + > + return 0; > +} > + > +/* > + * i2c_get_bus_speed: > + * > + * Returns speed of selected I2C bus in Hz > + */ > +int i2c_get_bus_speed(struct udevice *bus) > +{ > + struct dm_i2c_ops *ops = i2c_get_ops(bus); > + struct dm_i2c_bus *i2c = bus->uclass_priv; > + > + if (!ops->set_bus_speed) > + return i2c->speed_hz; > + > + return ops->get_bus_speed(bus); > +} > + > +int i2c_set_addr_len(struct udevice *dev, uint addr_len) > +{ > + struct udevice *bus = dev->parent; > + struct dm_i2c_chip *chip = dev_get_parentdata(dev); > + struct dm_i2c_ops *ops = i2c_get_ops(bus); > + int ret; > + > + if (addr_len > 3) > + return -EINVAL; > + if (ops->set_addr_len) { > + ret = ops->set_addr_len(dev, addr_len); > + if (ret) > + return ret; > + } > + chip->addr_len = addr_len; > + > + return 0; > +} I am not 100% sure, but "addr_len" is a user-configurable parameter? I think each device has its own fixed address size. > +UCLASS_DRIVER(i2c_generic) = { > + .id = UCLASS_I2C_GENERIC, > + .name = "i2c_generic", > +}; > + > +U_BOOT_DRIVER(i2c_generic_drv) = { > + .name = "i2c_generic_drv", > + .id = UCLASS_I2C_GENERIC, > +}; Could you explain how "i2c_generic" is used. > + > +/** > + * struct dm_i2c_ops - driver operations for I2C uclass > + * > + * Drivers should support these operations unless otherwise noted. These > + * operations are intended to be used by uclass code, not directly from > + * other code. > + */ > +struct dm_i2c_ops { > + /** > + * read() - read from a chip > + * > + * @bus: Bus to read from > + * @chip_addr: Chip address to read from > + * @alen: Length of chip address in bytes > + * @offset: Offset within chip to start reading > + * @buffer: Place to put data > + * @len: Number of bytes to read > + */ > + int (*read)(struct udevice *bus, uint chip_addr, uint alen, > + uint offset, uint8_t *buffer, int len); > + > + /** > + * write() - write bytes to a chip > + * > + * @dev: Device to write to > + * @chip_addr: Chip address to read from > + * @alen: Length of chip address in bytes > + * @offset: Offset within chip to start writing > + * @buffer: Buffer containing data to write > + * @len: Number of bytes to write > + * > + * @return 0 on success, -ve on failure > + */ > + int (*write)(struct udevice *bus, uint chip_addr, uint alen, > + uint offset, const uint8_t *buffer, int len); See. The third argument is address length. Best Regards Masahiro Yamada _______________________________________________ U-Boot mailing list [email protected] http://lists.denx.de/mailman/listinfo/u-boot

