All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support
@ 2014-10-13  5:39 Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 01/12] dm: core: Allow access to the device's driver_id data Simon Glass
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

(Note this is RFC since the uclass interface needs discussion and also
because only sandbox is implemented so far. But I thought it best to get
this out there as soon as I wrote it as it may influence the PMIC library,
etc.)

This series is an initial attempt to add I2C support to driver model. It
has become apparent that this is a high priority as it is widely used. It
follows along to some extent from the SPI conversion.

Several changes are made from the original I2C implementations.

Firstly It is not necessary to specify the chip address with every call,
since each chip knows its own address - it is stored in struct dm_i2c_chip
which is attached to each chip on the I2C bus. However, this information
*is* passed to the driver since I presume most drivers need it and it would
be cumbersome to look up in every call.

Secondly there is no concept of a 'current' I2C bus so all associated logic
is removed. With driver model i2c_set_bus_num() and i2c_get_bus_num() are
not available. Since the chip device specifies both the bus and the chip
address, there is no need for this concept. It also causes problems when
one driver changes the current bus and forgets to change it back.

Thirdly initialisation is handled by driver model's normal probe() method
on each device so there should be no need for i2c_init_all(), i2c_init(),
i2c_init_board(), i2c_board_late_init() and board_i2c_init().

I2C muxes are not yet supported. To support these we will need to maintain
state of the current mux settings to avoid resetting every mux every time.
Probably we need to add a sandbox I2C mux driver to permit testing of this.
This can probably be done later.

Platform data is not yet supported either, only device tree. The
U_BOOT_I2C_MKENT_COMPLETE() and U_BOOT_I2C_ADAP_COMPLETE() macros are not
used. Also struct i2c_adapter is not defined anymore. This will need to be
addressed, perhaps as part of converting over a board that does not use
device tree.

This series is available at u-boot-dm/i2c-working.


Simon Glass (12):
  dm: core: Allow access to the device's driver_id data
  dm: core: Add functions to find parent and OF data
  dm: i2c: Add a uclass for I2C
  dm: i2c: Implement driver model support in the i2c command
  dm: i2c: Add I2C emulation driver for sandbox
  dm: i2c: Add a sandbox I2C driver
  dm: i2c: Add an I2C EEPROM simulator
  dm: i2c: config: Enable I2C for sandbox using driver model
  dm: i2c: dts: Add an I2C bus for sandbox
  dm: WIP: EEPROM driver
  dm: i2c: Add tests for I2C
  dm: i2c: tegra: Convert to driver model for I2C for seaboard

 arch/arm/cpu/tegra20-common/pmu.c           |  21 +-
 arch/arm/include/asm/arch-tegra/tegra_i2c.h |   2 +-
 arch/sandbox/dts/sandbox.dts                |  17 ++
 board/nvidia/common/board.c                 |   4 -
 common/cmd_i2c.c                            | 312 +++++++++++++++++++++++----
 drivers/core/device.c                       |  10 +
 drivers/core/lists.c                        |  17 +-
 drivers/i2c/Makefile                        |   2 +
 drivers/i2c/i2c-emul-uclass.c               |  14 ++
 drivers/i2c/i2c-uclass.c                    | 177 ++++++++++++++++
 drivers/i2c/sandbox_i2c.c                   | 148 +++++++++++++
 drivers/i2c/tegra_i2c.c                     | 313 ++++++++++------------------
 drivers/misc/Makefile                       |   4 +
 drivers/misc/i2c_eeprom.c                   |  51 +++++
 drivers/misc/i2c_eeprom_emul.c              | 108 ++++++++++
 drivers/power/tps6586x.c                    |  27 +--
 include/config_fallbacks.h                  |   6 +
 include/configs/cardhu.h                    |   2 -
 include/configs/colibri_t30.h               |   2 -
 include/configs/sandbox.h                   |   6 +
 include/configs/seaboard.h                  |   3 -
 include/configs/tegra-common.h              |   1 +
 include/configs/tegra20-common.h            |   3 -
 include/dm/device.h                         |  19 ++
 include/dm/uclass-id.h                      |   3 +
 include/i2c.h                               | 252 ++++++++++++++++++++++
 include/i2c_eeprom.h                        |  19 ++
 include/tps6586x.h                          |   2 +-
 test/dm/Makefile                            |   1 +
 test/dm/i2c.c                               | 100 +++++++++
 test/dm/test.dts                            |  17 ++
 31 files changed, 1373 insertions(+), 290 deletions(-)
 create mode 100644 drivers/i2c/i2c-emul-uclass.c
 create mode 100644 drivers/i2c/i2c-uclass.c
 create mode 100644 drivers/i2c/sandbox_i2c.c
 create mode 100644 drivers/misc/i2c_eeprom.c
 create mode 100644 drivers/misc/i2c_eeprom_emul.c
 create mode 100644 include/i2c_eeprom.h
 create mode 100644 test/dm/i2c.c

-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 01/12] dm: core: Allow access to the device's driver_id data
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 02/12] dm: core: Add functions to find parent and OF data Simon Glass
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

When the device is created from a device tree node, it matches a compatible
string. Allow access to that string and the associated data.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/core/device.c |  5 +++++
 drivers/core/lists.c  | 17 ++++++++++++-----
 include/dm/device.h   | 11 +++++++++++
 3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 49faa29..0d84776 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -548,3 +548,8 @@ int device_find_next_child(struct udevice **devp)
 
 	return 0;
 }
+
+ulong dev_get_of_data(struct udevice *dev)
+{
+	return dev->of_id->data;
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 699f94b..f170ae7 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -96,22 +96,26 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
  * tree error
  */
 static int driver_check_compatible(const void *blob, int offset,
-				   const struct udevice_id *of_match)
+				   const struct udevice_id *of_match,
+				   const struct udevice_id **of_idp)
 {
 	int ret;
 
+	*of_idp = NULL;
 	if (!of_match)
 		return -ENOENT;
 
 	while (of_match->compatible) {
 		ret = fdt_node_check_compatible(blob, offset,
 						of_match->compatible);
-		if (!ret)
+		if (!ret) {
+			*of_idp = of_match;
 			return 0;
-		else if (ret == -FDT_ERR_NOTFOUND)
+		} else if (ret == -FDT_ERR_NOTFOUND) {
 			return -ENODEV;
-		else if (ret < 0)
+		} else if (ret < 0) {
 			return -EINVAL;
+		}
 		of_match++;
 	}
 
@@ -123,6 +127,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 {
 	struct driver *driver = ll_entry_start(struct driver, driver);
 	const int n_ents = ll_entry_count(struct driver, driver);
+	const struct udevice_id *id;
 	struct driver *entry;
 	struct udevice *dev;
 	bool found = false;
@@ -134,7 +139,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 	if (devp)
 		*devp = NULL;
 	for (entry = driver; entry != driver + n_ents; entry++) {
-		ret = driver_check_compatible(blob, offset, entry->of_match);
+		ret = driver_check_compatible(blob, offset, entry->of_match,
+					      &id);
 		name = fdt_get_name(blob, offset, NULL);
 		if (ret == -ENOENT) {
 			continue;
@@ -154,6 +160,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 			dm_warn("Error binding driver '%s'\n", entry->name);
 			return ret;
 		} else {
+			dev->of_id = id;
 			found = true;
 			if (devp)
 				*devp = dev;
diff --git a/include/dm/device.h b/include/dm/device.h
index b8d4e7a..a712156 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -47,6 +47,7 @@ struct driver_info;
  * @name: Name of device, typically the FDT node name
  * @platdata: Configuration data for this device
  * @of_offset: Device tree node offset for this device (- for none)
+ * @of_id: Pointer to the udevice_id structure which created the device
  * @parent: Parent of this device, or NULL for the top level device
  * @priv: Private data for this device
  * @uclass: Pointer to uclass for this device
@@ -65,6 +66,7 @@ struct udevice {
 	const char *name;
 	void *platdata;
 	int of_offset;
+	const struct udevice_id *of_id;
 	struct udevice *parent;
 	void *priv;
 	struct uclass *uclass;
@@ -200,6 +202,15 @@ void *dev_get_parentdata(struct udevice *dev);
 void *dev_get_priv(struct udevice *dev);
 
 /**
+ * dev_get_of_data() - get the device tree data used to bind a device
+ *
+ * When a device is bound using a device tree node, it matches a
+ * particular compatible string as in struct udevice_id. This function
+ * returns the associated data value for that compatible string
+ */
+ulong dev_get_of_data(struct udevice *dev);
+
+/**
  * device_get_child() - Get the child of a device by index
  *
  * Returns the numbered child, 0 being the first. This does not use
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 02/12] dm: core: Add functions to find parent and OF data
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 01/12] dm: core: Allow access to the device's driver_id data Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 03/12] dm: i2c: Add a uclass for I2C Simon Glass
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

Add dev_get_parent() as a convenience to obtain the parent of a device.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/core/device.c | 5 +++++
 include/dm/device.h   | 8 ++++++++
 2 files changed, 13 insertions(+)

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 0d84776..76b29fd 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -549,6 +549,11 @@ int device_find_next_child(struct udevice **devp)
 	return 0;
 }
 
+struct udevice *dev_get_parent(struct udevice *child)
+{
+	return child->parent;
+}
+
 ulong dev_get_of_data(struct udevice *dev)
 {
 	return dev->of_id->data;
diff --git a/include/dm/device.h b/include/dm/device.h
index a712156..e8b7fcf 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -202,6 +202,14 @@ void *dev_get_parentdata(struct udevice *dev);
 void *dev_get_priv(struct udevice *dev);
 
 /**
+ * struct dev_get_parent() - Get the parent of a device
+ *
+ * @child:	Child to check
+ * @return parent of child, or NULL if this is the root device
+ */
+struct udevice *dev_get_parent(struct udevice *child);
+
+/**
  * dev_get_of_data() - get the device tree data used to bind a device
  *
  * When a device is bound using a device tree node, it matches a
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 03/12] dm: i2c: Add a uclass for I2C
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 01/12] dm: core: Allow access to the device's driver_id data Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 02/12] dm: core: Add functions to find parent and OF data Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-11-10  6:33   ` Heiko Schocher
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 04/12] dm: i2c: Implement driver model support in the i2c command Simon Glass
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

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 <sjg@chromium.org>
---

 drivers/i2c/Makefile       |   1 +
 drivers/i2c/i2c-uclass.c   | 177 +++++++++++++++++++++++++++++++
 include/config_fallbacks.h |   6 ++
 include/dm/uclass-id.h     |   1 +
 include/i2c.h              | 252 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 437 insertions(+)
 create mode 100644 drivers/i2c/i2c-uclass.c

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 416ea4f..2ee468d 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,6 +4,7 @@
 #
 # SPDX-License-Identifier:	GPL-2.0+
 #
+obj-$(CONFIG_DM_I2C) += i2c-uclass.o
 
 obj-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 obj-$(CONFIG_DW_I2C) += designware_i2c.o
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
new file mode 100644
index 0000000..6bdce8c
--- /dev/null
+++ b/drivers/i2c/i2c-uclass.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+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);
+}
+
+int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	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);
+			if (ret)
+				return ret;
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+int i2c_probe(struct udevice *bus, uint chip)
+{
+	struct dm_i2c_ops *ops = i2c_get_ops(bus);
+	struct udevice *dev;
+	int ret;
+
+	if (!ops->probe)
+		return -ENODEV;
+
+	/* First probe that chip */
+	ret = ops->probe(bus, chip);
+	if (ret)
+		return ret;
+
+	/* The cihp was found, see if we have a driver, and probe it */
+	return i2c_get_chip(bus, chip, &dev);
+
+	/* No driver. TODO create a dummy one */
+}
+
+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;
+}
+
+int i2c_chip_ofdata_to_platdata(const void *blob, int node,
+				struct dm_i2c_chip *chip)
+{
+	chip->addr_len = 1;	/* default */
+	chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
+	if (chip->chip_addr == -1) {
+		debug("%s: I2C Node '%s' has no 'reg' property\n", __func__,
+		      fdt_get_name(blob, node, NULL));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int i2c_post_probe(struct udevice *dev)
+{
+	struct dm_i2c_bus *i2c = dev->uclass_priv;
+
+	i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				     "clock-frequency", 100000);
+
+	return 0;
+}
+
+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);
+}
+
+UCLASS_DRIVER(i2c) = {
+	.id		= UCLASS_I2C,
+	.name		= "i2c",
+	.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+	.post_bind	= i2c_post_bind,
+	.post_probe	= i2c_post_probe,
+};
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
index 76818f6..c75f42d 100644
--- a/include/config_fallbacks.h
+++ b/include/config_fallbacks.h
@@ -91,4 +91,10 @@
 #undef CONFIG_IMAGE_FORMAT_LEGACY
 #endif
 
+#ifdef CONFIG_DM_I2C
+# ifdef CONFIG_SYS_I2C
+#  error "Cannot define CONFIG_SYS_I2C when CONFIG_DM_I2C is used"
+# endif
+#endif
+
 #endif	/* __CONFIG_FALLBACKS_H */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index e3e9296..9611a13 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -28,6 +28,7 @@ enum uclass_id {
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
+	UCLASS_I2C,		/* I2C bus */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/i2c.h b/include/i2c.h
index 1b4078e..85b914d 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -18,6 +18,255 @@
 #define _I2C_H_
 
 /*
+ * For now there are essentially two parts to this file - driver model
+ * here at the top, and the older code below (with CONFIG_SYS_I2C being
+ * most recent). The plan is to migrate everything to driver model.
+ * The driver model structures and API are separate as they are different
+ * enough as to be incompatible for compilation purposes.
+ */
+
+#ifdef CONFIG_DM_I2C
+
+/**
+ * struct dm_i2c_chip - information about an i2c chip
+ *
+ * An I2C chip is a device on the I2C bus. It sits at a particular address
+ * and normally supports 7-bit or 10-bit addressing.
+ *
+ * To obtain this structure, use dev_get_parentdata(dev) where dev is the
+ * chip to examine.
+ *
+ * @chip_addr: Chip address on bus
+ * @addr_len: Address length in bytes (normally 1 for 7-bit address)
+ * @emul: Emulator for this chip address (only used for emulation)
+ */
+struct dm_i2c_chip {
+	uint chip_addr;
+	uint addr_len;
+#ifdef CONFIG_SANDBOX
+	struct udevice *emul;
+#endif
+};
+
+/**
+ * struct dm_i2c_bus- information about an i2c bus
+ *
+ * An I2C bus contains 0 or more chips on it, each at its own address. The
+ * bus can operate at different speeds (measured in Hz, typically 100KHz
+ * or 400KHz).
+ *
+ * To obtain this structure, use bus->uclass_priv where bus is the I2C
+ * bus udevice.
+ *
+ * @speed_hz: Bus speed in hertz (typically 100000)
+ */
+struct dm_i2c_bus {
+	int speed_hz;
+};
+
+/**
+ * i2c_read() - read bytes from an I2C chip
+ *
+ * To obtain an I2C device (called a 'chip') given the I2C bus address you
+ * can use i2c_get_chip(). To obtain a bus by bus number use
+ * uclass_get_device_by_seq(UCLASS_I2C, <bus number>).
+ *
+ * To set the address length of a devce use i2c_set_addr_len(). It
+ * defaults to 1.
+ *
+ * @dev:	Chip to read from
+ * @offset:	Offset within chip to start reading
+ * @buffer:	Place to put data
+ * @len:	Number of bytes to read
+ *
+ * @return 0 on success, -ve on failure
+ */
+int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer,
+	     int len);
+
+/**
+ * i2c_write() - write bytes to an I2C chip
+ *
+ * See notes for i2c_read() above.
+ *
+ * @dev:	Chip to write to
+ * @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 i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
+	      int len);
+
+/**
+ * i2c_probe() - probe a particular chip address
+ *
+ * This can be useful to check for the existence of a chip on the bus.
+ * It is typically implemented by writing the chip address to the bus
+ * and checking that the chip replies with an ACK.
+ *
+ * @bus:	Bus to probe
+ * @chip_addr:	7-bit address to probe (10-bit and others are not supported)
+ * @return 0 if a chip was found at that address, -ve if not
+ */
+int i2c_probe(struct udevice *bus, uint chip_addr);
+
+/**
+ * i2c_set_bus_speed() - set the speed of a bus
+ *
+ * @bus:	Bus to adjust
+ * @speed:	Requested speed in Hz
+ * @return 0 if OK, -EINVAL for invalid values
+ */
+int i2c_set_bus_speed(struct udevice *bus, unsigned int speed);
+
+/**
+ * i2c_get_bus_speed() - get the speed of a bus
+ *
+ * @bus:	Bus to check
+ * @return speed of selected I2C bus in Hz, -ve on error
+ */
+int i2c_get_bus_speed(struct udevice *bus);
+
+/**
+ * i2c_set_addr_len() - set the address length of a chip
+ *
+ * Typically addresses are 7 bits (so @addr_len should be 1 which is the
+ * default). For 10-bit addresses use a value of 2. Some drivers and
+ * chips may support 0 and 3 also.
+ *
+ * @dev:	Chip to adjust
+ * @addr_len:	New address length value (typically 1 or 2)
+ * @return 0 if OK, -EINVAL if value is unsupported, other -ve value on error
+ */
+int i2c_set_addr_len(struct udevice *dev, uint addr_len);
+
+/**
+ * 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);
+
+	/**
+	 * probe() - probe a particular chip address (recommended)
+	 *
+	 * This function is optional but should be implemented since it is
+	 * an expected feature of the I2C subsystem.
+	 *
+	 * @bus:	Bus to probe
+	 * @chip_addr:	7-bit address to probe
+	 * @return 0 if a chip was found at that address, -ve if not
+	 */
+	int (*probe)(struct udevice *bus, uint chip_addr);
+
+	/**
+	 * set_bus_speed() - set the speed of a bus (optional)
+	 *
+	 * The bus speed value will be updated by the uclass if this function
+	 * does not return an error.
+	 *
+	 * @bus:	Bus to adjust
+	 * @speed:	Requested speed in Hz
+	 * @return 0 if OK, -INVAL for invalid values
+	 */
+	int (*set_bus_speed)(struct udevice *bus, unsigned int speed);
+
+	/**
+	 * get_bus_speed() - get the speed of a bus (optional)
+	 *
+	 * Normally this can be provided by the uclass, but if you want your
+	 * driver to check the bus speed by looking at the hardware, you can
+	 * implement that here.
+	 *
+	 * @bus:	Bus to check
+	 * @return speed of selected I2C bus in Hz, -ve on error
+	 */
+	int (*get_bus_speed)(struct udevice *bus);
+
+	/**
+	 * set_addr_len() - set the address length of a chip (optional)
+	 *
+	 * This is generally implemented by the uclass, but drivers can
+	 * check the value to ensure that unsupported options are not used.
+	 * If provided, this method will always be called when the address
+	 * length changes from the default of 1.
+	 *
+	 * @dev:	Chip to adjust
+	 * @addr_len:	New address length value (typically 1 or 2)
+	 * @return 0 if OK, -INVAL if value is unsupported
+	 */
+	int (*set_addr_len)(struct udevice *dev, uint addr_len);
+};
+
+#define i2c_get_ops(dev)	((struct dm_i2c_ops *)(dev)->driver->ops)
+
+/**
+ * i2c_get_chip() - get a device to use to access a chip on a bus
+ *
+ * This returns the device for the given chip address. The device can then
+ * be used with calls to i2c_read(), i2c_write(), i2c_probe(), etc.
+ *
+ * TODO(sjg at chromium.org): This function should permit a device to be
+ * created 'on the fly' for any address.
+ *
+ * @bus:	Bus to examine
+ * @chip_addr:	Chip address for the new device
+ * @devp:	Returns pointer to new device if found or -ENODEV if not
+ *		found
+ *
+ */
+int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp);
+
+/**
+ * i2c_chip_ofdata_to_platdata() - Decode standard I2C platform data
+ *
+ * This decodes the chip address from a device tree node and puts it into
+ * its dm_i2c_chip structure. This should be called in your driver's
+ * ofdata_to_platdata() method.
+ *
+ * @blob:	Device tree blob
+ * @node:	Node offset to read from
+ * @spi:	Place to put the decoded information
+ */
+int i2c_chip_ofdata_to_platdata(const void *blob, int node,
+				struct dm_i2c_chip *chip);
+
+#endif
+
+#ifndef CONFIG_DM_I2C
+
+/*
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
  *
  * The implementation MUST NOT use static or global variables if the
@@ -451,4 +700,7 @@ int i2c_get_bus_num_fdt(int node);
  * @return 0 if port was reset, -1 if not found
  */
 int i2c_reset_port_fdt(const void *blob, int node);
+
+#endif /* !CONFIG_DM_I2C */
+
 #endif	/* _I2C_H_ */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 04/12] dm: i2c: Implement driver model support in the i2c command
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (2 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 03/12] dm: i2c: Add a uclass for I2C Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-11-10  7:01   ` Heiko Schocher
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 05/12] dm: i2c: Add I2C emulation driver for sandbox Simon Glass
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

The concept of a 'current bus' is now implemented in the command line
rather than in the uclass. Also the address length does not need to
be specified with each command - really we should consider dropping
this from most commands but it works OK for now.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/cmd_i2c.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 267 insertions(+), 45 deletions(-)

diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index c266b88..6766856 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -69,8 +69,10 @@
 #include <bootretry.h>
 #include <cli.h>
 #include <command.h>
+#include <dm.h>
 #include <edid.h>
 #include <environment.h>
+#include <errno.h>
 #include <i2c.h>
 #include <malloc.h>
 #include <asm/byteorder.h>
@@ -117,6 +119,60 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES;
 
 #define DISP_LINE_LEN	16
 
+/*
+ * Default for driver model is to use the chip's existing address length.
+ * For legacy code, this is not stored, so we need to use a suitable
+ * default.
+ */
+#ifdef CONFIG_DM_I2C
+#define DEFAULT_ADDR_LEN	(-1)
+#else
+#define DEFAULT_ADDR_LEN	1
+#endif
+
+#ifdef CONFIG_DM_I2C
+static struct udevice *i2c_cur_bus;
+
+static int i2c_set_bus_num(unsigned int busnum)
+{
+	struct udevice *bus;
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
+	if (ret) {
+		debug("%s: No bus %d\n", __func__, busnum);
+		return ret;
+	}
+	i2c_cur_bus = bus;
+
+	return 0;
+}
+
+static int i2c_get_cur_bus(struct udevice **busp)
+{
+	if (!i2c_cur_bus) {
+		puts("No I2C bus selected\n");
+		return -ENODEV;
+	}
+	*busp = i2c_cur_bus;
+
+	return 0;
+}
+
+static int i2c_get_cur_bus_chip(uint chip_addr, struct udevice **devp)
+{
+	struct udevice *bus;
+	int ret;
+
+	ret = i2c_get_cur_bus(&bus);
+	if (ret)
+		return ret;
+
+	return i2c_get_chip(bus, chip_addr, devp);
+}
+
+#endif
+
 /**
  * i2c_init_board() - Board-specific I2C bus init
  *
@@ -143,7 +199,7 @@ void i2c_init_board(void)
  *
  * Returns I2C bus speed in Hz.
  */
-#if !defined(CONFIG_SYS_I2C)
+#if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_DM_I2C)
 /*
  * TODO: Implement architecture-specific get/set functions
  * Should go away, if we switched completely to new multibus support
@@ -182,12 +238,12 @@ int i2c_set_bus_speed(unsigned int speed)
  *
  * Returns the address length.
  */
-static uint get_alen(char *arg)
+static uint get_alen(char *arg, int default_len)
 {
 	int	j;
 	int	alen;
 
-	alen = 1;
+	alen = default_len;
 	for (j = 0; j < 8; j++) {
 		if (arg[j] == '.') {
 			alen = arg[j+1] - '0';
@@ -229,6 +285,10 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
 	u_char	chip;
 	uint	devaddr, alen, length;
 	u_char  *memaddr;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc != 5)
 		return CMD_RET_USAGE;
@@ -243,7 +303,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
 	 * 2 bytes long.  Some day it might be 3 bytes long :-).
 	 */
 	devaddr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
 
@@ -257,10 +317,18 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
 	 */
 	memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16);
 
-	if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) {
-		i2c_report_err(-1, I2C_ERR_READ);
-		return 1;
-	}
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (!ret)
+		ret = i2c_read(dev, devaddr, memaddr, length);
+#else
+	ret = i2c_read(chip, devaddr, alen, memaddr, length);
+#endif
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+
 	return 0;
 }
 
@@ -269,6 +337,10 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
 	u_char	chip;
 	uint	devaddr, alen, length;
 	u_char  *memaddr;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc != 5)
 		return cmd_usage(cmdtp);
@@ -288,7 +360,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
 	 * 2 bytes long.  Some day it might be 3 bytes long :-).
 	 */
 	devaddr = simple_strtoul(argv[3], NULL, 16);
-	alen = get_alen(argv[3]);
+	alen = get_alen(argv[3], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return cmd_usage(cmdtp);
 
@@ -297,10 +369,22 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
 	 */
 	length = simple_strtoul(argv[4], NULL, 16);
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
+
 	while (length-- > 0) {
-		if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) {
-			return i2c_report_err(-1, I2C_ERR_WRITE);
-		}
+#ifdef CONFIG_DM_I2C
+		ret = i2c_write(dev, devaddr++, memaddr++, 1);
+#else
+		ret = i2c_write(chip, devaddr++, alen, memaddr++, 1);
+#endif
+		if (ret)
+			return i2c_report_err(ret, I2C_ERR_WRITE);
 /*
  * No write delay with FRAM devices.
  */
@@ -329,6 +413,10 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	u_char	chip;
 	uint	addr, alen, length;
 	int	j, nbytes, linebytes;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	/* We use the last specified parameters, unless new ones are
 	 * entered.
@@ -356,7 +444,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 		 * 2 bytes long.  Some day it might be 3 bytes long :-).
 		 */
 		addr = simple_strtoul(argv[2], NULL, 16);
-		alen = get_alen(argv[2]);
+		alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 		if (alen > 3)
 			return CMD_RET_USAGE;
 
@@ -368,6 +456,14 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 			length = simple_strtoul(argv[3], NULL, 16);
 	}
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+#endif
+
 	/*
 	 * Print the lines.
 	 *
@@ -381,8 +477,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 
 		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
 
-		if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0)
-			i2c_report_err(-1, I2C_ERR_READ);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, linebuf, linebytes);
+#else
+		ret = i2c_read(chip, addr, alen, linebuf, linebytes);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_READ);
 		else {
 			printf("%04x:", addr);
 			cp = linebuf;
@@ -432,6 +533,10 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	uint	alen;
 	uchar	byte;
 	int	count;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if ((argc < 4) || (argc > 5))
 		return CMD_RET_USAGE;
@@ -445,10 +550,17 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	 * Address is always specified.
 	 */
 	addr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
 	/*
 	 * Value to write is always specified.
 	 */
@@ -463,8 +575,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 		count = 1;
 
 	while (count-- > 0) {
-		if (i2c_write(chip, addr++, alen, &byte, 1) != 0)
-			i2c_report_err(-1, I2C_ERR_WRITE);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_write(dev, addr++, &byte, 1);
+#else
+		ret = i2c_write(chip, addr++, alen, &byte, 1);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_WRITE);
 		/*
 		 * Wait for the write to complete.  The write can take
 		 * up to 10mSec (we allow a little more time).
@@ -504,6 +621,10 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	uchar	byte;
 	ulong	crc;
 	ulong	err;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc < 4)
 		return CMD_RET_USAGE;
@@ -517,10 +638,17 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	 * Address is always specified.
 	 */
 	addr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
+#endif
 	/*
 	 * Count is always specified
 	 */
@@ -534,13 +662,18 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	crc = 0;
 	err = 0;
 	while (count-- > 0) {
-		if (i2c_read(chip, addr, alen, &byte, 1) != 0)
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, &byte, 1);
+#else
+		ret = i2c_read(chip, addr, alen, &byte, 1);
+#endif
+		if (ret)
 			err++;
 		crc = crc32 (crc, &byte, 1);
 		addr++;
 	}
 	if (err > 0)
-		i2c_report_err(-1, I2C_ERR_READ);
+		i2c_report_err(ret, I2C_ERR_READ);
 	else
 		printf ("%08lx\n", crc);
 
@@ -572,6 +705,10 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
 	ulong	data;
 	int	size = 1;
 	int	nbytes;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc != 3)
 		return CMD_RET_USAGE;
@@ -601,19 +738,32 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
 		 * Address is always specified.
 		 */
 		addr = simple_strtoul(argv[2], NULL, 16);
-		alen = get_alen(argv[2]);
+		alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 		if (alen > 3)
 			return CMD_RET_USAGE;
 	}
 
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
+
 	/*
 	 * Print the address, followed by value.  Then accept input for
 	 * the next value.  A non-converted value exits.
 	 */
 	do {
 		printf("%08lx:", addr);
-		if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0)
-			i2c_report_err(-1, I2C_ERR_READ);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, (uchar *)&data, size);
+#else
+		ret = i2c_read(chip, addr, alen, (uchar *)&data, size);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_READ);
 		else {
 			data = cpu_to_be32(data);
 			if (size == 1)
@@ -655,8 +805,15 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
 				 * good enough to not time out
 				 */
 				bootretry_reset_cmd_timeout();
-				if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0)
-					i2c_report_err(-1, I2C_ERR_WRITE);
+#ifdef CONFIG_DM_I2C
+				ret = i2c_write(dev, addr, (uchar *)&data,
+						size);
+#else
+				ret = i2c_write(chip, addr, alen,
+						(uchar *)&data, size);
+#endif
+				if (ret)
+					i2c_report_err(ret, I2C_ERR_WRITE);
 #ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
 				udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
 #endif
@@ -697,6 +854,13 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
 	int k, skip;
 	unsigned int bus = GET_BUS_NUM;
 #endif	/* NOPROBES */
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *bus;
+
+	if (i2c_get_cur_bus(&bus))
+		return CMD_RET_FAILURE;
+#endif
 
 	if (argc == 2)
 		addr = simple_strtol(argv[1], 0, 16);
@@ -717,7 +881,12 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
 		if (skip)
 			continue;
 #endif
-		if (i2c_probe(j) == 0) {
+#ifdef CONFIG_DM_I2C
+		ret = i2c_probe(bus, j);
+#else
+		ret = i2c_probe(j);
+#endif
+		if (ret == 0) {
 			printf(" %02X", j);
 			found++;
 		}
@@ -759,6 +928,10 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	uint	length;
 	u_char	bytes[16];
 	int	delay;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc < 3)
 		return CMD_RET_USAGE;
@@ -772,9 +945,16 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	 * Address is always specified.
 	 */
 	addr = simple_strtoul(argv[2], NULL, 16);
-	alen = get_alen(argv[2]);
+	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
 	if (alen > 3)
 		return CMD_RET_USAGE;
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret && alen != -1)
+		ret = i2c_set_addr_len(dev, alen);
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_WRITE);
+#endif
 
 	/*
 	 * Length is the number of objects, not number of bytes.
@@ -794,8 +974,13 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
 	 * Run the loop...
 	 */
 	while (1) {
-		if (i2c_read(chip, addr, alen, bytes, length) != 0)
-			i2c_report_err(-1, I2C_ERR_READ);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_read(dev, addr, bytes, length);
+#else
+		ret = i2c_read(chip, addr, alen, bytes, length);
+#endif
+		if (ret)
+			i2c_report_err(ret, I2C_ERR_READ);
 		udelay(delay);
 	}
 
@@ -1345,6 +1530,10 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	u_char chip;
 	struct edid1_info edid;
+	int ret;
+#ifdef CONFIG_DM_I2C
+	struct udevice *dev;
+#endif
 
 	if (argc < 2) {
 		cmd_usage(cmdtp);
@@ -1352,10 +1541,15 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 	}
 
 	chip = simple_strtoul(argv[1], NULL, 16);
-	if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) {
-		i2c_report_err(-1, I2C_ERR_READ);
-		return 1;
-	}
+#ifdef CONFIG_DM_I2C
+	ret = i2c_get_cur_bus_chip(chip, &dev);
+	if (!ret)
+		ret = i2c_read(dev, 0, (uchar *)&edid, sizeof(edid));
+#else
+	ret = i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid));
+#endif
+	if (ret)
+		return i2c_report_err(ret, I2C_ERR_READ);
 
 	if (edid_check_info(&edid)) {
 		puts("Content isn't valid EDID.\n");
@@ -1437,17 +1631,28 @@ static int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,
  * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
  * on error.
  */
-#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS)
+#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) || \
+		defined(CONFIG_DM_I2C)
 static int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
 				char * const argv[])
 {
 	int		ret = 0;
-	unsigned int	bus_no;
+	int	bus_no;
 
-	if (argc == 1)
+	if (argc == 1) {
 		/* querying current setting */
-		printf("Current bus is %d\n", i2c_get_bus_num());
-	else {
+#ifdef CONFIG_DM_I2C
+		struct udevice *bus;
+
+		if (!i2c_get_cur_bus(&bus))
+			bus_no = bus->seq;
+		else
+			bus_no = -1;
+#else
+		bus_no = i2c_get_bus_num();
+#endif
+		printf("Current bus is %d\n", bus_no);
+	} else {
 		bus_no = simple_strtoul(argv[1], NULL, 10);
 #if defined(CONFIG_SYS_I2C)
 		if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) {
@@ -1478,13 +1683,28 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const
 {
 	int speed, ret=0;
 
-	if (argc == 1)
+#ifdef CONFIG_DM_I2C
+	struct udevice *bus;
+
+	if (i2c_get_cur_bus(&bus))
+		return 1;
+#endif
+	if (argc == 1) {
+#ifdef CONFIG_DM_I2C
+		speed = i2c_get_bus_speed(bus);
+#else
+		speed = i2c_get_bus_speed();
+#endif
 		/* querying current speed */
-		printf("Current bus speed=%d\n", i2c_get_bus_speed());
-	else {
+		printf("Current bus speed=%d\n", speed);
+	} else {
 		speed = simple_strtoul(argv[1], NULL, 10);
 		printf("Setting bus speed to %d Hz\n", speed);
+#ifdef CONFIG_DM_I2C
+		ret = i2c_set_bus_speed(bus, speed);
+#else
 		ret = i2c_set_bus_speed(speed);
+#endif
 		if (ret)
 			printf("Failure changing bus speed (%d)\n", ret);
 	}
@@ -1532,7 +1752,9 @@ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
  */
 static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
-#if defined(CONFIG_SYS_I2C)
+#if defined(CONFIG_DM_I2C)
+	/* TODO(sjg at chromium.org): What should we do here? */
+#elif defined(CONFIG_SYS_I2C)
 	i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr);
 #else
 	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
@@ -1546,7 +1768,7 @@ static cmd_tbl_t cmd_i2c_sub[] = {
 #endif
 	U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""),
 #if defined(CONFIG_SYS_I2C) || \
-	defined(CONFIG_I2C_MULTI_BUS)
+	defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C)
 	U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),
 #endif  /* CONFIG_I2C_MULTI_BUS */
 #if defined(CONFIG_I2C_EDID)
@@ -1610,7 +1832,7 @@ static char i2c_help_text[] =
 #endif
 	"crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n"
 #if defined(CONFIG_SYS_I2C) || \
-	defined(CONFIG_I2C_MULTI_BUS)
+	defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C)
 	"i2c dev [dev] - show or set current I2C bus\n"
 #endif  /* CONFIG_I2C_MULTI_BUS */
 #if defined(CONFIG_I2C_EDID)
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 05/12] dm: i2c: Add I2C emulation driver for sandbox
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (3 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 04/12] dm: i2c: Implement driver model support in the i2c command Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 06/12] dm: i2c: Add a sandbox I2C driver Simon Glass
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

In order to test I2C we need some sort of emulation interface. Add hooks
to allow a driver to emulate an I2C device for sandbox.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/i2c/Makefile          |  1 +
 drivers/i2c/i2c-emul-uclass.c | 14 ++++++++++++++
 include/dm/uclass-id.h        |  1 +
 3 files changed, 16 insertions(+)
 create mode 100644 drivers/i2c/i2c-emul-uclass.c

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 2ee468d..10edea6 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o
 obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
+obj-$(CONFIG_SYS_I2C_SANDBOX) += i2c-emul-uclass.o
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c
new file mode 100644
index 0000000..aa89f95
--- /dev/null
+++ b/drivers/i2c/i2c-emul-uclass.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+
+UCLASS_DRIVER(i2c_emul) = {
+	.id		= UCLASS_I2C_EMUL,
+	.name		= "i2c_emul",
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 9611a13..9e20d31 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -19,6 +19,7 @@ enum uclass_id {
 	UCLASS_TEST_FDT,
 	UCLASS_TEST_BUS,
 	UCLASS_SPI_EMUL,	/* sandbox SPI device emulator */
+	UCLASS_I2C_EMUL,	/* sandbox I2C device emulator */
 	UCLASS_SIMPLE_BUS,
 
 	/* U-Boot uclasses start here */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 06/12] dm: i2c: Add a sandbox I2C driver
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (4 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 05/12] dm: i2c: Add I2C emulation driver for sandbox Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 07/12] dm: i2c: Add an I2C EEPROM simulator Simon Glass
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

This driver includes some test features such as only supporting certain
bus speeds. It passes its I2C traffic through to an emulator.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/i2c/Makefile      |   2 +-
 drivers/i2c/sandbox_i2c.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 149 insertions(+), 1 deletion(-)
 create mode 100644 drivers/i2c/sandbox_i2c.c

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 10edea6..ea18228 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -27,7 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o
 obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
-obj-$(CONFIG_SYS_I2C_SANDBOX) += i2c-emul-uclass.o
+obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
new file mode 100644
index 0000000..3beb0f9
--- /dev/null
+++ b/drivers/i2c/sandbox_i2c.c
@@ -0,0 +1,148 @@
+/*
+ * Simulate an I2C port
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct dm_sandbox_i2c_emul_priv {
+	struct udevice *emul;
+};
+
+static int get_emul(struct udevice *bus, uint chip_addr, struct udevice **devp,
+		    struct dm_i2c_ops **opsp)
+{
+	const void *blob = gd->fdt_blob;
+	struct dm_i2c_chip *priv;
+	struct udevice *dev;
+	int ret;
+
+	ret = i2c_get_chip(bus, chip_addr, &dev);
+	if (ret)
+		return ret;
+	priv = dev_get_parentdata(dev);
+	if (!priv->emul) {
+		int node;
+
+		debug("Scanning i2c bus '%s' for devices\n", dev->name);
+		for (node = fdt_first_subnode(blob, dev->of_offset);
+			node >= 0;
+			node = fdt_next_subnode(blob, node)) {
+			int ret;
+
+			ret = lists_bind_fdt(dev, blob, node, &priv->emul);
+			if (ret)
+				return ret;
+			debug("Found emul '%s' for i2c device '%s'\n",
+			      priv->emul->name, dev->name);
+			break;
+		}
+	}
+
+	if (!priv->emul)
+		return -ENODEV;
+	ret = device_probe(priv->emul);
+	if (ret)
+		return ret;
+	*devp = priv->emul;
+	*opsp = i2c_get_ops(priv->emul);
+
+	return 0;
+}
+
+static int sandbox_i2c_probe_chip(struct udevice *bus, uint chip_addr)
+{
+	struct dm_i2c_ops *ops;
+	struct udevice *emul;
+	int ret;
+
+	ret = get_emul(bus, chip_addr, &emul, &ops);
+	if (ret)
+		return ret;
+
+	return ops->probe(emul, chip_addr);
+}
+
+static int sandbox_i2c_read(struct udevice *bus, uint chip_addr, uint addr,
+			    uint alen, uint8_t *buffer, int len)
+{
+	struct dm_i2c_bus *i2c = bus->uclass_priv;
+	struct dm_i2c_ops *ops;
+	struct udevice *emul;
+	int ret;
+
+	ret = get_emul(bus, chip_addr, &emul, &ops);
+	if (ret)
+		return ret;
+
+	/* For testing, don't allow reading above 400KHz */
+	if (i2c->speed_hz > 400000 || alen != 1)
+		return -EINVAL;
+	return ops->read(emul, chip_addr, addr, alen, buffer, len);
+}
+
+static int sandbox_i2c_write(struct udevice *bus, uint chip_addr, uint addr,
+			     uint alen, const uint8_t *buffer, int len)
+{
+	struct dm_i2c_bus *i2c = bus->uclass_priv;
+	struct dm_i2c_ops *ops;
+	struct udevice *emul;
+	int ret;
+
+	ret = get_emul(bus, chip_addr, &emul, &ops);
+	if (ret)
+		return ret;
+
+	/* For testing, don't allow writing above 100KHz */
+	if (i2c->speed_hz > 100000 || alen != 1)
+		return -EINVAL;
+	return ops->write(emul, chip_addr, addr, alen, buffer, len);
+}
+
+static int sandbox_i2c_set_addr_len(struct udevice *dev, uint addr_len)
+{
+	if (addr_len == 3)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct dm_i2c_ops sandbox_i2c_ops = {
+	.probe		= sandbox_i2c_probe_chip,
+	.read		= sandbox_i2c_read,
+	.write		= sandbox_i2c_write,
+	.set_addr_len	= sandbox_i2c_set_addr_len,
+};
+
+static int sandbox_i2c_child_pre_probe(struct udevice *dev)
+{
+	struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
+
+	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+					   i2c_chip);
+}
+
+static const struct udevice_id sandbox_i2c_ids[] = {
+	{ .compatible = "sandbox,i2c" },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_sandbox) = {
+	.name	= "i2c_sandbox",
+	.id	= UCLASS_I2C,
+	.of_match = sandbox_i2c_ids,
+	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+	.child_pre_probe = sandbox_i2c_child_pre_probe,
+	.ops	= &sandbox_i2c_ops,
+};
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 07/12] dm: i2c: Add an I2C EEPROM simulator
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (5 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 06/12] dm: i2c: Add a sandbox I2C driver Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 08/12] dm: i2c: config: Enable I2C for sandbox using driver model Simon Glass
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

To enable testing of I2C, add a simple I2C EEPROM simulator for sandbox.
It supports reading and writing from a small data store.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/misc/Makefile          |   3 ++
 drivers/misc/i2c_eeprom_emul.c | 108 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
 create mode 100644 drivers/misc/i2c_eeprom_emul.c

diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2f2e48f..ff02184 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -20,6 +20,9 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
 obj-$(CONFIG_NS87308) += ns87308.o
 obj-$(CONFIG_PDSP188x) += pdsp188x.o
+ifdef CONFIG_DM_I2C
+obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
+endif
 obj-$(CONFIG_STATUS_LED) += status_led.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c
new file mode 100644
index 0000000..9a4c385
--- /dev/null
+++ b/drivers/misc/i2c_eeprom_emul.c
@@ -0,0 +1,108 @@
+/*
+ * Simulate an I2C eeprom
+ *
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sandbox_i2c_flash_plat_data {
+	const char *filename;
+	int size;
+};
+
+struct sandbox_i2c_flash {
+	uint8_t *data;
+};
+
+static int sandbox_i2c_eprom_probe_chip(struct udevice *dev, uint chip)
+{
+	return 0;
+}
+
+static int sandbox_i2c_eprom_read(struct udevice *dev, uint chip_addr,
+				  uint addr, uint alen, uint8_t *buffer,
+				  int len)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+	if (addr + len > plat->size)
+		return -EINVAL;
+	memcpy(buffer, priv->data + addr, len);
+
+	return 0;
+}
+
+static int sandbox_i2c_eprom_write(struct udevice *dev, uint chip_addr,
+				   uint addr, uint alen, const uint8_t *buffer,
+				   int len)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+	if (addr + len > plat->size)
+		return -EINVAL;
+	memcpy(priv->data + addr, buffer, len);
+
+	return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_emul_ops = {
+	.probe = sandbox_i2c_eprom_probe_chip,
+	.read = sandbox_i2c_eprom_read,
+	.write = sandbox_i2c_eprom_write,
+};
+
+static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+
+	plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				    "sandbox,size", 32);
+	plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset,
+				     "sandbox,filename", NULL);
+	if (!plat->filename) {
+		debug("%s: No filename for device '%s'\n", __func__,
+		      dev->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sandbox_i2c_eeprom_probe(struct udevice *dev)
+{
+	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
+	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
+
+	priv->data = calloc(1, plat->size);
+	if (!priv->data)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_i2c_ids[] = {
+	{ .compatible = "sandbox,i2c-eeprom" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_emul) = {
+	.name		= "sandbox_i2c_eeprom_emul",
+	.id		= UCLASS_I2C_EMUL,
+	.of_match	= sandbox_i2c_ids,
+	.ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata,
+	.probe		= sandbox_i2c_eeprom_probe,
+	.priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash),
+	.platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data),
+	.ops		= &sandbox_i2c_emul_ops,
+};
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 08/12] dm: i2c: config: Enable I2C for sandbox using driver model
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (6 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 07/12] dm: i2c: Add an I2C EEPROM simulator Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 09/12] dm: i2c: dts: Add an I2C bus for sandbox Simon Glass
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

Enable the options to bring up I2C on sandbox. Also enable all the available
I2C commands for testing purposes.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 include/configs/sandbox.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 2fd2c64..c5b46ac 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -110,6 +110,12 @@
 #define CONFIG_SPI_FLASH_STMICRO
 #define CONFIG_SPI_FLASH_WINBOND
 
+#define CONFIG_DM_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SANDBOX
+#define CONFIG_I2C_EDID
+#define CONFIG_I2C_EEPROM
+
 /* Memory things - we don't really want a memory test */
 #define CONFIG_SYS_LOAD_ADDR		0x00000000
 #define CONFIG_SYS_MEMTEST_START	0x00100000
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 09/12] dm: i2c: dts: Add an I2C bus for sandbox
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (7 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 08/12] dm: i2c: config: Enable I2C for sandbox using driver model Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 10/12] dm: WIP: EEPROM driver Simon Glass
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

Add an I2C bus to the device tree, with an EEPROM emulator attached to one
of the addresses.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/sandbox/dts/sandbox.dts | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 7614715..11748ae 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -134,6 +134,23 @@
 		num-gpios = <20>;
 	};
 
+	i2c at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "sandbox,i2c";
+		clock-frequency = <400000>;
+		eeprom at 2c {
+			reg = <0x2c>;
+			compatible = "i2c-eeprom";
+			emul {
+				compatible = "sandbox,i2c-eeprom";
+				sandbox,filename = "i2c.bin";
+				sandbox,size = <128>;
+			};
+		};
+	};
+
 	spi at 0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 10/12] dm: WIP: EEPROM driver
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (8 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 09/12] dm: i2c: dts: Add an I2C bus for sandbox Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 11/12] dm: i2c: Add tests for I2C Simon Glass
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

There seem to be a few EEPROM drivers around - perhaps we should have a
single standard one?

This is little more than a placeholder at present.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/misc/Makefile     |  1 +
 drivers/misc/i2c_eeprom.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h    |  1 +
 include/i2c_eeprom.h      | 19 ++++++++++++++++++
 4 files changed, 72 insertions(+)
 create mode 100644 drivers/misc/i2c_eeprom.c
 create mode 100644 include/i2c_eeprom.h

diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index ff02184..6fa836f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
 obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
 obj-$(CONFIG_FSL_IIM) += fsl_iim.o
 obj-$(CONFIG_GPIO_LED) += gpio_led.o
+obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o
 obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
 obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
new file mode 100644
index 0000000..d0548ec
--- /dev/null
+++ b/drivers/misc/i2c_eeprom.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2c_eeprom.h>
+
+static int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf,
+			   int size)
+{
+	return -ENODEV;
+}
+
+static int i2c_eeprom_write(struct udevice *dev, int offset,
+			    const uint8_t *buf, int size)
+{
+	return -ENODEV;
+}
+
+struct i2c_eeprom_ops i2c_eeprom_std_ops = {
+	.read	= i2c_eeprom_read,
+	.write	= i2c_eeprom_write,
+};
+
+int i2c_eeprom_std_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct udevice_id i2c_eeprom_std_ids[] = {
+	{ .compatible = "i2c-eeprom" },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_eeprom_std) = {
+	.name		= "i2c_eeprom",
+	.id		= UCLASS_I2C_EEPROM,
+	.of_match	= i2c_eeprom_std_ids,
+	.probe		= i2c_eeprom_std_probe,
+	.priv_auto_alloc_size = sizeof(struct i2c_eeprom),
+	.ops		= &i2c_eeprom_std_ops,
+};
+
+UCLASS_DRIVER(i2c_eeprom) = {
+	.id		= UCLASS_I2C_EEPROM,
+	.name		= "i2c_eeprom",
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 9e20d31..8f389df 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -30,6 +30,7 @@ enum uclass_id {
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
 	UCLASS_I2C,		/* I2C bus */
+	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h
new file mode 100644
index 0000000..ea6c962
--- /dev/null
+++ b/include/i2c_eeprom.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __I2C_EEPROM
+#define __I2C_EEPROM
+
+struct i2c_eeprom_ops {
+	int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size);
+	int (*write)(struct udevice *dev, int offset, const uint8_t *buf,
+		     int size);
+};
+
+struct i2c_eeprom {
+};
+
+#endif
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 11/12] dm: i2c: Add tests for I2C
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (9 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 10/12] dm: WIP: EEPROM driver Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 12/12] dm: i2c: tegra: Convert to driver model for I2C for seaboard Simon Glass
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

Add some basic tests to check that the system works as expected.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 test/dm/Makefile |   1 +
 test/dm/i2c.c    | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/dm/test.dts |  17 ++++++++++
 3 files changed, 118 insertions(+)
 create mode 100644 test/dm/i2c.c

diff --git a/test/dm/Makefile b/test/dm/Makefile
index 75d3d41..612aa95 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -20,4 +20,5 @@ ifneq ($(CONFIG_SANDBOX),)
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_SPI) += spi.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
+obj-$(CONFIG_DM_I2C) += i2c.o
 endif
diff --git a/test/dm/i2c.c b/test/dm/i2c.c
new file mode 100644
index 0000000..d2ee19d
--- /dev/null
+++ b/test/dm/i2c.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <dm/device-internal.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <dm/ut.h>
+#include <dm/util.h>
+#include <asm/state.h>
+
+static const int busnum;
+static const int chip = 0x2c;
+
+/* Test that we can find buses and chips */
+static int dm_test_i2c_find(struct dm_test_state *dms)
+{
+	struct udevice *bus;
+	const int no_chip = 0x10;
+
+	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_I2C, busnum,
+						       false, &bus));
+
+	/*
+	 * i2c_post_bind() will bind devices to chip selects. Check this then
+	 * remove the emulation and the slave device.
+	 */
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_probe(bus, chip));
+	ut_asserteq(-ENODEV, i2c_probe(bus, no_chip));
+	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_I2C, 1, &bus));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_read_write(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
+	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(memcmp(buf, "\0\0AB\0", sizeof(buf)));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_read_write, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_speed(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_set_bus_speed(bus, 100000));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(i2c_set_bus_speed(bus, 400000));
+	ut_asserteq(400000, i2c_get_bus_speed(bus));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_asserteq(-EINVAL, i2c_write(dev, 0, buf, 5));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_speed, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_i2c_addr_len(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	uint8_t buf[5];
+
+	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
+	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_set_addr_len(dev, 1));
+	ut_assertok(i2c_read(dev, 0, buf, 5));
+
+	/* The sandbox driver allows this setting, but then fails reads */
+	ut_assertok(i2c_set_addr_len(dev, 2));
+	ut_asserteq(-EINVAL, i2c_read(dev, 0, buf, 5));
+
+	/* This is not supported by the uclass */
+	ut_asserteq(-EINVAL, i2c_set_addr_len(dev, 4));
+
+	/* This is faulted by the sandbox driver */
+	ut_asserteq(-EINVAL, i2c_set_addr_len(dev, 3));
+
+	return 0;
+}
+DM_TEST(dm_test_i2c_addr_len, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test.dts b/test/dm/test.dts
index 1fba792..69991a3 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -93,6 +93,23 @@
 		num-gpios = <10>;
 	};
 
+	i2c at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "sandbox,i2c";
+		clock-frequency = <100000>;
+		eeprom at 2c {
+			reg = <0x2c>;
+			compatible = "i2c-eeprom";
+			emul {
+				compatible = "sandbox,i2c-eeprom";
+				sandbox,filename = "i2c.bin";
+				sandbox,size = <128>;
+			};
+		};
+	};
+
 	spi at 0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 12/12] dm: i2c: tegra: Convert to driver model for I2C for seaboard
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (10 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 11/12] dm: i2c: Add tests for I2C Simon Glass
@ 2014-10-13  5:39 ` Simon Glass
  2014-10-24 15:03 ` [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Tom Rini
  2014-11-10  7:16 ` Heiko Schocher
  13 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-10-13  5:39 UTC (permalink / raw)
  To: u-boot

This converts seaboard over to use driver model for I2C. This is so far
untested and only useful for broad comments / review. To complete this,
trimslice and whistler will also need conversion.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/arm/cpu/tegra20-common/pmu.c           |  21 +-
 arch/arm/include/asm/arch-tegra/tegra_i2c.h |   2 +-
 board/nvidia/common/board.c                 |   4 -
 drivers/i2c/tegra_i2c.c                     | 313 ++++++++++------------------
 drivers/power/tps6586x.c                    |  27 +--
 include/configs/cardhu.h                    |   2 -
 include/configs/colibri_t30.h               |   2 -
 include/configs/seaboard.h                  |   3 -
 include/configs/tegra-common.h              |   1 +
 include/configs/tegra20-common.h            |   3 -
 include/tps6586x.h                          |   2 +-
 11 files changed, 140 insertions(+), 240 deletions(-)

diff --git a/arch/arm/cpu/tegra20-common/pmu.c b/arch/arm/cpu/tegra20-common/pmu.c
index c595f70..36a76a2 100644
--- a/arch/arm/cpu/tegra20-common/pmu.c
+++ b/arch/arm/cpu/tegra20-common/pmu.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <i2c.h>
 #include <tps6586x.h>
 #include <asm/io.h>
 #include <asm/arch/tegra.h>
@@ -23,9 +24,13 @@
 #define VDD_TRANSITION_STEP	0x06	/* 150mv */
 #define VDD_TRANSITION_RATE	0x06	/* 3.52mv/us */
 
+#define PMI_I2C_ADDRESS	0x34	/* chip requires this address */
+
 int pmu_set_nominal(void)
 {
-	int core, cpu, bus;
+	struct udevice *bus, *dev;
+	int core, cpu;
+	int ret;
 
 	/* by default, the table has been filled with T25 settings */
 	switch (tegra_get_chip_sku()) {
@@ -42,12 +47,18 @@ int pmu_set_nominal(void)
 		return -1;
 	}
 
-	bus = tegra_i2c_get_dvc_bus_num();
-	if (bus == -1) {
+	ret = tegra_i2c_get_dvc_bus(&bus);
+	if (ret) {
 		debug("%s: Cannot find DVC I2C bus\n", __func__);
-		return -1;
+		return ret;
 	}
-	tps6586x_init(bus);
+	ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, &dev);
+	if (ret) {
+		debug("%s: Cannot find DVC I2C chip\n", __func__);
+		return ret;
+	}
+
+	tps6586x_init(dev);
 	tps6586x_set_pwm_mode(TPS6586X_PWM_SM1);
 	return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP,
 				VDD_TRANSITION_RATE, VDD_RELATION);
diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
index 7ca6907..eeeb247 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
@@ -167,6 +167,6 @@ struct i2c_ctlr {
  *
  * @return number of bus, or -1 if there is no DVC active
  */
-int tegra_i2c_get_dvc_bus_num(void);
+int tegra_i2c_get_dvc_bus(struct udevice **busp);
 
 #endif	/* _TEGRA_I2C_H_ */
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index 03f055d..7226fa4 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -132,10 +132,6 @@ int board_init(void)
 	power_det_init();
 
 #ifdef CONFIG_SYS_I2C_TEGRA
-#ifndef CONFIG_SYS_I2C_INIT_BOARD
-#error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards"
-#endif
-	i2c_init_board();
 # ifdef CONFIG_TEGRA_PMU
 	if (pmu_set_nominal())
 		debug("Failed to select nominal voltages\n");
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index 257b72f..85a6837 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -7,6 +7,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <asm/io.h>
@@ -19,6 +21,12 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+enum i2c_type {
+	TYPE_114,
+	TYPE_STD,
+	TYPE_DVC,
+};
+
 /* Information about i2c controller */
 struct i2c_bus {
 	int			id;
@@ -27,20 +35,17 @@ struct i2c_bus {
 	int			pinmux_config;
 	struct i2c_control	*control;
 	struct i2c_ctlr		*regs;
-	int			is_dvc;	/* DVC type, rather than I2C */
-	int			is_scs;	/* single clock source (T114+) */
+	enum i2c_type		type;
 	int			inited;	/* bus is inited */
 };
 
-static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS];
-
 static void set_packet_mode(struct i2c_bus *i2c_bus)
 {
 	u32 config;
 
 	config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
 
-	if (i2c_bus->is_dvc) {
+	if (i2c_bus->type == TYPE_DVC) {
 		struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
 
 		writel(config, &dvc->cnfg);
@@ -73,7 +78,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
 	clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
 		i2c_bus->speed * 2 * 8);
 
-	if (i2c_bus->is_scs) {
+	if (i2c_bus->type == TYPE_114) {
 		/*
 		 * T114 I2C went to a single clock source for standard/fast and
 		 * HS clock speeds. The new clock rate setting calculation is:
@@ -98,7 +103,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
 	i2c_reset_controller(i2c_bus);
 
 	/* Configure I2C controller. */
-	if (i2c_bus->is_dvc) {	/* only for DVC I2C */
+	if (i2c_bus->type == TYPE_DVC) {	/* only for DVC I2C */
 		struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
 
 		setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
@@ -272,7 +277,7 @@ exit:
 	return error;
 }
 
-static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
 				u32 len, bool end_with_repeated_start)
 {
 	int error;
@@ -286,14 +291,14 @@ static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
 	trans_info.num_bytes = len;
 	trans_info.is_10bit_address = 0;
 
-	error = send_recv_packets(bus, &trans_info);
+	error = send_recv_packets(i2c_bus, &trans_info);
 	if (error)
 		debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
 
 	return error;
 }
 
-static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
+static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
 			       u32 len)
 {
 	int error;
@@ -305,7 +310,7 @@ static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
 	trans_info.num_bytes = len;
 	trans_info.is_10bit_address = 0;
 
-	error = send_recv_packets(bus, &trans_info);
+	error = send_recv_packets(i2c_bus, &trans_info);
 	if (error)
 		debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
 
@@ -316,41 +321,25 @@ static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
 #error "Please enable device tree support to use this driver"
 #endif
 
-/**
- * Check that a bus number is valid and return a pointer to it
- *
- * @param bus_num	Bus number to check / return
- * @return pointer to bus, if valid, else NULL
- */
-static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap)
+static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 {
-	struct i2c_bus *bus;
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
 
-	bus = &i2c_controllers[adap->hwadapnr];
-	if (!bus->inited) {
-		debug("%s: Bus %u not available\n", __func__, adap->hwadapnr);
-		return NULL;
-	}
-
-	return bus;
-}
-
-static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap,
-			unsigned int speed)
-{
-	struct i2c_bus *bus;
-
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 0;
-	bus->speed = speed;
-	i2c_init_controller(bus);
+	i2c_bus->speed = speed;
+	i2c_init_controller(i2c_bus);
 
 	return 0;
 }
 
-static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
+static int tegra_i2c_probe(struct udevice *dev)
 {
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	bool is_dvc;
+
+	i2c_bus->id = dev->seq;
+	i2c_bus->type = dev_get_of_data(dev);
 	i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
 
 	/*
@@ -358,7 +347,6 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
 	 * far no one needs anything other than the default.
 	 */
 	i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
-	i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0);
 	i2c_bus->periph_id = clock_decode_periph_id(blob, node);
 
 	/*
@@ -371,107 +359,25 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
 	 *		i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
 	 */
 	if (i2c_bus->periph_id == -1)
-		return -FDT_ERR_NOTFOUND;
-
-	return 0;
-}
+		return -EINVAL;
 
-/*
- * Process a list of nodes, adding them to our list of I2C ports.
- *
- * @param blob		fdt blob
- * @param node_list	list of nodes to process (any <=0 are ignored)
- * @param count		number of nodes to process
- * @param is_dvc	1 if these are DVC ports, 0 if standard I2C
- * @param is_scs	1 if this HW uses a single clock source (T114+)
- * @return 0 if ok, -1 on error
- */
-static int process_nodes(const void *blob, int node_list[], int count,
-			 int is_dvc, int is_scs)
-{
-	struct i2c_bus *i2c_bus;
-	int i;
-
-	/* build the i2c_controllers[] for each controller */
-	for (i = 0; i < count; i++) {
-		int node = node_list[i];
-
-		if (node <= 0)
-			continue;
-
-		i2c_bus = &i2c_controllers[i];
-		i2c_bus->id = i;
-
-		if (i2c_get_config(blob, node, i2c_bus)) {
-			printf("i2c_init_board: failed to decode bus %d\n", i);
-			return -1;
-		}
-
-		i2c_bus->is_scs = is_scs;
-
-		i2c_bus->is_dvc = is_dvc;
-		if (is_dvc) {
-			i2c_bus->control =
-				&((struct dvc_ctlr *)i2c_bus->regs)->control;
-		} else {
-			i2c_bus->control = &i2c_bus->regs->control;
-		}
-		debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
-		      is_dvc ? "dvc" : "i2c", i, i2c_bus->regs,
-		      i2c_bus->periph_id, i2c_bus->speed);
-		i2c_init_controller(i2c_bus);
-		debug("ok\n");
-		i2c_bus->inited = 1;
-
-		/* Mark position as used */
-		node_list[i] = -1;
+	is_dvc = dev_get_of_data(dev) == TYPE_DVC;
+	if (is_dvc) {
+		i2c_bus->control =
+			&((struct dvc_ctlr *)i2c_bus->regs)->control;
+	} else {
+		i2c_bus->control = &i2c_bus->regs->control;
 	}
+	i2c_init_controller(i2c_bus);
+	debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
+	      is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
+	      i2c_bus->periph_id, i2c_bus->speed);
 
 	return 0;
 }
 
-/* Sadly there is no error return from this function */
-void i2c_init_board(void)
-{
-	int node_list[TEGRA_I2C_NUM_CONTROLLERS];
-	const void *blob = gd->fdt_blob;
-	int count;
-
-	/* First check for newer (T114+) I2C ports */
-	count = fdtdec_find_aliases_for_id(blob, "i2c",
-			COMPAT_NVIDIA_TEGRA114_I2C, node_list,
-			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 0, 1))
-		return;
-
-	/* Now get the older (T20/T30) normal I2C ports */
-	count = fdtdec_find_aliases_for_id(blob, "i2c",
-			COMPAT_NVIDIA_TEGRA20_I2C, node_list,
-			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 0, 0))
-		return;
-
-	/* Now look for dvc ports */
-	count = fdtdec_add_aliases_for_id(blob, "i2c",
-			COMPAT_NVIDIA_TEGRA20_DVC, node_list,
-			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 1, 0))
-		return;
-}
-
-static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
-{
-	/* No i2c support prior to relocation */
-	if (!(gd->flags & GD_FLG_RELOC))
-		return;
-
-	/* This will override the speed selected in the fdt for that port */
-	debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
-	i2c_set_bus_speed(speed);
-}
-
 /* i2c write version without the register address */
-int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len,
+int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer, int len,
 		   bool end_with_repeated_start)
 {
 	int rc;
@@ -484,7 +390,7 @@ int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len,
 	debug("\n");
 
 	/* Shift 7-bit address over for lower-level i2c functions */
-	rc = tegra_i2c_write_data(bus, chip << 1, buffer, len,
+	rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
 				  end_with_repeated_start);
 	if (rc)
 		debug("i2c_write_data(): rc=%d\n", rc);
@@ -493,13 +399,13 @@ int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len,
 }
 
 /* i2c read version without the register address */
-int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
+int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer, int len)
 {
 	int rc;
 
 	debug("inside i2c_read_data():\n");
 	/* Shift 7-bit address over for lower-level i2c functions */
-	rc = tegra_i2c_read_data(bus, chip << 1, buffer, len);
+	rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
 	if (rc) {
 		debug("i2c_read_data(): rc=%d\n", rc);
 		return rc;
@@ -515,48 +421,41 @@ int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
 }
 
 /* Probe to see if a chip is present. */
-static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip)
+static int tegra_i2c_probe_chip(struct udevice *dev, uint chip)
 {
-	struct i2c_bus *bus;
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
 	int rc;
 	uchar reg;
 
 	debug("i2c_probe: addr=0x%x\n", chip);
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 1;
 	reg = 0;
-	rc = i2c_write_data(bus, chip, &reg, 1, false);
+	rc = i2c_write_data(i2c_bus, chip, &reg, 1, false);
 	if (rc) {
 		debug("Error probing 0x%x.\n", chip);
-		return 1;
+		return rc;
 	}
 	return 0;
 }
 
-static int i2c_addr_ok(const uint addr, const int alen)
+static int tegra_i2c_set_addr_len(struct udevice *dev, const uint alen)
 {
 	/* We support 7 or 10 bit addresses, so one or two bytes each */
-	return alen == 1 || alen == 2;
+	if (alen == 1 || alen == 2)
+		return 0;
+
+	return -EINVAL;
 }
 
 /* Read bytes */
-static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
-			int alen, uchar *buffer, int len)
+static int tegra_i2c_read(struct udevice *dev, uint chip_addr, uint addr,
+			  uint alen, uchar *buffer, int len)
 {
-	struct i2c_bus *bus;
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
 	uint offset;
 	int i;
 
 	debug("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n",
-	      chip, addr, alen, len);
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 1;
-	if (!i2c_addr_ok(addr, alen)) {
-		debug("i2c_read: Bad address %x.%d.\n", addr, alen);
-		return 1;
-	}
+	      chip_addr, addr, alen, len);
 	for (offset = 0; offset < len; offset++) {
 		if (alen) {
 			uchar data[alen];
@@ -564,13 +463,14 @@ static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
 				data[alen - i - 1] =
 					(addr + offset) >> (8 * i);
 			}
-			if (i2c_write_data(bus, chip, data, alen, true)) {
+			if (i2c_write_data(i2c_bus, chip_addr, data, alen,
+					   true)) {
 				debug("i2c_read: error sending (0x%x)\n",
 					addr);
 				return 1;
 			}
 		}
-		if (i2c_read_data(bus, chip, buffer + offset, 1)) {
+		if (i2c_read_data(i2c_bus, chip_addr, buffer + offset, 1)) {
 			debug("i2c_read: error reading (0x%x)\n", addr);
 			return 1;
 		}
@@ -580,28 +480,22 @@ static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
 }
 
 /* Write bytes */
-static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
-			int alen, uchar *buffer, int len)
+static int tegra_i2c_write(struct udevice *dev, uint chip_addr, uint addr,
+			uint alen, const uchar *buffer, int len)
 {
-	struct i2c_bus *bus;
+	struct i2c_bus *i2c_bus = dev_get_priv(dev);
 	uint offset;
 	int i;
 
 	debug("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n",
-	      chip, addr, alen, len);
-	bus = tegra_i2c_get_bus(adap);
-	if (!bus)
-		return 1;
-	if (!i2c_addr_ok(addr, alen)) {
-		debug("i2c_write: Bad address %x.%d.\n", addr, alen);
-		return 1;
-	}
+	      chip_addr, addr, alen, len);
 	for (offset = 0; offset < len; offset++) {
 		uchar data[alen + 1];
 		for (i = 0; i < alen; i++)
 			data[alen - i - 1] = (addr + offset) >> (8 * i);
 		data[alen] = buffer[offset];
-		if (i2c_write_data(bus, chip, data, alen + 1, false)) {
+		if (i2c_write_data(i2c_bus, chip_addr, data, alen + 1,
+				   false)) {
 			debug("i2c_write: error sending (0x%x)\n", addr);
 			return 1;
 		}
@@ -610,37 +504,58 @@ static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
 	return 0;
 }
 
-int tegra_i2c_get_dvc_bus_num(void)
+int tegra_i2c_get_dvc_bus(struct udevice **busp)
 {
-	int i;
+	struct udevice *bus;
 
-	for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) {
-		struct i2c_bus *bus = &i2c_controllers[i];
-
-		if (bus->inited && bus->is_dvc)
-			return i;
+	for (uclass_first_device(UCLASS_I2C, &bus);
+	     bus;
+	     uclass_next_device(&bus)) {
+		if (dev_get_of_data(bus) == TYPE_DVC) {
+			*busp = bus;
+			return 0;
+		}
 	}
 
-	return -1;
+	return -ENODEV;
 }
 
-/*
- * Register soft i2c adapters
- */
-U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 0)
-U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 1)
-U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 2)
-U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 3)
-#if TEGRA_I2C_NUM_CONTROLLERS > 4
-U_BOOT_I2C_ADAP_COMPLETE(tegra4, tegra_i2c_init, tegra_i2c_probe,
-			 tegra_i2c_read, tegra_i2c_write,
-			 tegra_i2c_set_bus_speed, 100000, 0, 4)
-#endif
+static const struct dm_i2c_ops tegra_i2c_ops = {
+	.probe		= tegra_i2c_probe_chip,
+	.read		= tegra_i2c_read,
+	.write		= tegra_i2c_write,
+	.set_bus_speed	= tegra_i2c_set_bus_speed,
+	.set_addr_len	= tegra_i2c_set_addr_len,
+};
+
+static int tegra_i2c_child_pre_probe(struct udevice *dev)
+{
+	struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
+
+	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+					   i2c_chip);
+}
+
+static int tegra_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct udevice_id tegra_i2c_ids[] = {
+	{ .compatible = "tegra114-i2c", .data = TYPE_114 },
+	{ .compatible = "tegra,i2c", .data = TYPE_STD },
+	{ .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+	.name	= "i2c_tegra",
+	.id	= UCLASS_I2C,
+	.of_match = tegra_i2c_ids,
+	.ofdata_to_platdata = tegra_i2c_ofdata_to_platdata,
+	.probe	= tegra_i2c_probe,
+	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+	.child_pre_probe = tegra_i2c_child_pre_probe,
+	.priv_auto_alloc_size = sizeof(struct i2c_bus),
+	.ops	= &tegra_i2c_ops,
+};
diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c
index d29d969..29bab4c 100644
--- a/drivers/power/tps6586x.c
+++ b/drivers/power/tps6586x.c
@@ -10,9 +10,7 @@
 #include <asm/io.h>
 #include <i2c.h>
 
-static int bus_num;		/* I2C bus we are on */
-#define I2C_ADDRESS		0x34	/* chip requires this address */
-static char inited;		/* 1 if we have been inited */
+static struct udevice *tps6586x_dev;
 
 enum {
 	/* Registers that we access */
@@ -37,13 +35,9 @@ static int tps6586x_read(int reg)
 	int	i;
 	uchar	data;
 	int	retval = -1;
-	int	old_bus_num;
-
-	old_bus_num = i2c_get_bus_num();
-	i2c_set_bus_num(bus_num);
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) {
+		if (!i2c_read(tps6586x_dev, reg,  &data, 1)) {
 			retval = (int)data;
 			goto exit;
 		}
@@ -53,7 +47,6 @@ static int tps6586x_read(int reg)
 	}
 
 exit:
-	i2c_set_bus_num(old_bus_num);
 	debug("pmu_read %x=%x\n", reg, retval);
 	if (retval < 0)
 		debug("%s: failed to read register %#x: %d\n", __func__, reg,
@@ -65,13 +58,9 @@ static int tps6586x_write(int reg, uchar *data, uint len)
 {
 	int	i;
 	int	retval = -1;
-	int	old_bus_num;
-
-	old_bus_num = i2c_get_bus_num();
-	i2c_set_bus_num(bus_num);
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) {
+		if (!i2c_write(tps6586x_dev, reg, data, len)) {
 			retval = 0;
 			goto exit;
 		}
@@ -81,7 +70,6 @@ static int tps6586x_write(int reg, uchar *data, uint len)
 	}
 
 exit:
-	i2c_set_bus_num(old_bus_num);
 	debug("pmu_write %x=%x: ", reg, retval);
 	for (i = 0; i < len; i++)
 		debug("%x ", data[i]);
@@ -163,7 +151,7 @@ int tps6586x_set_pwm_mode(int mask)
 	uchar val;
 	int ret;
 
-	assert(inited);
+	assert(tps6586x_dev);
 	ret = tps6586x_read(PFM_MODE);
 	if (ret != -1) {
 		val = (uchar)ret;
@@ -184,7 +172,7 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,
 	int sm0, sm1;
 	int bad;
 
-	assert(inited);
+	assert(tps6586x_dev);
 
 	/* get current voltage settings */
 	if (read_voltages(&sm0, &sm1)) {
@@ -255,10 +243,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,
 	return bad ? -1 : 0;
 }
 
-int tps6586x_init(int bus)
+int tps6586x_init(struct udevice *dev)
 {
-	bus_num = bus;
-	inited = 1;
+	tps6586x_dev = dev;
 
 	return 0;
 }
diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h
index 09129c7..5be3752 100644
--- a/include/configs/cardhu.h
+++ b/include/configs/cardhu.h
@@ -45,8 +45,6 @@
 #define CONFIG_SYS_I2C_TEGRA
 #define CONFIG_SYS_I2C_INIT_BOARD
 #define CONFIG_I2C_MULTI_BUS
-#define CONFIG_SYS_MAX_I2C_BUS		TEGRA_I2C_NUM_CONTROLLERS
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
 #define CONFIG_SYS_I2C
 
diff --git a/include/configs/colibri_t30.h b/include/configs/colibri_t30.h
index 782b9d1..18ce2fa 100644
--- a/include/configs/colibri_t30.h
+++ b/include/configs/colibri_t30.h
@@ -27,9 +27,7 @@
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
 #define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index 04e4f82..5f77051 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -37,10 +37,7 @@
 
 /* I2C */
 #define CONFIG_SYS_I2C_TEGRA
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
 
 /* SD/MMC */
 #define CONFIG_MMC
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index 4719ee1..a68b474 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -26,6 +26,7 @@
 #endif
 #define CONFIG_DM_SPI
 #define CONFIG_DM_SPI_FLASH
+#define CONFIG_DM_I2C
 
 #define CONFIG_SYS_TIMER_RATE		1000000
 #define CONFIG_SYS_TIMER_COUNTER	NV_PA_TMRUS_BASE
diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h
index 21bf977..6330281 100644
--- a/include/configs/tegra20-common.h
+++ b/include/configs/tegra20-common.h
@@ -97,9 +97,6 @@
 #define CONFIG_EHCI_IS_TDI
 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
 
-/* Total I2C ports on Tegra20 */
-#define TEGRA_I2C_NUM_CONTROLLERS	4
-
 #define CONFIG_SYS_NAND_SELF_INIT
 #define CONFIG_SYS_NAND_ONFI_DETECTION
 
diff --git a/include/tps6586x.h b/include/tps6586x.h
index 78ce428..9ea0c89 100644
--- a/include/tps6586x.h
+++ b/include/tps6586x.h
@@ -47,6 +47,6 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,
  * @param bus	I2C bus number containing the TPS6586X chip
  * @return 0 (always succeeds)
  */
-int tps6586x_init(int bus);
+int tps6586x_init(struct udevice *bus);
 
 #endif	/* _TPS6586X_H_ */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (11 preceding siblings ...)
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 12/12] dm: i2c: tegra: Convert to driver model for I2C for seaboard Simon Glass
@ 2014-10-24 15:03 ` Tom Rini
  2014-10-29  7:31   ` Heiko Schocher
  2014-11-10  7:16 ` Heiko Schocher
  13 siblings, 1 reply; 19+ messages in thread
From: Tom Rini @ 2014-10-24 15:03 UTC (permalink / raw)
  To: u-boot

On Sun, Oct 12, 2014 at 11:39:26PM -0600, Simon Glass wrote:

> (Note this is RFC since the uclass interface needs discussion and also
> because only sandbox is implemented so far. But I thought it best to get
> this out there as soon as I wrote it as it may influence the PMIC library,
> etc.)
> 
> This series is an initial attempt to add I2C support to driver model. It
> has become apparent that this is a high priority as it is widely used. It
> follows along to some extent from the SPI conversion.
> 
> Several changes are made from the original I2C implementations.
> 
> Firstly It is not necessary to specify the chip address with every call,
> since each chip knows its own address - it is stored in struct dm_i2c_chip
> which is attached to each chip on the I2C bus. However, this information
> *is* passed to the driver since I presume most drivers need it and it would
> be cumbersome to look up in every call.
> 
> Secondly there is no concept of a 'current' I2C bus so all associated logic
> is removed. With driver model i2c_set_bus_num() and i2c_get_bus_num() are
> not available. Since the chip device specifies both the bus and the chip
> address, there is no need for this concept. It also causes problems when
> one driver changes the current bus and forgets to change it back.
> 
> Thirdly initialisation is handled by driver model's normal probe() method
> on each device so there should be no need for i2c_init_all(), i2c_init(),
> i2c_init_board(), i2c_board_late_init() and board_i2c_init().
> 
> I2C muxes are not yet supported. To support these we will need to maintain
> state of the current mux settings to avoid resetting every mux every time.
> Probably we need to add a sandbox I2C mux driver to permit testing of this.
> This can probably be done later.
> 
> Platform data is not yet supported either, only device tree. The
> U_BOOT_I2C_MKENT_COMPLETE() and U_BOOT_I2C_ADAP_COMPLETE() macros are not
> used. Also struct i2c_adapter is not defined anymore. This will need to be
> addressed, perhaps as part of converting over a board that does not use
> device tree.
> 
> This series is available at u-boot-dm/i2c-working.

Nothing jumped out at me.  Heiko?

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141024/ede72dd0/attachment-0001.pgp>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support
  2014-10-24 15:03 ` [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Tom Rini
@ 2014-10-29  7:31   ` Heiko Schocher
  0 siblings, 0 replies; 19+ messages in thread
From: Heiko Schocher @ 2014-10-29  7:31 UTC (permalink / raw)
  To: u-boot

Hello Tom,

Am 24.10.2014 17:03, schrieb Tom Rini:
> On Sun, Oct 12, 2014 at 11:39:26PM -0600, Simon Glass wrote:
>
>> (Note this is RFC since the uclass interface needs discussion and also
>> because only sandbox is implemented so far. But I thought it best to get
>> this out there as soon as I wrote it as it may influence the PMIC library,
>> etc.)
>>
>> This series is an initial attempt to add I2C support to driver model. It
>> has become apparent that this is a high priority as it is widely used. It
>> follows along to some extent from the SPI conversion.
>>
>> Several changes are made from the original I2C implementations.
>>
>> Firstly It is not necessary to specify the chip address with every call,
>> since each chip knows its own address - it is stored in struct dm_i2c_chip
>> which is attached to each chip on the I2C bus. However, this information
>> *is* passed to the driver since I presume most drivers need it and it would
>> be cumbersome to look up in every call.
>>
>> Secondly there is no concept of a 'current' I2C bus so all associated logic
>> is removed. With driver model i2c_set_bus_num() and i2c_get_bus_num() are
>> not available. Since the chip device specifies both the bus and the chip
>> address, there is no need for this concept. It also causes problems when
>> one driver changes the current bus and forgets to change it back.
>>
>> Thirdly initialisation is handled by driver model's normal probe() method
>> on each device so there should be no need for i2c_init_all(), i2c_init(),
>> i2c_init_board(), i2c_board_late_init() and board_i2c_init().
>>
>> I2C muxes are not yet supported. To support these we will need to maintain
>> state of the current mux settings to avoid resetting every mux every time.
>> Probably we need to add a sandbox I2C mux driver to permit testing of this.
>> This can probably be done later.
>>
>> Platform data is not yet supported either, only device tree. The
>> U_BOOT_I2C_MKENT_COMPLETE() and U_BOOT_I2C_ADAP_COMPLETE() macros are not
>> used. Also struct i2c_adapter is not defined anymore. This will need to be
>> addressed, perhaps as part of converting over a board that does not use
>> device tree.
>>
>> This series is available at u-boot-dm/i2c-working.
>
> Nothing jumped out at me.  Heiko?

Looking in this patches soon... sorry for the delay.

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 03/12] dm: i2c: Add a uclass for I2C
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 03/12] dm: i2c: Add a uclass for I2C Simon Glass
@ 2014-11-10  6:33   ` Heiko Schocher
  0 siblings, 0 replies; 19+ messages in thread
From: Heiko Schocher @ 2014-11-10  6:33 UTC (permalink / raw)
  To: u-boot

Hello Simon,

Am 13.10.2014 07:39, schrieb Simon Glass:
> 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 <sjg@chromium.org>
> ---
>
>   drivers/i2c/Makefile       |   1 +
>   drivers/i2c/i2c-uclass.c   | 177 +++++++++++++++++++++++++++++++
>   include/config_fallbacks.h |   6 ++
>   include/dm/uclass-id.h     |   1 +
>   include/i2c.h              | 252 +++++++++++++++++++++++++++++++++++++++++++++
>   5 files changed, 437 insertions(+)
>   create mode 100644 drivers/i2c/i2c-uclass.c

only nitpick ...

[...]
> diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
> new file mode 100644
> index 0000000..6bdce8c
> --- /dev/null
> +++ b/drivers/i2c/i2c-uclass.c
> @@ -0,0 +1,177 @@
> +/*
> + * Copyright (c) 2014 Google, Inc
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <fdtdec.h>
> +#include <i2c.h>
> +#include <dm/device-internal.h>
> +#include <dm/root.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +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);
> +}
> +
> +int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
> +{
> +	struct udevice *dev;
> +
> +	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);
> +			if (ret)
> +				return ret;
> +			*devp = dev;
> +			return 0;
> +		}
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +int i2c_probe(struct udevice *bus, uint chip)
> +{
> +	struct dm_i2c_ops *ops = i2c_get_ops(bus);
> +	struct udevice *dev;
> +	int ret;
> +
> +	if (!ops->probe)
> +		return -ENODEV;
> +
> +	/* First probe that chip */
> +	ret = ops->probe(bus, chip);
> +	if (ret)
> +		return ret;
> +
> +	/* The cihp was found, see if we have a driver, and probe it */

s/cihp/chip

[...]

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 04/12] dm: i2c: Implement driver model support in the i2c command
  2014-10-13  5:39 ` [U-Boot] [RFC PATCH 04/12] dm: i2c: Implement driver model support in the i2c command Simon Glass
@ 2014-11-10  7:01   ` Heiko Schocher
  0 siblings, 0 replies; 19+ messages in thread
From: Heiko Schocher @ 2014-11-10  7:01 UTC (permalink / raw)
  To: u-boot

Hello Simon,

Am 13.10.2014 07:39, schrieb Simon Glass:
> The concept of a 'current bus' is now implemented in the command line
> rather than in the uclass. Also the address length does not need to
> be specified with each command - really we should consider dropping
> this from most commands but it works OK for now.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>   common/cmd_i2c.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++--------
>   1 file changed, 267 insertions(+), 45 deletions(-)
>
> diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
> index c266b88..6766856 100644
> --- a/common/cmd_i2c.c
> +++ b/common/cmd_i2c.c
> @@ -69,8 +69,10 @@
>   #include <bootretry.h>
>   #include <cli.h>
>   #include <command.h>
> +#include <dm.h>
>   #include <edid.h>
>   #include <environment.h>
> +#include <errno.h>
>   #include <i2c.h>
>   #include <malloc.h>
>   #include <asm/byteorder.h>
> @@ -117,6 +119,60 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES;
>
>   #define DISP_LINE_LEN	16
>
> +/*
> + * Default for driver model is to use the chip's existing address length.
> + * For legacy code, this is not stored, so we need to use a suitable
> + * default.
> + */
> +#ifdef CONFIG_DM_I2C
> +#define DEFAULT_ADDR_LEN	(-1)
> +#else
> +#define DEFAULT_ADDR_LEN	1
> +#endif
> +
> +#ifdef CONFIG_DM_I2C
> +static struct udevice *i2c_cur_bus;
> +
> +static int i2c_set_bus_num(unsigned int busnum)
> +{
> +	struct udevice *bus;
> +	int ret;
> +
> +	ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
> +	if (ret) {
> +		debug("%s: No bus %d\n", __func__, busnum);
> +		return ret;
> +	}
> +	i2c_cur_bus = bus;
> +
> +	return 0;
> +}
> +
> +static int i2c_get_cur_bus(struct udevice **busp)
> +{
> +	if (!i2c_cur_bus) {
> +		puts("No I2C bus selected\n");
> +		return -ENODEV;
> +	}
> +	*busp = i2c_cur_bus;
> +
> +	return 0;
> +}
> +
> +static int i2c_get_cur_bus_chip(uint chip_addr, struct udevice **devp)
> +{
> +	struct udevice *bus;
> +	int ret;
> +
> +	ret = i2c_get_cur_bus(&bus);
> +	if (ret)
> +		return ret;
> +
> +	return i2c_get_chip(bus, chip_addr, devp);
> +}
> +
> +#endif
> +
>   /**
>    * i2c_init_board() - Board-specific I2C bus init
>    *
> @@ -143,7 +199,7 @@ void i2c_init_board(void)
>    *
>    * Returns I2C bus speed in Hz.
>    */
> -#if !defined(CONFIG_SYS_I2C)
> +#if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_DM_I2C)
>   /*
>    * TODO: Implement architecture-specific get/set functions
>    * Should go away, if we switched completely to new multibus support
> @@ -182,12 +238,12 @@ int i2c_set_bus_speed(unsigned int speed)
>    *
>    * Returns the address length.
>    */
> -static uint get_alen(char *arg)
> +static uint get_alen(char *arg, int default_len)
>   {
>   	int	j;
>   	int	alen;
>
> -	alen = 1;
> +	alen = default_len;
>   	for (j = 0; j < 8; j++) {
>   		if (arg[j] == '.') {
>   			alen = arg[j+1] - '0';
> @@ -229,6 +285,10 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
>   	u_char	chip;
>   	uint	devaddr, alen, length;
>   	u_char  *memaddr;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if (argc != 5)
>   		return CMD_RET_USAGE;
> @@ -243,7 +303,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
>   	 * 2 bytes long.  Some day it might be 3 bytes long :-).
>   	 */
>   	devaddr = simple_strtoul(argv[2], NULL, 16);
> -	alen = get_alen(argv[2]);
> +	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
>   	if (alen > 3)
>   		return CMD_RET_USAGE;
>
> @@ -257,10 +317,18 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
>   	 */
>   	memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16);
>
> -	if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) {
> -		i2c_report_err(-1, I2C_ERR_READ);
> -		return 1;
> -	}
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (!ret)
> +		ret = i2c_read(dev, devaddr, memaddr, length);
> +#else
> +	ret = i2c_read(chip, devaddr, alen, memaddr, length);
> +#endif
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_READ);
> +
>   	return 0;
>   }
>
> @@ -269,6 +337,10 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
>   	u_char	chip;
>   	uint	devaddr, alen, length;
>   	u_char  *memaddr;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if (argc != 5)
>   		return cmd_usage(cmdtp);
> @@ -288,7 +360,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
>   	 * 2 bytes long.  Some day it might be 3 bytes long :-).
>   	 */
>   	devaddr = simple_strtoul(argv[3], NULL, 16);
> -	alen = get_alen(argv[3]);
> +	alen = get_alen(argv[3], DEFAULT_ADDR_LEN);
>   	if (alen > 3)
>   		return cmd_usage(cmdtp);
>
> @@ -297,10 +369,22 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
>   	 */
>   	length = simple_strtoul(argv[4], NULL, 16);
>
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_WRITE);
> +#endif
> +
>   	while (length-- > 0) {
> -		if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) {
> -			return i2c_report_err(-1, I2C_ERR_WRITE);
> -		}
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_write(dev, devaddr++, memaddr++, 1);
> +#else
> +		ret = i2c_write(chip, devaddr++, alen, memaddr++, 1);
> +#endif
> +		if (ret)
> +			return i2c_report_err(ret, I2C_ERR_WRITE);
>   /*
>    * No write delay with FRAM devices.
>    */
> @@ -329,6 +413,10 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	u_char	chip;
>   	uint	addr, alen, length;
>   	int	j, nbytes, linebytes;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	/* We use the last specified parameters, unless new ones are
>   	 * entered.
> @@ -356,7 +444,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   		 * 2 bytes long.  Some day it might be 3 bytes long :-).
>   		 */
>   		addr = simple_strtoul(argv[2], NULL, 16);
> -		alen = get_alen(argv[2]);
> +		alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
>   		if (alen > 3)
>   			return CMD_RET_USAGE;
>
> @@ -368,6 +456,14 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   			length = simple_strtoul(argv[3], NULL, 16);
>   	}
>
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_READ);
> +#endif
> +
>   	/*
>   	 * Print the lines.
>   	 *
> @@ -381,8 +477,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>
>   		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
>
> -		if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0)
> -			i2c_report_err(-1, I2C_ERR_READ);
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_read(dev, addr, linebuf, linebytes);
> +#else
> +		ret = i2c_read(chip, addr, alen, linebuf, linebytes);
> +#endif
> +		if (ret)
> +			i2c_report_err(ret, I2C_ERR_READ);
>   		else {
>   			printf("%04x:", addr);
>   			cp = linebuf;
> @@ -432,6 +533,10 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	uint	alen;
>   	uchar	byte;
>   	int	count;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if ((argc < 4) || (argc > 5))
>   		return CMD_RET_USAGE;
> @@ -445,10 +550,17 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	 * Address is always specified.
>   	 */
>   	addr = simple_strtoul(argv[2], NULL, 16);
> -	alen = get_alen(argv[2]);
> +	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
>   	if (alen > 3)
>   		return CMD_RET_USAGE;
>
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_WRITE);
> +#endif
>   	/*
>   	 * Value to write is always specified.
>   	 */
> @@ -463,8 +575,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   		count = 1;
>
>   	while (count-- > 0) {
> -		if (i2c_write(chip, addr++, alen, &byte, 1) != 0)
> -			i2c_report_err(-1, I2C_ERR_WRITE);
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_write(dev, addr++, &byte, 1);
> +#else
> +		ret = i2c_write(chip, addr++, alen, &byte, 1);
> +#endif
> +		if (ret)
> +			i2c_report_err(ret, I2C_ERR_WRITE);
>   		/*
>   		 * Wait for the write to complete.  The write can take
>   		 * up to 10mSec (we allow a little more time).
> @@ -504,6 +621,10 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	uchar	byte;
>   	ulong	crc;
>   	ulong	err;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if (argc < 4)
>   		return CMD_RET_USAGE;
> @@ -517,10 +638,17 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	 * Address is always specified.
>   	 */
>   	addr = simple_strtoul(argv[2], NULL, 16);
> -	alen = get_alen(argv[2]);
> +	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
>   	if (alen > 3)
>   		return CMD_RET_USAGE;
>
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_READ);
> +#endif
>   	/*
>   	 * Count is always specified
>   	 */
> @@ -534,13 +662,18 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	crc = 0;
>   	err = 0;
>   	while (count-- > 0) {
> -		if (i2c_read(chip, addr, alen, &byte, 1) != 0)
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_read(dev, addr, &byte, 1);
> +#else
> +		ret = i2c_read(chip, addr, alen, &byte, 1);
> +#endif
> +		if (ret)
>   			err++;
>   		crc = crc32 (crc, &byte, 1);
>   		addr++;
>   	}
>   	if (err > 0)
> -		i2c_report_err(-1, I2C_ERR_READ);
> +		i2c_report_err(ret, I2C_ERR_READ);
>   	else
>   		printf ("%08lx\n", crc);
>
> @@ -572,6 +705,10 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
>   	ulong	data;
>   	int	size = 1;
>   	int	nbytes;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if (argc != 3)
>   		return CMD_RET_USAGE;
> @@ -601,19 +738,32 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
>   		 * Address is always specified.
>   		 */
>   		addr = simple_strtoul(argv[2], NULL, 16);
> -		alen = get_alen(argv[2]);
> +		alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
>   		if (alen > 3)
>   			return CMD_RET_USAGE;
>   	}
>
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_WRITE);
> +#endif
> +
>   	/*
>   	 * Print the address, followed by value.  Then accept input for
>   	 * the next value.  A non-converted value exits.
>   	 */
>   	do {
>   		printf("%08lx:", addr);
> -		if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0)
> -			i2c_report_err(-1, I2C_ERR_READ);
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_read(dev, addr, (uchar *)&data, size);
> +#else
> +		ret = i2c_read(chip, addr, alen, (uchar *)&data, size);
> +#endif
> +		if (ret)
> +			i2c_report_err(ret, I2C_ERR_READ);
>   		else {
>   			data = cpu_to_be32(data);
>   			if (size == 1)
> @@ -655,8 +805,15 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg
>   				 * good enough to not time out
>   				 */
>   				bootretry_reset_cmd_timeout();
> -				if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0)
> -					i2c_report_err(-1, I2C_ERR_WRITE);
> +#ifdef CONFIG_DM_I2C
> +				ret = i2c_write(dev, addr, (uchar *)&data,
> +						size);
> +#else
> +				ret = i2c_write(chip, addr, alen,
> +						(uchar *)&data, size);
> +#endif
> +				if (ret)
> +					i2c_report_err(ret, I2C_ERR_WRITE);
>   #ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
>   				udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
>   #endif
> @@ -697,6 +854,13 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
>   	int k, skip;
>   	unsigned int bus = GET_BUS_NUM;
>   #endif	/* NOPROBES */
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *bus;
> +
> +	if (i2c_get_cur_bus(&bus))
> +		return CMD_RET_FAILURE;
> +#endif
>
>   	if (argc == 2)
>   		addr = simple_strtol(argv[1], 0, 16);
> @@ -717,7 +881,12 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
>   		if (skip)
>   			continue;
>   #endif
> -		if (i2c_probe(j) == 0) {
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_probe(bus, j);
> +#else
> +		ret = i2c_probe(j);
> +#endif
> +		if (ret == 0) {
>   			printf(" %02X", j);
>   			found++;
>   		}
> @@ -759,6 +928,10 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	uint	length;
>   	u_char	bytes[16];
>   	int	delay;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if (argc < 3)
>   		return CMD_RET_USAGE;
> @@ -772,9 +945,16 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	 * Address is always specified.
>   	 */
>   	addr = simple_strtoul(argv[2], NULL, 16);
> -	alen = get_alen(argv[2]);
> +	alen = get_alen(argv[2], DEFAULT_ADDR_LEN);
>   	if (alen > 3)
>   		return CMD_RET_USAGE;
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret && alen != -1)
> +		ret = i2c_set_addr_len(dev, alen);
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_WRITE);
> +#endif
>
>   	/*
>   	 * Length is the number of objects, not number of bytes.
> @@ -794,8 +974,13 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]
>   	 * Run the loop...
>   	 */
>   	while (1) {
> -		if (i2c_read(chip, addr, alen, bytes, length) != 0)
> -			i2c_report_err(-1, I2C_ERR_READ);
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_read(dev, addr, bytes, length);
> +#else
> +		ret = i2c_read(chip, addr, alen, bytes, length);
> +#endif
> +		if (ret)
> +			i2c_report_err(ret, I2C_ERR_READ);
>   		udelay(delay);
>   	}
>
> @@ -1345,6 +1530,10 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
>   {
>   	u_char chip;
>   	struct edid1_info edid;
> +	int ret;
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *dev;
> +#endif
>
>   	if (argc < 2) {
>   		cmd_usage(cmdtp);
> @@ -1352,10 +1541,15 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
>   	}
>
>   	chip = simple_strtoul(argv[1], NULL, 16);
> -	if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) {
> -		i2c_report_err(-1, I2C_ERR_READ);
> -		return 1;
> -	}
> +#ifdef CONFIG_DM_I2C
> +	ret = i2c_get_cur_bus_chip(chip, &dev);
> +	if (!ret)
> +		ret = i2c_read(dev, 0, (uchar *)&edid, sizeof(edid));
> +#else
> +	ret = i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid));
> +#endif
> +	if (ret)
> +		return i2c_report_err(ret, I2C_ERR_READ);
>
>   	if (edid_check_info(&edid)) {
>   		puts("Content isn't valid EDID.\n");
> @@ -1437,17 +1631,28 @@ static int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,
>    * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
>    * on error.
>    */
> -#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS)
> +#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) || \
> +		defined(CONFIG_DM_I2C)
>   static int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc,
>   				char * const argv[])
>   {
>   	int		ret = 0;
> -	unsigned int	bus_no;
> +	int	bus_no;
>
> -	if (argc == 1)
> +	if (argc == 1) {
>   		/* querying current setting */
> -		printf("Current bus is %d\n", i2c_get_bus_num());
> -	else {
> +#ifdef CONFIG_DM_I2C
> +		struct udevice *bus;
> +
> +		if (!i2c_get_cur_bus(&bus))
> +			bus_no = bus->seq;
> +		else
> +			bus_no = -1;
> +#else
> +		bus_no = i2c_get_bus_num();
> +#endif
> +		printf("Current bus is %d\n", bus_no);
> +	} else {
>   		bus_no = simple_strtoul(argv[1], NULL, 10);
>   #if defined(CONFIG_SYS_I2C)
>   		if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) {
> @@ -1478,13 +1683,28 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const
>   {
>   	int speed, ret=0;
>
> -	if (argc == 1)
> +#ifdef CONFIG_DM_I2C
> +	struct udevice *bus;
> +
> +	if (i2c_get_cur_bus(&bus))
> +		return 1;
> +#endif
> +	if (argc == 1) {
> +#ifdef CONFIG_DM_I2C
> +		speed = i2c_get_bus_speed(bus);
> +#else
> +		speed = i2c_get_bus_speed();
> +#endif
>   		/* querying current speed */
> -		printf("Current bus speed=%d\n", i2c_get_bus_speed());
> -	else {
> +		printf("Current bus speed=%d\n", speed);
> +	} else {
>   		speed = simple_strtoul(argv[1], NULL, 10);
>   		printf("Setting bus speed to %d Hz\n", speed);
> +#ifdef CONFIG_DM_I2C
> +		ret = i2c_set_bus_speed(bus, speed);
> +#else
>   		ret = i2c_set_bus_speed(speed);
> +#endif
>   		if (ret)
>   			printf("Failure changing bus speed (%d)\n", ret);
>   	}
> @@ -1532,7 +1752,9 @@ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
>    */
>   static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
>   {
> -#if defined(CONFIG_SYS_I2C)
> +#if defined(CONFIG_DM_I2C)
> +	/* TODO(sjg at chromium.org): What should we do here? */

This is a good question. I wanted to add in the CONFIG_SYS_I2C case,
a possibility to add a i2c deblock function for drivers and call them
from here ... Currently the i2c_init_board() is abused (see
u-boot:doc/I2C_Edge_Conditions) for this ...

This gets interesting as a lot of SoCs can switch the i2c pins
into gpio mode and do then a bitbang deblock of the bus, and
if this is finished switch back the pins to i2c mode ...

So maybe we add the following in include/i2c.h for the DM case:

+struct dm_i2c_ops {
+       /**
+        * deblock() - deblock an i2c bus
+        *
+        * @bus:        Bus to deblock
+        */
+       int (*deblock)(struct udevice *bus);

and this deblock() gets called here (if defined for an driver).

So we can provide a default soft bitbang deblock function (a good one is in
./board/keymile/common/common.c i2c_make_abort())
which should call a board specific i2c_switch_pin(struct udevice *bus, int mode)
with mode = PIN_TO_GPIO_MODE or PIN_TO_I2C_MODE

rough fast proposal:

int i2c_soft_deblock(struct udevice *bus)
{
	int ret;

	ret = i2c_switch_pin(bus, PIN_TO_GPIO_MODE);
         /* boards which could not do softbitbang return here -EPERM */
         if (ret)
		return ret;

	/* call soft bitbang ...  */
	ret = i2c_soft_deblock()
         if (ret)
		return ret;

	ret = i2c_switch_pin(bus, PIN_TO_GPIO_MODE);
	return ret;
}

bye,
Heiko

> +#elif defined(CONFIG_SYS_I2C)
>   	i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr);
>   #else
>   	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
> @@ -1546,7 +1768,7 @@ static cmd_tbl_t cmd_i2c_sub[] = {
>   #endif
>   	U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""),
>   #if defined(CONFIG_SYS_I2C) || \
> -	defined(CONFIG_I2C_MULTI_BUS)
> +	defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C)
>   	U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),
>   #endif  /* CONFIG_I2C_MULTI_BUS */
>   #if defined(CONFIG_I2C_EDID)
> @@ -1610,7 +1832,7 @@ static char i2c_help_text[] =
>   #endif
>   	"crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n"
>   #if defined(CONFIG_SYS_I2C) || \
> -	defined(CONFIG_I2C_MULTI_BUS)
> +	defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C)
>   	"i2c dev [dev] - show or set current I2C bus\n"
>   #endif  /* CONFIG_I2C_MULTI_BUS */
>   #if defined(CONFIG_I2C_EDID)
>

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support
  2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
                   ` (12 preceding siblings ...)
  2014-10-24 15:03 ` [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Tom Rini
@ 2014-11-10  7:16 ` Heiko Schocher
  2014-11-11 15:44   ` Simon Glass
  13 siblings, 1 reply; 19+ messages in thread
From: Heiko Schocher @ 2014-11-10  7:16 UTC (permalink / raw)
  To: u-boot

Hello Simon,

sorry for the long delay...

Am 13.10.2014 07:39, schrieb Simon Glass:
> (Note this is RFC since the uclass interface needs discussion and also
> because only sandbox is implemented so far. But I thought it best to get
> this out there as soon as I wrote it as it may influence the PMIC library,
> etc.)
>
> This series is an initial attempt to add I2C support to driver model. It
> has become apparent that this is a high priority as it is widely used. It
> follows along to some extent from the SPI conversion.
>
> Several changes are made from the original I2C implementations.
>
> Firstly It is not necessary to specify the chip address with every call,
> since each chip knows its own address - it is stored in struct dm_i2c_chip
> which is attached to each chip on the I2C bus. However, this information
> *is* passed to the driver since I presume most drivers need it and it would
> be cumbersome to look up in every call.
>
> Secondly there is no concept of a 'current' I2C bus so all associated logic
> is removed. With driver model i2c_set_bus_num() and i2c_get_bus_num() are
> not available. Since the chip device specifies both the bus and the chip
> address, there is no need for this concept. It also causes problems when
> one driver changes the current bus and forgets to change it back.
>
> Thirdly initialisation is handled by driver model's normal probe() method
> on each device so there should be no need for i2c_init_all(), i2c_init(),
> i2c_init_board(), i2c_board_late_init() and board_i2c_init().

Great!

> I2C muxes are not yet supported. To support these we will need to maintain
> state of the current mux settings to avoid resetting every mux every time.
> Probably we need to add a sandbox I2C mux driver to permit testing of this.
> This can probably be done later.

Currently only the keymile boards really use i2c muxes, so I am fine
with doing this in a second step.

> Platform data is not yet supported either, only device tree. The
> U_BOOT_I2C_MKENT_COMPLETE() and U_BOOT_I2C_ADAP_COMPLETE() macros are not
> used. Also struct i2c_adapter is not defined anymore. This will need to be
> addressed, perhaps as part of converting over a board that does not use
> device tree.

Ok for this in the first step... The question raised if we only would
support Device tree with DM ... so maybe we do not need to do this step.

I am not really sure, if we should really support Device Tree only with
DM, because:

- do all archs switch to Device Tree in the near future?

- in SPL we have really on some SoCs small memory (like I just work
   on some AT91 boards which have 4k only!) To get DM with Device
   Tree into 4k is a big challenge ... so in my opinion, it would be
   good to have the possibility of Platform data ... so we prevent
   to make dirty hacks for the  SPL case (I hope) ...

> This series is available at u-boot-dm/i2c-working.

Thanks for your great work.

I looked through your patchset and have no real objection against it ...
To the "i2c deblocking" subject ... we should add at least the
"deblock()" in "struct dm_i2c_ops" and call it "do_i2c_reset"
if defined ... beside of this, you can add my

Acked-by: Heiko Schocher <hs@denx.de>

to the hole series.

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support
  2014-11-10  7:16 ` Heiko Schocher
@ 2014-11-11 15:44   ` Simon Glass
  0 siblings, 0 replies; 19+ messages in thread
From: Simon Glass @ 2014-11-11 15:44 UTC (permalink / raw)
  To: u-boot

Hi Heiko,

On 10 November 2014 00:16, Heiko Schocher <hs@denx.de> wrote:
> Hello Simon,
>
> sorry for the long delay...
>
> Am 13.10.2014 07:39, schrieb Simon Glass:
>>
>> (Note this is RFC since the uclass interface needs discussion and also
>> because only sandbox is implemented so far. But I thought it best to get
>> this out there as soon as I wrote it as it may influence the PMIC library,
>> etc.)
>>
>> This series is an initial attempt to add I2C support to driver model. It
>> has become apparent that this is a high priority as it is widely used. It
>> follows along to some extent from the SPI conversion.
>>
>> Several changes are made from the original I2C implementations.
>>
>> Firstly It is not necessary to specify the chip address with every call,
>> since each chip knows its own address - it is stored in struct dm_i2c_chip
>> which is attached to each chip on the I2C bus. However, this information
>> *is* passed to the driver since I presume most drivers need it and it
>> would
>> be cumbersome to look up in every call.
>>
>> Secondly there is no concept of a 'current' I2C bus so all associated
>> logic
>> is removed. With driver model i2c_set_bus_num() and i2c_get_bus_num() are
>> not available. Since the chip device specifies both the bus and the chip
>> address, there is no need for this concept. It also causes problems when
>> one driver changes the current bus and forgets to change it back.
>>
>> Thirdly initialisation is handled by driver model's normal probe() method
>> on each device so there should be no need for i2c_init_all(), i2c_init(),
>> i2c_init_board(), i2c_board_late_init() and board_i2c_init().
>
>
> Great!
>
>> I2C muxes are not yet supported. To support these we will need to maintain
>> state of the current mux settings to avoid resetting every mux every time.
>> Probably we need to add a sandbox I2C mux driver to permit testing of
>> this.
>> This can probably be done later.
>
>
> Currently only the keymile boards really use i2c muxes, so I am fine
> with doing this in a second step.
>
>> Platform data is not yet supported either, only device tree. The
>> U_BOOT_I2C_MKENT_COMPLETE() and U_BOOT_I2C_ADAP_COMPLETE() macros are not
>> used. Also struct i2c_adapter is not defined anymore. This will need to be
>> addressed, perhaps as part of converting over a board that does not use
>> device tree.
>
>
> Ok for this in the first step... The question raised if we only would
> support Device tree with DM ... so maybe we do not need to do this step.
>
> I am not really sure, if we should really support Device Tree only with
> DM, because:
>
> - do all archs switch to Device Tree in the near future?
>
> - in SPL we have really on some SoCs small memory (like I just work
>   on some AT91 boards which have 4k only!) To get DM with Device
>   Tree into 4k is a big challenge ... so in my opinion, it would be
>   good to have the possibility of Platform data ... so we prevent
>   to make dirty hacks for the  SPL case (I hope) ...
>
>> This series is available at u-boot-dm/i2c-working.
>
>
> Thanks for your great work.
>
> I looked through your patchset and have no real objection against it ...
> To the "i2c deblocking" subject ... we should add at least the
> "deblock()" in "struct dm_i2c_ops" and call it "do_i2c_reset"
> if defined ... beside of this, you can add my
>
> Acked-by: Heiko Schocher <hs@denx.de>
>
> to the hole series.

Thanks for reviewing this. I have added the deblock() method and also
the generic I2C support (allows you to use a device on the command
line without it having a proper driver). There are a few changes so if
you have time to take another look I will definitely add your
Acked-by.

Regards,
Simon

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2014-11-11 15:44 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-13  5:39 [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 01/12] dm: core: Allow access to the device's driver_id data Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 02/12] dm: core: Add functions to find parent and OF data Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 03/12] dm: i2c: Add a uclass for I2C Simon Glass
2014-11-10  6:33   ` Heiko Schocher
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 04/12] dm: i2c: Implement driver model support in the i2c command Simon Glass
2014-11-10  7:01   ` Heiko Schocher
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 05/12] dm: i2c: Add I2C emulation driver for sandbox Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 06/12] dm: i2c: Add a sandbox I2C driver Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 07/12] dm: i2c: Add an I2C EEPROM simulator Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 08/12] dm: i2c: config: Enable I2C for sandbox using driver model Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 09/12] dm: i2c: dts: Add an I2C bus for sandbox Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 10/12] dm: WIP: EEPROM driver Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 11/12] dm: i2c: Add tests for I2C Simon Glass
2014-10-13  5:39 ` [U-Boot] [RFC PATCH 12/12] dm: i2c: tegra: Convert to driver model for I2C for seaboard Simon Glass
2014-10-24 15:03 ` [U-Boot] [RFC PATCH 0/12] RFC: dm: Add I2C support Tom Rini
2014-10-29  7:31   ` Heiko Schocher
2014-11-10  7:16 ` Heiko Schocher
2014-11-11 15:44   ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.