Forráskód Böngészése

Merge branch 'master' of git://git.denx.de/u-boot-i2c

- DM I2C improvements
Tom Rini 5 éve
szülő
commit
f94fa0e94f

+ 18 - 0
drivers/core/of_access.c

@@ -812,6 +812,24 @@ int of_alias_get_id(const struct device_node *np, const char *stem)
 	return id;
 }
 
+int of_alias_get_highest_id(const char *stem)
+{
+	struct alias_prop *app;
+	int id = -1;
+
+	mutex_lock(&of_mutex);
+	list_for_each_entry(app, &aliases_lookup, link) {
+		if (strcmp(app->stem, stem) != 0)
+			continue;
+
+		if (app->id > id)
+			id = app->id;
+	}
+	mutex_unlock(&of_mutex);
+
+	return id;
+}
+
 struct device_node *of_get_stdout(void)
 {
 	return of_stdout;

+ 8 - 0
drivers/core/read.c

@@ -264,3 +264,11 @@ u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr)
 {
 	return ofnode_translate_address(dev_ofnode(dev), in_addr);
 }
+
+int dev_read_alias_highest_id(const char *stem)
+{
+	if (of_live_active())
+		return of_alias_get_highest_id(stem);
+
+	return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
+}

+ 51 - 3
drivers/i2c/i2c-uclass.c

@@ -619,13 +619,61 @@ static int i2c_child_post_bind(struct udevice *dev)
 #endif
 }
 
+struct i2c_priv {
+	int max_id;
+};
+
+static int i2c_post_bind(struct udevice *dev)
+{
+	struct uclass *class = dev->uclass;
+	struct i2c_priv *priv = class->priv;
+	int ret = 0;
+
+	/* Just for sure */
+	if (!priv)
+		return -ENOMEM;
+
+	debug("%s: %s, req_seq=%d\n", __func__, dev->name, dev->req_seq);
+
+	/* if there is no alias ID, use the first free */
+	if (dev->req_seq == -1)
+		dev->req_seq = ++priv->max_id;
+
+	debug("%s: %s, new req_seq=%d\n", __func__, dev->name, dev->req_seq);
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+	ret = dm_scan_fdt_dev(dev);
+#endif
+	return ret;
+}
+
+int i2c_uclass_init(struct uclass *class)
+{
+	struct i2c_priv *priv = class->priv;
+
+	/* Just for sure */
+	if (!priv)
+		return -ENOMEM;
+
+	/* Get the last allocated alias. */
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	priv->max_id = dev_read_alias_highest_id("i2c");
+#else
+	priv->max_id = -1;
+#endif
+
+	debug("%s: highest alias id is %d\n", __func__, priv->max_id);
+
+	return 0;
+}
+
 UCLASS_DRIVER(i2c) = {
 	.id		= UCLASS_I2C,
 	.name		= "i2c",
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
-#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
-	.post_bind	= dm_scan_fdt_dev,
-#endif
+	.post_bind	= i2c_post_bind,
+	.init		= i2c_uclass_init,
+	.priv_auto_alloc_size = sizeof(struct i2c_priv),
 	.post_probe	= i2c_post_probe,
 	.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
 	.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),

+ 26 - 3
drivers/i2c/muxes/i2c-mux-uclass.c

@@ -59,11 +59,34 @@ static int i2c_mux_post_bind(struct udevice *mux)
 	dev_for_each_subnode(node, mux) {
 		struct udevice *dev;
 		const char *name;
+		const char *arrow = "->";
+		char *full_name;
+		int parent_name_len, arrow_len, mux_name_len, name_len;
 
 		name = ofnode_get_name(node);
-		ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name,
-						 node, &dev);
-		debug("   - bind ret=%d, %s\n", ret, dev ? dev->name : NULL);
+
+		/* Calculate lenghts of strings */
+		parent_name_len = strlen(mux->parent->name);
+		arrow_len = strlen(arrow);
+		mux_name_len = strlen(mux->name);
+		name_len = strlen(name);
+
+		full_name = calloc(1, parent_name_len + arrow_len +
+				   mux_name_len + arrow_len + name_len + 1);
+		if (!full_name)
+			return -ENOMEM;
+
+		/* Compose bus name */
+		strcat(full_name, mux->parent->name);
+		strcat(full_name, arrow);
+		strcat(full_name, mux->name);
+		strcat(full_name, arrow);
+		strcat(full_name, name);
+
+		ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv",
+						 full_name, node, &dev);
+		debug("   - bind ret=%d, %s, req_seq %d\n", ret,
+		      dev ? dev->name : NULL, dev->req_seq);
 		if (ret)
 			return ret;
 	}

+ 10 - 0
include/dm/of_access.h

@@ -424,6 +424,16 @@ int of_alias_scan(void);
  */
 int of_alias_get_id(const struct device_node *np, const char *stem);
 
+/**
+ * of_alias_get_highest_id - Get highest alias id for the given stem
+ * @stem:	Alias stem to be examined
+ *
+ * The function travels the lookup table to get the highest alias id for the
+ * given alias stem.
+ * @return alias ID, if found, else -1
+ */
+int of_alias_get_highest_id(const char *stem);
+
 /**
  * of_get_stdout() - Get node to use for stdout
  *

+ 16 - 0
include/dm/read.h

@@ -510,6 +510,17 @@ int dev_read_resource_byname(struct udevice *dev, const char *name,
  * @return the translated address; OF_BAD_ADDR on error
  */
 u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_addr);
+
+/**
+ * dev_read_alias_highest_id - Get highest alias id for the given stem
+ * @stem:	Alias stem to be examined
+ *
+ * The function travels the lookup table to get the highest alias id for the
+ * given alias stem.
+ * @return alias ID, if found, else -1
+ */
+int dev_read_alias_highest_id(const char *stem);
+
 #else /* CONFIG_DM_DEV_READ_INLINE is enabled */
 
 static inline int dev_read_u32(struct udevice *dev,
@@ -740,6 +751,11 @@ static inline u64 dev_translate_address(struct udevice *dev, const fdt32_t *in_a
 	return ofnode_translate_address(dev_ofnode(dev), in_addr);
 }
 
+static inline int dev_read_alias_highest_id(const char *stem)
+{
+	return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
+}
+
 #endif /* CONFIG_DM_DEV_READ_INLINE */
 
 /**

+ 13 - 0
include/fdtdec.h

@@ -618,6 +618,19 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name,
 int fdtdec_get_alias_seq(const void *blob, const char *base, int node,
 			 int *seqp);
 
+/**
+ * Get the highest alias number for susbystem.
+ *
+ * It parses all aliases and find out highest recorded alias for subsystem.
+ * Aliases are of the form <base><num> where <num> is the sequence number.
+ *
+ * @param blob		Device tree blob (if NULL, then error is returned)
+ * @param base		Base name for alias susbystem (before the number)
+ *
+ * @return 0 highest alias ID, -1 if not found
+ */
+int fdtdec_get_alias_highest_id(const void *blob, const char *base);
+
 /**
  * Get a property from the /chosen node
  *

+ 33 - 0
lib/fdtdec.c

@@ -542,6 +542,39 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
 	return -ENOENT;
 }
 
+int fdtdec_get_alias_highest_id(const void *blob, const char *base)
+{
+	int base_len = strlen(base);
+	int prop_offset;
+	int aliases;
+	int max = -1;
+
+	debug("Looking for highest alias id for '%s'\n", base);
+
+	aliases = fdt_path_offset(blob, "/aliases");
+	for (prop_offset = fdt_first_property_offset(blob, aliases);
+	     prop_offset > 0;
+	     prop_offset = fdt_next_property_offset(blob, prop_offset)) {
+		const char *prop;
+		const char *name;
+		int len, val;
+
+		prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
+		debug("   - %s, %s\n", name, prop);
+		if (*prop != '/' || prop[len - 1] ||
+		    strncmp(name, base, base_len))
+			continue;
+
+		val = trailing_strtol(name);
+		if (val > max) {
+			debug("Found seq %d\n", val);
+			max = val;
+		}
+	}
+
+	return max;
+}
+
 const char *fdtdec_get_chosen_prop(const void *blob, const char *name)
 {
 	int chosen_node;

+ 23 - 0
test/dm/test-fdt.c

@@ -219,6 +219,29 @@ static int dm_test_fdt(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_fdt, 0);
 
+static int dm_test_alias_highest_id(struct unit_test_state *uts)
+{
+	int ret;
+
+	ret = dev_read_alias_highest_id("eth");
+	ut_asserteq(5, ret);
+
+	ret = dev_read_alias_highest_id("gpio");
+	ut_asserteq(2, ret);
+
+	ret = dev_read_alias_highest_id("pci");
+	ut_asserteq(2, ret);
+
+	ret = dev_read_alias_highest_id("i2c");
+	ut_asserteq(0, ret);
+
+	ret = dev_read_alias_highest_id("deadbeef");
+	ut_asserteq(-1, ret);
+
+	return 0;
+}
+DM_TEST(dm_test_alias_highest_id, 0);
+
 static int dm_test_fdt_pre_reloc(struct unit_test_state *uts)
 {
 	struct uclass *uc;