diff --git a/examples/Makefile b/examples/Makefile
index 074404b3..32b09101 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -33,6 +33,7 @@ obj-m += vkbd.o
 obj-m += static_key.o
 obj-m += led.o
 obj-m += dht11.o
+obj-m += devicetree.o
 
 PWD := $(CURDIR)
 
diff --git a/examples/devicetree.c b/examples/devicetree.c
new file mode 100644
index 00000000..bb23d194
--- /dev/null
+++ b/examples/devicetree.c
@@ -0,0 +1,151 @@
+/* devicetree.c - Demonstrates device tree interaction with kernel modules */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+
+#define DRIVER_NAME "lkmpg_devicetree"
+
+/* Structure to hold device-specific data */
+struct dt_device_data {
+    const char *label;
+    u32 reg_value;
+    u32 custom_value;
+    bool has_clock;
+};
+
+/* Probe function - called when device tree node matches */
+static int dt_probe(struct platform_device *pdev)
+{
+    struct device *dev = &pdev->dev;
+    struct device_node *np = dev->of_node;
+    struct dt_device_data *data;
+    const char *string_prop;
+    u32 value;
+    int ret;
+
+    pr_info("%s: Device tree probe called for %s\n", DRIVER_NAME,
+            np->full_name);
+
+    /* Allocate memory for device data */
+    data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+    if (!data)
+        return -ENOMEM;
+
+    /* Read a string property */
+    ret = of_property_read_string(np, "label", &string_prop);
+    if (ret == 0) {
+        data->label = string_prop;
+        pr_info("%s: Found label property: %s\n", DRIVER_NAME, data->label);
+    } else {
+        data->label = "unnamed";
+        pr_info("%s: No label property found, using default\n", DRIVER_NAME);
+    }
+
+    /* Read a u32 property */
+    ret = of_property_read_u32(np, "reg", &value);
+    if (ret == 0) {
+        data->reg_value = value;
+        pr_info("%s: Found reg property: 0x%x\n", DRIVER_NAME, data->reg_value);
+    }
+
+    /* Read a custom u32 property */
+    ret = of_property_read_u32(np, "lkmpg,custom-value", &value);
+    if (ret == 0) {
+        data->custom_value = value;
+        pr_info("%s: Found custom-value property: %u\n", DRIVER_NAME,
+                data->custom_value);
+    } else {
+        data->custom_value = 42; /* Default value */
+        pr_info("%s: No custom-value found, using default: %u\n", DRIVER_NAME,
+                data->custom_value);
+    }
+
+    /* Check for presence of a property */
+    data->has_clock = of_property_read_bool(np, "lkmpg,has-clock");
+    pr_info("%s: has-clock property: %s\n", DRIVER_NAME,
+            data->has_clock ? "present" : "absent");
+
+    /* Store device data for later use */
+    platform_set_drvdata(pdev, data);
+
+    pr_info("%s: Device probe successful\n", DRIVER_NAME);
+    return 0;
+}
+
+/* Remove function - called when device is removed */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0)
+static void dt_remove(struct platform_device *pdev)
+{
+    struct dt_device_data *data = platform_get_drvdata(pdev);
+
+    pr_info("%s: Removing device %s\n", DRIVER_NAME, data->label);
+    /* Cleanup is handled automatically by devm_* functions */
+}
+#else
+static int dt_remove(struct platform_device *pdev)
+{
+    struct dt_device_data *data = platform_get_drvdata(pdev);
+
+    pr_info("%s: Removing device %s\n", DRIVER_NAME, data->label);
+    /* Cleanup is handled automatically by devm_* functions */
+    return 0;
+}
+#endif
+
+/* Device tree match table - defines compatible strings this driver supports */
+static const struct of_device_id dt_match_table[] = {
+    {
+        .compatible = "lkmpg,example-device",
+    },
+    {
+        .compatible = "lkmpg,another-device",
+    },
+    {} /* Sentinel */
+};
+MODULE_DEVICE_TABLE(of, dt_match_table);
+
+/* Platform driver structure */
+static struct platform_driver dt_driver = {
+    .probe = dt_probe,
+    .remove = dt_remove,
+    .driver = {
+        .name = DRIVER_NAME,
+        .of_match_table = dt_match_table,
+    },
+};
+
+/* Module initialization */
+static int __init dt_init(void)
+{
+    int ret;
+
+    pr_info("%s: Initializing device tree example module\n", DRIVER_NAME);
+
+    /* Register the platform driver */
+    ret = platform_driver_register(&dt_driver);
+    if (ret) {
+        pr_err("%s: Failed to register platform driver\n", DRIVER_NAME);
+        return ret;
+    }
+
+    pr_info("%s: Module loaded successfully\n", DRIVER_NAME);
+    return 0;
+}
+
+/* Module cleanup */
+static void __exit dt_exit(void)
+{
+    pr_info("%s: Cleaning up device tree example module\n", DRIVER_NAME);
+    platform_driver_unregister(&dt_driver);
+}
+
+module_init(dt_init);
+module_exit(dt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Device tree interaction example for LKMPG");
diff --git a/examples/dt-overlay.dts b/examples/dt-overlay.dts
new file mode 100644
index 00000000..84636c10
--- /dev/null
+++ b/examples/dt-overlay.dts
@@ -0,0 +1,42 @@
+/*
+ * Device Tree Overlay for LKMPG Device Tree Example
+ * 
+ * This overlay can be compiled and loaded on systems that support
+ * runtime device tree overlays (like Raspberry Pi).
+ *
+ * Compile with:
+ *   dtc -@ -I dts -O dtb -o dt-overlay.dtbo dt-overlay.dts
+ *
+ * Load with (on Raspberry Pi):
+ *   sudo dtoverlay dt-overlay.dtbo
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+    compatible = "brcm,bcm2835";
+
+    fragment@0 {
+        target-path = "/";
+        __overlay__ {
+            lkmpg_device@0 {
+                compatible = "lkmpg,example-device";
+                reg = <0x40000000 0x1000>;
+                label = "LKMPG Test Device";
+                lkmpg,custom-value = <100>;
+                lkmpg,has-clock;
+                status = "okay";
+            };
+
+            lkmpg_device@1 {
+                compatible = "lkmpg,another-device";
+                reg = <0x40001000 0x1000>;
+                label = "LKMPG Secondary Device";
+                lkmpg,custom-value = <200>;
+                /* no has-clock property for this one */
+                status = "okay";
+            };
+        };
+    };
+};
diff --git a/lkmpg.tex b/lkmpg.tex
index ceecca91..638bd1de 100644
--- a/lkmpg.tex
+++ b/lkmpg.tex
@@ -2236,6 +2236,97 @@ \section{Standardizing the interfaces: The Device Model}
 
 \samplec{examples/devicemodel.c}
 
+\section{Device Tree}
+\label{sec:device_tree}
+\subsection{Introduction to Device Tree}
+\label{sec:dt_intro}
+Device Tree is a data structure that describes hardware components in a system, particularly in embedded systems and ARM-based platforms.
+Instead of hard-coding hardware details in the kernel source, Device Tree provides a separate, human-readable description that the kernel can parse at boot time.
+This separation allows the same kernel binary to support multiple hardware platforms,
+making development and maintenance significantly easier.
+
+Device Tree files (with \verb|.dts| extension for source files and \verb|.dtb| for compiled binary files) use a hierarchical structure similar to a filesystem to represent the hardware topology.
+Each hardware component is represented as a node with properties that describe its characteristics,
+such as memory addresses, interrupt numbers, and device-specific parameters.
+
+\subsection{Device Tree and Kernel Modules}
+\label{sec:dt_modules}
+While Device Tree is primarily used during kernel initialization, kernel modules can also interact with Device Tree nodes through the platform device framework.
+When the kernel parses the Device Tree at boot, it creates platform devices for nodes that have compatible strings.
+Kernel modules can then register platform drivers that match these compatible strings, allowing them to be automatically probed when the corresponding hardware is detected.
+
+The key concepts for Device Tree interaction in kernel modules include:
+\begin{itemize}
+\item \textbf{Compatible strings}: Unique identifiers that match Device Tree nodes to their drivers
+\item \textbf{Property reading}: Functions to extract configuration data from Device Tree nodes
+\item \textbf{Platform driver framework}: Infrastructure for binding drivers to devices described in Device Tree
+\item \textbf{Device-specific data}: Custom properties that can be defined for specific hardware
+\end{itemize}
+
+\subsection{Example: Device Tree Module}
+\label{sec:dt_example}
+The following example demonstrates how a kernel module can interact with Device Tree nodes.
+This module registers a platform driver that matches specific compatible strings and extracts properties from the matched Device Tree nodes.
+
+\samplec{examples/devicetree.c}
+
+\subsection{Device Tree Source Example}
+\label{sec:dt_source}
+To use the above module, you would need a Device Tree entry like this:
+
+\begin{code}
+/* Example device tree fragment */
+lkmpg_device@0 {
+    compatible = "lkmpg,example-device";
+    reg = <0x40000000 0x1000>;
+    label = "LKMPG Test Device";
+    lkmpg,custom-value = <100>;
+    lkmpg,has-clock;
+};
+\end{code}
+
+The properties in this Device Tree node would be read by the module's probe function when the device is matched.
+The \verb|compatible| property is used to match the device with the driver, while other properties provide device-specific configuration.
+
+\subsection{Testing Device Tree Modules}
+\label{sec:dt_testing}
+Testing Device Tree modules can be done in several ways:
+
+\begin{enumerate}
+\item \textbf{Using Device Tree overlays}: On systems that support it (like Raspberry Pi), you can load Device Tree overlays at runtime to add new devices without rebooting.
+
+\item \textbf{Modifying the main Device Tree}: Add your device nodes to the system's main Device Tree source file and recompile it.
+
+\item \textbf{Using QEMU}: For development and testing, QEMU can emulate systems with custom Device Trees, allowing you to test your modules without physical hardware.
+\end{enumerate}
+
+To check if your device was properly detected, you can examine the sysfs filesystem:
+
+\begin{codebash}
+# List all platform devices
+ls /sys/bus/platform/devices/
+
+# Check device tree nodes
+ls /proc/device-tree/
+\end{codebash}
+
+\subsection{Common Device Tree Functions}
+\label{sec:dt_functions}
+Here are some commonly used Device Tree functions in kernel modules:
+
+\begin{itemize}
+\item \cpp|of_property_read_string()| - Read a string property
+\item \cpp|of_property_read_u32()| - Read a 32-bit integer property
+\item \cpp|of_property_read_bool()| - Check if a boolean property exists
+\item \cpp|of_find_property()| - Find a property by name
+\item \cpp|of_get_property()| - Get a property's raw value
+\item \cpp|of_match_device()| - Match a device against a match table
+\item \cpp|of_parse_phandle()| - Parse a phandle reference to another node
+\end{itemize}
+
+These functions provide a robust interface for extracting configuration data from Device Tree nodes,
+allowing modules to be highly configurable without code changes.
+
 \section{Optimizations}
 \label{sec:optimization}
 \subsection{Likely and Unlikely conditions}
