fs: enable fstab devicetree integration for fatfs

In order to use fstab with fatfs in addition to
littlefs a new driver fstab,fatfs was introduced
containing the required logic to detect and if
needed automount fatfs devices specified in fstab.
Additionally as the partition phandle is not needed
by fatfs and currently is specific to littlefs it
was moved from the common dts binding into the
littlefs binding.

Signed-off-by: Carlo Kirchmeier <carlo.kirchmeier@zuehlke.com>
Co-authored-by: Carlo Kirchmeier <carlo.kirchmeier@zuehlke.com>
Co-authored-by: Dominik Ermel <dominik.ermel@nordicsemi.no>
diff --git a/dts/bindings/fs/zephyr,fstab,fatfs.yaml b/dts/bindings/fs/zephyr,fstab,fatfs.yaml
new file mode 100644
index 0000000..ba11fae
--- /dev/null
+++ b/dts/bindings/fs/zephyr,fstab,fatfs.yaml
@@ -0,0 +1,9 @@
+# Copyright (C) 2025 Endress+Hauser AG
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+    Description of pre-defined fatfs file systems.
+
+compatible: "zephyr,fstab,fatfs"
+
+include: zephyr,fstab-common.yaml
diff --git a/dts/bindings/fs/zephyr,fstab,littlefs.yaml b/dts/bindings/fs/zephyr,fstab,littlefs.yaml
index 92e6677..8703c51 100644
--- a/dts/bindings/fs/zephyr,fstab,littlefs.yaml
+++ b/dts/bindings/fs/zephyr,fstab,littlefs.yaml
@@ -11,6 +11,12 @@
 properties:
   # num-files and num-dirs are not filesystem-specific.
 
+  partition:
+    type: phandle
+    required: true
+    description: |
+      A reference to the file system's partition.
+
   read-size:
     type: int
     required: true
diff --git a/dts/bindings/fs/zephyr,fstab-common.yaml b/dts/bindings/fs/zephyr,fstab-common.yaml
index e7e9fa3..054098e 100644
--- a/dts/bindings/fs/zephyr,fstab-common.yaml
+++ b/dts/bindings/fs/zephyr,fstab-common.yaml
@@ -12,12 +12,6 @@
     description: |
       The absolute path used as the file system mount point.
 
-  partition:
-    type: phandle
-    required: true
-    description: |
-      A reference to the file system's partition.
-
   automount:
     type: boolean
     description: |
diff --git a/subsys/fs/Kconfig.fatfs b/subsys/fs/Kconfig.fatfs
index 2d3c6b1..ee0ec6a 100644
--- a/subsys/fs/Kconfig.fatfs
+++ b/subsys/fs/Kconfig.fatfs
@@ -299,6 +299,14 @@
 	   be used for mounting fatfs filesystems anymore.
 	depends on FS_FATFS_CUSTOM_MOUNT_POINT_COUNT > 0
 
+DT_COMPAT_ZEPHYR_FSTAB_FATFS := zephyr,fstab,fatfs
+config FS_FATFS_FSTAB_AUTOMOUNT
+	bool "Support for fstab auto-mounting"
+	depends on $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_FSTAB_FATFS))
+	help
+	  This option enables fatfs support for the devicetree fstab auto-mounting
+	  functionality.
+
 endmenu
 
 endif # FAT_FILESYSTEM_ELM
diff --git a/subsys/fs/fat_fs.c b/subsys/fs/fat_fs.c
index a0d99c6..016c23a 100644
--- a/subsys/fs/fat_fs.c
+++ b/subsys/fs/fat_fs.c
@@ -557,6 +557,43 @@
 #endif
 };
 
+#define DT_DRV_COMPAT zephyr_fstab_fatfs
+
+#define DEFINE_FS(inst)                                                                            \
+	BUILD_ASSERT(DT_INST_PROP(inst, disk_access), "FATFS needs disk-access");                  \
+	BUILD_ASSERT(!DT_INST_PROP(inst, read_only),                                               \
+		     "READ_ONLY not supported for individual instances see FS_FATFS_READ_ONLY");   \
+	BUILD_ASSERT(!DT_INST_PROP(inst, no_format),                                               \
+		     "NO_FORMAT not supported for individual instanzes FS_FATFS_MKFS");            \
+	static FATFS fs_data_##inst;                                                               \
+	struct fs_mount_t FS_FSTAB_ENTRY(DT_DRV_INST(inst)) = {                                    \
+		.type = FS_FATFS,                                                                  \
+		.mnt_point = DT_INST_PROP(inst, mount_point),                                      \
+		.fs_data = &fs_data_##inst,                                                        \
+		.storage_dev = NULL,                                                               \
+		.flags = FSTAB_ENTRY_DT_MOUNT_FLAGS(DT_DRV_INST(inst)),                            \
+	};
+
+DT_INST_FOREACH_STATUS_OKAY(DEFINE_FS);
+
+#ifdef CONFIG_FS_FATFS_FSTAB_AUTOMOUNT
+#define REFERENCE_MOUNT(inst) (&FS_FSTAB_ENTRY(DT_DRV_INST(inst))),
+
+static void automount_if_enabled(struct fs_mount_t *mountp)
+{
+	int ret = 0;
+
+	if ((mountp->flags & FS_MOUNT_FLAG_AUTOMOUNT) != 0) {
+		ret = fs_mount(mountp);
+		if (ret < 0) {
+			LOG_ERR("Error mounting filesystem: at %s: %d", mountp->mnt_point, ret);
+		} else {
+			LOG_DBG("FATFS Filesystem \"%s\" initialized", mountp->mnt_point);
+		}
+	}
+}
+#endif /* CONFIG_FS_FATFS_FSTAB_AUTOMOUNT */
+
 #if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT
 const char *VolumeStr[CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT];
 #endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */
@@ -581,7 +618,21 @@
 		}
 	}
 #endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */
-	return fs_register(FS_FATFS, &fatfs_fs);
+	int rc = fs_register(FS_FATFS, &fatfs_fs);
+
+#ifdef CONFIG_FS_FATFS_FSTAB_AUTOMOUNT
+	if (rc == 0) {
+		struct fs_mount_t *partitions[] = {DT_INST_FOREACH_STATUS_OKAY(REFERENCE_MOUNT)};
+
+		for (size_t i = 0; i < ARRAY_SIZE(partitions); i++) {
+			struct fs_mount_t *mpi = partitions[i];
+
+			automount_if_enabled(mpi);
+		}
+	}
+#endif /* CONFIG_FS_FATFS_FSTAB_AUTOMOUNT */
+
+	return rc;
 }
 
 SYS_INIT(fatfs_init, POST_KERNEL, CONFIG_FILE_SYSTEM_INIT_PRIORITY);