context FEATURE ly_ctx_get_submodule functions
diff --git a/doc/transition.dox b/doc/transition.dox
index e82aa00..44ec3f1 100644
--- a/doc/transition.dox
+++ b/doc/transition.dox
@@ -117,12 +117,12 @@
  * ly_ctx_new_ylpath()       | TBD                                  | ^
  * -                         | ::ly_ctx_unset_searchdir_last()      | Extend the functionality of the ::ly_ctx_unset_searchdir() to make its use easier.
  * ly_ctx_get_module_older() | -                                    | Removed functionality.
- * ly_ctx_get_submodule()    | -                                    | Removed functionality since the submodules are only in the parsed tree.
- * ly_ctx_get_submodule2()   | -                                    | ^
  * -                         | ::ly_ctx_get_module_implemented()    | Supplement for ::ly_ctx_get_module()
  * -                         | ::ly_ctx_get_module_latest()         | ^
  * -                         | ::ly_ctx_get_module_implemented_ns() | Supplement for ::ly_ctx_get_module_ns()
  * -                         | ::ly_ctx_get_module_latest_ns()      | ^
+ * -                         | ::ly_ctx_get_submodule_latest()      | Supplement for ::ly_ctx_get_submodule()
+ * -                         | ::ly_ctx_get_submodule2_latest()     | Supplement for ::ly_ctx_get_submodule2()
  * ly_ctx_get_module_by_ns() | ::ly_ctx_get_module_ns ()            | Redesign the API - replace some of the parameters with standalone supplement functions.
  * -                         | ::ly_ctx_reset_latests()             | The new functionality of maintaining the latest module revision flag.
  * ly_ctx_unset_searchdirs() | ::ly_ctx_unset_searchdir()           | Simplify API and instead of index numbers, work with the values themselves.
diff --git a/src/common.h b/src/common.h
index 438c7f8..a7c483c 100644
--- a/src/common.h
+++ b/src/common.h
@@ -304,20 +304,6 @@
 };
 
 /**
- * @brief Try to find submodule in the context. Submodules are present only in the parsed (lysp_) schema trees, if only
- * the compiled versions of the schemas are present, the submodule cannot be returned even if it was used to compile
- * some of the currently present schemas.
- *
- * @param[in] ctx Context where to search in case @p module is NULL.
- * @param[in] module Submodule parent (belongs-to) module in case @p ctx is NULL.
- * @param[in] submodule Name of the submodule to find.
- * @param[in] revision Optional revision of the submodule to find. If not specified, the latest revision is returned.
- * @return Pointer to the specified submodule if it is present in the context.
- */
-struct lysp_submodule *ly_ctx_get_submodule(const struct ly_ctx *ctx, const struct lys_module *module,
-        const char *submodule, const char *revision);
-
-/**
  * @brief Get the (only) implemented YANG module specified by its name.
  *
  * @param[in] ctx Context where to search.
diff --git a/src/context.c b/src/context.c
index 88f2f00..46d9cbd 100644
--- a/src/context.c
+++ b/src/context.c
@@ -516,53 +516,98 @@
     return ly_ctx_get_module_implemented_by(ctx, ns, 0, offsetof(struct lys_module, ns));
 }
 
-struct lysp_submodule *
-ly_ctx_get_submodule(const struct ly_ctx *ctx, const struct lys_module *module, const char *submodule, const char *revision)
+/**
+ * @brief Try to find a submodule in a module.
+ *
+ * @param[in] module Module where to search in.
+ * @param[in] submodule Name of the submodule to find.
+ * @param[in] revision Revision of the submodule to find. NULL for submodule with no revision.
+ * @param[in] latest Ignore @p revision and look for the latest revision.
+ * @return Pointer to the specified submodule if it is present in the context.
+ */
+static const struct lysp_submodule *
+_ly_ctx_get_submodule2(const struct lys_module *module, const char *submodule, const char *revision, ly_bool latest)
 {
-    const struct lys_module *mod;
     struct lysp_include *inc;
-    uint32_t v;
     LY_ARRAY_COUNT_TYPE u;
 
-    assert((ctx || module) && submodule);
+    LY_CHECK_ARG_RET(NULL, module, module->parsed, submodule, NULL);
 
-    if (module) {
-        if (!module->parsed) {
-            return NULL;
+    LY_ARRAY_FOR(module->parsed->includes, u) {
+        if (module->parsed->includes[u].submodule && !strcmp(submodule, module->parsed->includes[u].submodule->name)) {
+            inc = &module->parsed->includes[u];
+
+            if (latest && inc->submodule->latest_revision) {
+                /* latest revision */
+                return inc->submodule;
+            } else if (!revision && !inc->submodule->revs) {
+                /* no revision */
+                return inc->submodule;
+            } else if (revision && inc->submodule->revs && !strcmp(revision, inc->submodule->revs[0].date)) {
+                /* specific revision */
+                return inc->submodule;
+            }
         }
-
-        /* check only this module */
-        mod = module;
-        goto check_mod;
     }
 
+    return NULL;
+}
+
+/**
+ * @brief Try to find a submodule in the context.
+ *
+ * @param[in] ctx Context where to search in.
+ * @param[in] submodule Name of the submodule to find.
+ * @param[in] revision Revision of the submodule to find. NULL for submodule with no revision.
+ * @param[in] latest Ignore @p revision and look for the latest revision.
+ * @return Pointer to the specified submodule if it is present in the context.
+ */
+static const struct lysp_submodule *
+_ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *submodule, const char *revision, ly_bool latest)
+{
+    const struct lys_module *mod;
+    const struct lysp_submodule *submod = NULL;
+    uint32_t v;
+
+    LY_CHECK_ARG_RET(ctx, ctx, submodule, NULL);
+
     for (v = 0; v < ctx->list.count; ++v) {
         mod = ctx->list.objs[v];
         if (!mod->parsed) {
             continue;
         }
 
-check_mod:
-        LY_ARRAY_FOR(mod->parsed->includes, u) {
-            if (mod->parsed->includes[u].submodule && !strcmp(submodule, mod->parsed->includes[u].submodule->name)) {
-                inc = &mod->parsed->includes[u];
-                if (!revision) {
-                    if (inc->submodule->latest_revision) {
-                        return inc->submodule;
-                    }
-                } else if (inc->submodule->revs && !strcmp(revision, inc->submodule->revs[0].date)) {
-                    return inc->submodule;
-                }
-            }
-        }
-
-        if (module) {
-            /* do not check other modules */
+        submod = _ly_ctx_get_submodule2(mod, submodule, revision, latest);
+        if (submod) {
             break;
         }
     }
 
-    return NULL;
+    return submod;
+}
+
+API const struct lysp_submodule *
+ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *submodule, const char *revision)
+{
+    return _ly_ctx_get_submodule(ctx, submodule, revision, 0);
+}
+
+API const struct lysp_submodule *
+ly_ctx_get_submodule_latest(const struct ly_ctx *ctx, const char *submodule)
+{
+    return _ly_ctx_get_submodule(ctx, submodule, NULL, 1);
+}
+
+API const struct lysp_submodule *
+ly_ctx_get_submodule2(const struct lys_module *module, const char *submodule, const char *revision)
+{
+    return _ly_ctx_get_submodule2(module, submodule, revision, 0);
+}
+
+API const struct lysp_submodule *
+ly_ctx_get_submodule2_latest(const struct lys_module *module, const char *submodule)
+{
+    return _ly_ctx_get_submodule2(module, submodule, NULL, 1);
 }
 
 API void
diff --git a/src/context.h b/src/context.h
index 917fcef..ec55a29 100644
--- a/src/context.h
+++ b/src/context.h
@@ -117,6 +117,10 @@
  * - ::ly_ctx_get_module_implemented_ns()
  * - ::ly_ctx_get_module_latest()
  * - ::ly_ctx_get_module_latest_ns()
+ * - ::ly_ctx_get_submodule()
+ * - ::ly_ctx_get_submodule_latest()
+ * - ::ly_ctx_get_submodule2()
+ * - ::ly_ctx_get_submodule2_latest()
  * - ::ly_ctx_reset_latests()
  *
  * - ::ly_ctx_get_yanglib_data()
@@ -417,6 +421,47 @@
 struct lys_module *ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns);
 
 /**
+ * @brief Get a specific submodule from context. If its belongs-to module is known, use ::ly_ctx_get_submodule2().
+ *
+ * @param[in] ctx libyang context to search in.
+ * @param[in] submodule Submodule name to find.
+ * @param[in] revision Revision of the submodule to find, NULL for a submodule without a revision.
+ * @return Found submodule, NULL if there is none.
+ */
+const struct lysp_submodule *ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *submodule, const char *revision);
+
+/**
+ * @brief Get the latests revision of a submodule from context. If its belongs-to module is known,
+ * use ::ly_ctx_get_submodule2_latest().
+ *
+ * @param[in] ctx libyang context to search in.
+ * @param[in] submodule Submodule name to find.
+ * @return Found submodule, NULL if there is none.
+ */
+const struct lysp_submodule *ly_ctx_get_submodule_latest(const struct ly_ctx *ctx, const char *submodule);
+
+/**
+ * @brief Get a specific submodule from a module. If the belongs-to module is not known, use ::ly_ctx_get_submodule().
+ *
+ * @param[in] module Belongs-to module to search in.
+ * @param[in] submodule Submodule name to find.
+ * @param[in] revision Revision of the submodule to find, NULL for a submodule without a revision.
+ * @return Found submodule, NULL if there is none.
+ */
+const struct lysp_submodule *ly_ctx_get_submodule2(const struct lys_module *module, const char *submodule,
+        const char *revision);
+
+/**
+ * @brief Get the latest revision of a submodule from a module. If the belongs-to module is not known,
+ * use ::ly_ctx_get_submodule_latest().
+ *
+ * @param[in] module Belongs-to module to search in.
+ * @param[in] submodule Submodule name to find.
+ * @return Found submodule, NULL if there is none.
+ */
+const struct lysp_submodule *ly_ctx_get_submodule2_latest(const struct lys_module *module, const char *submodule);
+
+/**
  * @brief Reset cached latest revision information of the schemas in the context.
  *
  * When a (sub)module is imported/included without revision, the latest revision is
diff --git a/src/parser_yang.c b/src/parser_yang.c
index d92bc87..0e11bb0 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -4021,7 +4021,7 @@
     size_t word_len;
     enum ly_stmt kw, prev_kw = 0;
     enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
-    struct lysp_submodule *dup;
+    const struct lysp_submodule *dup;
 
     mod->is_submod = 0;
 
@@ -4203,7 +4203,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(PARSER_CTX(ctx), NULL, mod->mod->name, NULL);
+    dup = ly_ctx_get_submodule_latest(PARSER_CTX(ctx), mod->mod->name);
     if (dup) {
         LOGVAL_PARSER(ctx, LY_VCODE_NAME2_COL, "module", "submodule", mod->mod->name);
         return LY_EVALID;
@@ -4228,7 +4228,7 @@
     size_t word_len;
     enum ly_stmt kw, prev_kw = 0;
     enum yang_module_stmt mod_stmt = Y_MOD_MODULE_HEADER;
-    struct lysp_submodule *dup;
+    const struct lysp_submodule *dup;
 
     submod->is_submod = 1;
 
@@ -4407,7 +4407,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(PARSER_CTX(ctx), NULL, submod->name, NULL);
+    dup = ly_ctx_get_submodule_latest(PARSER_CTX(ctx), submod->name);
     /* main modules may have different revisions */
     if (dup && strcmp(dup->mod->name, submod->mod->name)) {
         LOGVAL_PARSER(ctx, LY_VCODE_NAME_COL, "submodules", dup->name);
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 597fc6e..03a2203 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -3637,7 +3637,7 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct yin_subelement *subelems = NULL;
-    struct lysp_submodule *dup;
+    const struct lysp_submodule *dup;
     size_t subelems_size;
 
     mod->is_submod = 0;
@@ -3680,7 +3680,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(ctx->xmlctx->ctx, NULL, mod->mod->name, NULL);
+    dup = ly_ctx_get_submodule_latest(ctx->xmlctx->ctx, mod->mod->name);
     if (dup) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_NAME2_COL, "module", "submodule", mod->mod->name);
         return LY_EVALID;
@@ -3703,7 +3703,7 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct yin_subelement *subelems = NULL;
-    struct lysp_submodule *dup;
+    const struct lysp_submodule *dup;
     size_t subelems_size;
 
     submod->is_submod = 1;
@@ -3745,7 +3745,7 @@
 
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
-    dup = ly_ctx_get_submodule(ctx->xmlctx->ctx, NULL, submod->name, NULL);
+    dup = ly_ctx_get_submodule_latest(ctx->xmlctx->ctx, submod->name);
     if (dup && strcmp(dup->mod->name, submod->mod->name)) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_NAME_COL, "submodules", dup->name);
         return LY_EVALID;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 831a055..d3bda7a 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -826,7 +826,7 @@
     lysp_sort_revisions(submod->revs);
 
     /* decide the latest revision */
-    latest_sp = ly_ctx_get_submodule(NULL, submod->mod, submod->name, NULL);
+    latest_sp = (struct lysp_submodule *)ly_ctx_get_submodule2_latest(submod->mod, submod->name);
     if (latest_sp) {
         if (submod->revs) {
             if (!latest_sp->revs) {