diff options
author | Tom Rini <trini@konsulko.com> | 2019-02-11 11:15:34 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-02-11 11:15:34 -0500 |
commit | f94fa0e94f36c740d3c7aa314c89a750c742185b (patch) | |
tree | 42077386d60386628bed02011566ddf990913eb8 | |
parent | f49929772c5ea22e4af987bfb1e5ae13e9895093 (diff) | |
parent | c4bd12a7dad43ed9de3070c7c5e8b690d8c03a79 (diff) | |
download | u-boot-f94fa0e94f36c740d3c7aa314c89a750c742185b.tar.gz |
Merge branch 'master' of git://git.denx.de/u-boot-i2c
- DM I2C improvements
-rw-r--r-- | drivers/core/of_access.c | 18 | ||||
-rw-r--r-- | drivers/core/read.c | 8 | ||||
-rw-r--r-- | drivers/i2c/i2c-uclass.c | 54 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-mux-uclass.c | 29 | ||||
-rw-r--r-- | include/dm/of_access.h | 10 | ||||
-rw-r--r-- | include/dm/read.h | 16 | ||||
-rw-r--r-- | include/fdtdec.h | 13 | ||||
-rw-r--r-- | lib/fdtdec.c | 33 | ||||
-rw-r--r-- | test/dm/test-fdt.c | 23 |
9 files changed, 198 insertions, 6 deletions
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 14c020a687..945b81448c 100644 --- a/drivers/core/of_access.c +++ b/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; diff --git a/drivers/core/read.c b/drivers/core/read.c index 3c46b3674e..6bda077a34 100644 --- a/drivers/core/read.c +++ b/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); +} diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 975318e5f2..49e23a0a4b 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/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), diff --git a/drivers/i2c/muxes/i2c-mux-uclass.c b/drivers/i2c/muxes/i2c-mux-uclass.c index a680ee1762..8b1149997a 100644 --- a/drivers/i2c/muxes/i2c-mux-uclass.c +++ b/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; } diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 5ed1a0cdb4..13fedb7cf5 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -425,6 +425,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 * * @return node referred to by stdout-path alias, or NULL if none diff --git a/include/dm/read.h b/include/dm/read.h index 389e30e7fb..60b727cbd8 100644 --- a/include/dm/read.h +++ b/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 */ /** diff --git a/include/fdtdec.h b/include/fdtdec.h index 2a8ad96026..b7e35cd87c 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -619,6 +619,19 @@ 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 * * @param blob Device tree blob (if NULL, then NULL is returned) diff --git a/lib/fdtdec.c b/lib/fdtdec.c index fd0ad6ea84..09a7e133a5 100644 --- a/lib/fdtdec.c +++ b/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; diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 984b80c02c..be16c99e17 100644 --- a/test/dm/test-fdt.c +++ b/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; |