Skip to contentSkip to conversation

RFC: dm: Add I2C support

RFC PATCH New Simon Glass 3 participants 19 messages Oct 13, 2014 – Nov 11, 2014

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover RFC: dm: Add I2C support

(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
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#1 lore raw

RFC PATCH 1/12 dm: core: Allow access to the device's driver_id data

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

---

 drivers/core/device.c |  5 +++++
 drivers/core/lists.c  | 17 ++++++++++++-----
 include/dm/device.h   | 11 +++++++++++
 3 files changed, 28 insertions(+), 5 deletions(-)
drivers/core/device.c +5 -0
index 49faa29..0d84776 100644
@@ -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;
+}
drivers/core/lists.c +12 -5
index 699f94b..f170ae7 100644
@@ -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;
include/dm/device.h +11 -0
index b8d4e7a..a712156 100644
@@ -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
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#2 lore raw

RFC PATCH 2/12 dm: core: Add functions to find parent and OF data

In reply to Simon Glass

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

---

 drivers/core/device.c | 5 +++++
 include/dm/device.h   | 8 ++++++++
 2 files changed, 13 insertions(+)
drivers/core/device.c +5 -0
index 0d84776..76b29fd 100644
@@ -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;
include/dm/device.h +8 -0
index a712156..e8b7fcf 100644
@@ -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
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#3 lore raw

RFC PATCH 3/12 dm: i2c: Add a uclass for I2C

In reply to 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

---

 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
drivers/i2c/Makefile +1 -0
index 416ea4f..2ee468d 100644
@@ -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
drivers/i2c/i2c-uclass.c new file +177 -0

177 lines not on this page · raw message

include/config_fallbacks.h +6 -0
index 76818f6..c75f42d 100644
@@ -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 */
include/dm/uclass-id.h +1 -0
index e3e9296..9611a13 100644
@@ -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,
include/i2c.h +252 -0

262 lines not on this page · raw message

Signature · 1 line
2.1.0.rc2.206.gedb03e5
#4 lore raw

RFC PATCH 3/12 dm: i2c: Add a uclass for I2C

Hello Simon,

Am 13.10.2014 07:39, schrieb Simon Glass:

Quoted 11 lines

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

---

Quoted 7 lines
  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 ...

[...]

Quoted 80 lines
drivers/i2c/i2c-uclass.c new file +74 -0
new file mode 100644
index 0000000..6bdce8c
@@ -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;

drivers/i2c/i2c-uclass.c line 84

Quoted 10 lines
drivers/i2c/i2c-uclass.c new file +10 -0
+
+	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

Signature · 2 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
#5 lore raw

RFC PATCH 4/12 dm: i2c: Implement driver model support in the i2c command

In reply to 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.

---

 common/cmd_i2c.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 267 insertions(+), 45 deletions(-)
common/cmd_i2c.c +267 -45
index c266b88..6766856 100644
@@ -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)
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#6 lore raw

RFC PATCH 4/12 dm: i2c: Implement driver model support in the i2c command

Hello Simon,

Am 13.10.2014 07:39, schrieb Simon Glass:

Quoted 584 lines

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.

---

  common/cmd_i2c.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++--------
  1 file changed, 267 insertions(+), 45 deletions(-)
common/cmd_i2c.c +262 -42
index c266b88..6766856 100644
@@ -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);
  	}

common/cmd_i2c.c static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) · line 1756

Quoted 6 lines
common/cmd_i2c.c +2 -1
@@ -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

Quoted 23 lines
common/cmd_i2c.c +3 -2
+#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)
Signature · 2 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
#7 lore raw

RFC PATCH 5/12 dm: i2c: Add I2C emulation driver for sandbox

In reply to Simon Glass

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.

---

 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
drivers/i2c/Makefile +1 -0
index 2ee468d..10edea6 100644
@@ -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
drivers/i2c/i2c-emul-uclass.c new file +14 -0
new file mode 100644
index 0000000..aa89f95
@@ -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",
+};
include/dm/uclass-id.h +1 -0
index 9611a13..9e20d31 100644
@@ -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 */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#8 lore raw

RFC PATCH 6/12 dm: i2c: Add a sandbox I2C driver

In reply to Simon Glass

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

---

 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
drivers/i2c/Makefile +1 -1
index 10edea6..ea18228 100644
@@ -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
drivers/i2c/sandbox_i2c.c new file +148 -0

148 lines not on this page · raw message

Signature · 1 line
2.1.0.rc2.206.gedb03e5
#9 lore raw

RFC PATCH 7/12 dm: i2c: Add an I2C EEPROM simulator

In reply to Simon Glass

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

---

 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
drivers/misc/Makefile +3 -0
index 2f2e48f..ff02184 100644
@@ -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
drivers/misc/i2c_eeprom_emul.c new file +108 -0

108 lines not on this page · raw message

Signature · 1 line
2.1.0.rc2.206.gedb03e5
#10 lore raw

RFC PATCH 8/12 dm: i2c: config: Enable I2C for sandbox using driver model

In reply to Simon Glass

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

---

 include/configs/sandbox.h | 6 ++++++
 1 file changed, 6 insertions(+)
include/configs/sandbox.h +6 -0
index 2fd2c64..c5b46ac 100644
@@ -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
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#11 lore raw

RFC PATCH 9/12 dm: i2c: dts: Add an I2C bus for sandbox

In reply to Simon Glass

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

---

 arch/sandbox/dts/sandbox.dts | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
arch/sandbox/dts/sandbox.dts +17 -0
index 7614715..11748ae 100644
@@ -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>;
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#12 lore raw

RFC PATCH 10/12 dm: WIP: EEPROM driver

In reply to Simon Glass

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.

---

 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
drivers/misc/Makefile +1 -0
index ff02184..6fa836f 100644
@@ -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
drivers/misc/i2c_eeprom.c new file +51 -0

51 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 9e20d31..8f389df 100644
@@ -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,
include/i2c_eeprom.h new file +19 -0
new file mode 100644
index 0000000..ea6c962
@@ -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
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#13 lore raw

RFC PATCH 11/12 dm: i2c: Add tests for I2C

In reply to Simon Glass

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

---

 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
test/dm/Makefile +1 -0
index 75d3d41..612aa95 100644
@@ -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
test/dm/i2c.c new file +100 -0

100 lines not on this page · raw message

test/dm/test.dts +17 -0
index 1fba792..69991a3 100644
@@ -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>;
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#14 lore raw

RFC PATCH 12/12 dm: i2c: tegra: Convert to driver model for I2C for seaboard

In reply to Simon Glass

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.

---

 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(-)
arch/arm/cpu/tegra20-common/pmu.c +16 -5
index c595f70..36a76a2 100644
@@ -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);
arch/arm/include/asm/arch-tegra/tegra_i2c.h +1 -1
index 7ca6907..eeeb247 100644
@@ -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_ */
board/nvidia/common/board.c +0 -4
index 03f055d..7226fa4 100644
@@ -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");
drivers/i2c/tegra_i2c.c +114 -199

489 lines not on this page · raw message

drivers/power/tps6586x.c +7 -20
index d29d969..29bab4c 100644
@@ -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;
 }
include/configs/cardhu.h +0 -2
index 09129c7..5be3752 100644
@@ -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
 
include/configs/colibri_t30.h +0 -2
index 782b9d1..18ce2fa 100644
@@ -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
include/configs/seaboard.h +0 -3
index 04e4f82..5f77051 100644
@@ -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
include/configs/tegra-common.h +1 -0
index 4719ee1..a68b474 100644
@@ -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
include/configs/tegra20-common.h +0 -3
index 21bf977..6330281 100644
@@ -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
 
include/tps6586x.h +1 -1
index 78ce428..9ea0c89 100644
@@ -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_ */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
#15 lore raw

cover RFC: dm: Add I2C support

In reply to Simon Glass
Quoted 32 lines · 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().

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.

Quoted 7 lines

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?

Signature · 8 lines
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>
#16 lore raw

cover RFC: dm: Add I2C support

Hello Tom,

Am 24.10.2014 17:03, schrieb Tom Rini:

Quoted 40 lines · Simon Glass
Quoted 39 lines

(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.

Quoted 3 lines
Quoted 1 line

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

Signature · 2 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
#17 lore raw

cover RFC: dm: Add I2C support

In reply to Simon Glass

Hello Simon,

sorry for the long delay...

Am 13.10.2014 07:39, schrieb Simon Glass:

Quoted 23 lines

(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.

Quoted 3 lines

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!

Quoted 4 lines

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.

Quoted 5 lines

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) ...

Quoted 1 line

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

to the hole series.

bye,
Heiko

Signature · 2 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
#18 lore raw

cover RFC: dm: Add I2C support

Hi Heiko,

Quoted 74 lines · Heiko Schocher

Hello Simon,

sorry for the long delay...

Am 13.10.2014 07:39, schrieb Simon Glass:

Quoted 26 lines

(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.

Quoted 3 lines

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!

Quoted 5 lines

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.

Quoted 5 lines

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) ...

Quoted 1 line

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

Thanks for your great work.

Quoted 8 lines

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

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