Kaynağa Gözat

[documentation][device_driver_model] Add NVMEM framework documentation (EN) - module 5/26

Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com>
copilot-swe-agent[bot] 1 hafta önce
ebeveyn
işleme
30ccfafa37

+ 859 - 0
documentation/6.components/device-driver/device_driver_model/nvmem/README.md

@@ -0,0 +1,859 @@
+# NVMEM (Non-Volatile Memory) Framework
+
+## Overview
+
+### What is NVMEM?
+
+Non-Volatile Memory (NVMEM) refers to computer memory that can retain stored information even when power is removed. Common examples include:
+
+- **EEPROM** (Electrically Erasable Programmable Read-Only Memory)
+- **OTP** (One-Time Programmable memory)
+- **eFuse** (Electronic fuse)
+- **Battery-backed SRAM**
+- **Flash memory regions** (for configuration storage)
+
+NVMEM devices are commonly used to store:
+- Device configuration and calibration data
+- MAC addresses and serial numbers
+- Hardware identifiers and unique IDs
+- Manufacturing test data
+- Secure key storage
+
+### NVMEM Framework in RT-Thread
+
+RT-Thread's NVMEM framework provides a unified abstraction layer for accessing various types of non-volatile memory devices. The framework supports:
+
+- **Unified Access Interface**: Common APIs for reading/writing NVMEM regardless of underlying hardware
+- **Cell-Based Organization**: NVMEM data organized into named cells (regions)
+- **Device Tree Integration**: Hardware description through device tree
+- **Write Protection**: Hardware write-protect pin support
+- **Bit-Level Access**: Support for bit-addressable memory regions
+- **Reference Counting**: Automatic resource management
+
+The framework is located in:
+- Header: `components/drivers/include/drivers/nvmem.h`
+- Implementation: `components/drivers/nvmem/nvmem.c`
+
+## Kconfig Configuration
+
+### Enable NVMEM Framework
+
+```
+RT-Thread Components
+    → Device Drivers
+        → Using Device Driver Model (RT_USING_DM)
+            → Using Open Firmware (OF) API (RT_USING_OFW)
+                → Using Non Volatile Memory (NVMEM) device drivers (RT_USING_NVMEM)
+```
+
+### Configuration Options
+
+#### RT_USING_NVMEM
+
+```kconfig
+menuconfig RT_USING_NVMEM
+    bool "Using Non Volatile Memory (NVMEM) device drivers"
+    depends on RT_USING_DM
+    depends on RT_USING_OFW
+    depends on RT_USING_PIN
+    select RT_USING_ADT
+    select RT_USING_ADT_REF
+    default n
+```
+
+**Dependencies**:
+- `RT_USING_DM`: Device Driver Model must be enabled
+- `RT_USING_OFW`: Open Firmware (Device Tree) support required
+- `RT_USING_PIN`: PIN driver framework for write-protect pins
+
+**Description**: Enables the NVMEM framework providing unified access to non-volatile memory devices like EEPROM, OTP, eFuse, etc.
+
+#### SOC-Specific NVMEM Drivers
+
+```kconfig
+if RT_USING_NVMEM
+    osource "$(SOC_DM_NVMEM_DIR)/Kconfig"
+endif
+```
+
+SoC vendors can provide their specific NVMEM driver configurations through the `SOC_DM_NVMEM_DIR` directory.
+
+## Device Tree Bindings
+
+### NVMEM Provider Node
+
+```dts
+eeprom: eeprom@50 {
+    compatible = "atmel,24c256";
+    reg = <0x50>;
+    
+    #address-cells = <1>;
+    #size-cells = <1>;
+    
+    /* Optional properties */
+    read-only;                  /* Memory is read-only */
+    wp-gpios = <&gpio 10 GPIO_ACTIVE_HIGH>;  /* Write protect pin */
+    
+    /* Define memory cells */
+    mac_address: mac@0 {
+        reg = <0x00 6>;        /* Offset 0x00, 6 bytes */
+    };
+    
+    serial_number: serial@10 {
+        reg = <0x10 16>;       /* Offset 0x10, 16 bytes */
+    };
+    
+    calibration: calib@100 {
+        reg = <0x100 32>;      /* Offset 0x100, 32 bytes */
+        bits = <4 12>;         /* Bit offset 4, 12 bits wide */
+    };
+};
+```
+
+### NVMEM Consumer Node
+
+```dts
+ethernet@40000000 {
+    compatible = "vendor,ethernet";
+    reg = <0x40000000 0x10000>;
+    
+    /* Reference NVMEM cells */
+    nvmem-cells = <&mac_address>;
+    nvmem-cell-names = "mac-address";
+};
+
+device@50000000 {
+    compatible = "vendor,device";
+    reg = <0x50000000 0x1000>;
+    
+    /* Multiple NVMEM references */
+    nvmem-cells = <&serial_number>, <&calibration>;
+    nvmem-cell-names = "serial", "calibration-data";
+};
+```
+
+### Device Tree Properties
+
+#### NVMEM Provider Properties
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `#address-cells` | u32 | Number of cells for cell address (usually 1) |
+| `#size-cells` | u32 | Number of cells for cell size (usually 1) |
+| `read-only` | bool | Memory is read-only, writes not allowed |
+| `wp-gpios` | phandle | GPIO for hardware write protection |
+
+#### NVMEM Cell Properties
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `reg` | u32 array | `<offset size>` - Memory region for this cell |
+| `bits` | u32 array | `<bit_offset nbits>` - Bit-level addressing |
+
+#### NVMEM Consumer Properties
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `nvmem-cells` | phandle | Reference to NVMEM cells |
+| `nvmem-cell-names` | string array | Names for referenced cells |
+
+## Application Layer API
+
+### Data Structures
+
+#### struct rt_nvmem_device
+
+```c
+struct rt_nvmem_device {
+    struct rt_device parent;            /* Parent device */
+    
+    int cells_nr;                       /* Number of cells */
+    rt_list_t cell_nodes;              /* List of cells */
+    
+    /* Read/Write callbacks */
+    rt_ssize_t (*reg_read)(struct rt_nvmem_device *, int offset, 
+                           void *val, rt_size_t bytes);
+    rt_ssize_t (*reg_write)(struct rt_nvmem_device *, int offset, 
+                            void *val, rt_size_t bytes);
+    
+    rt_ssize_t size;                   /* Total size in bytes */
+    int word_size;                     /* Word size (1, 2, 4 bytes) */
+    int stride;                        /* Minimum access stride */
+    
+    rt_bool_t read_only;               /* Read-only flag */
+    rt_bool_t ignore_wp;               /* Ignore WP pin */
+    rt_base_t wp_pin;                  /* Write protect GPIO */
+    rt_uint8_t wp_pin_active;          /* WP active level */
+    
+    struct rt_ref ref;                 /* Reference counter */
+    struct rt_spinlock spinlock;       /* Spinlock for protection */
+    
+    void *priv;                        /* Private data */
+};
+```
+
+#### struct rt_nvmem_cell
+
+```c
+struct rt_nvmem_cell {
+    rt_list_t list;                    /* List node */
+    
+    int index;                         /* Cell index */
+    const char *id;                    /* Cell identifier */
+    const rt_bool_t free_able;         /* Can be freed */
+    
+    rt_uint32_t offset;                /* Offset in bytes */
+    rt_uint32_t bytes;                 /* Size in bytes */
+    rt_uint32_t bit_offset;            /* Bit offset within byte */
+    rt_uint32_t nbits;                 /* Number of bits */
+    
+    struct rt_ref ref;                 /* Reference counter */
+    
+    struct rt_ofw_node *np;            /* Device tree node */
+    struct rt_nvmem_device *nvmem;     /* Parent NVMEM device */
+};
+```
+
+### Consumer APIs
+
+#### Get NVMEM Cell
+
+```c
+struct rt_nvmem_cell *rt_nvmem_get_cell_by_name(struct rt_device *dev, 
+                                                 const char *id);
+struct rt_nvmem_cell *rt_nvmem_get_cell_by_index(struct rt_device *dev, 
+                                                  int index);
+```
+
+**Parameters**:
+- `dev`: Consumer device
+- `id`: Cell name from device tree `nvmem-cell-names`
+- `index`: Cell index (0-based)
+
+**Returns**: Pointer to `rt_nvmem_cell` on success, NULL on failure
+
+**Description**: Obtain a reference to an NVMEM cell for reading/writing. Must be released with `rt_nvmem_put_cell()`.
+
+**Example**:
+```c
+struct rt_nvmem_cell *cell;
+
+/* Get by name */
+cell = rt_nvmem_get_cell_by_name(dev, "mac-address");
+if (!cell) {
+    rt_kprintf("Failed to get MAC address cell\n");
+    return -RT_ERROR;
+}
+
+/* Get by index */
+cell = rt_nvmem_get_cell_by_index(dev, 0);
+```
+
+#### Release NVMEM Cell
+
+```c
+void rt_nvmem_put_cell(struct rt_nvmem_cell *cell);
+```
+
+**Parameters**:
+- `cell`: NVMEM cell to release
+
+**Description**: Release a reference to an NVMEM cell obtained with `rt_nvmem_get_cell_*()`.
+
+#### Read NVMEM Cell
+
+```c
+rt_ssize_t rt_nvmem_cell_read(struct rt_nvmem_cell *cell, 
+                              void *buffer, rt_size_t len);
+```
+
+**Parameters**:
+- `cell`: NVMEM cell to read
+- `buffer`: Buffer to store read data
+- `len`: Number of bytes to read
+
+**Returns**: Number of bytes read on success, negative error code on failure
+
+**Description**: Read data from an NVMEM cell. Supports bit-level access if configured.
+
+#### Write NVMEM Cell
+
+```c
+rt_ssize_t rt_nvmem_cell_write(struct rt_nvmem_cell *cell, 
+                               void *buffer, rt_size_t len);
+```
+
+**Parameters**:
+- `cell`: NVMEM cell to write
+- `buffer`: Data to write
+- `len`: Number of bytes to write
+
+**Returns**: Number of bytes written on success, negative error code on failure
+
+**Description**: Write data to an NVMEM cell. Returns error if memory is read-only.
+
+#### Typed Read Functions
+
+```c
+rt_ssize_t rt_nvmem_cell_read_u8(struct rt_nvmem_cell *cell, 
+                                 rt_uint8_t *out_val);
+rt_ssize_t rt_nvmem_cell_read_u16(struct rt_nvmem_cell *cell, 
+                                  rt_uint16_t *out_val);
+rt_ssize_t rt_nvmem_cell_read_u32(struct rt_nvmem_cell *cell, 
+                                  rt_uint32_t *out_val);
+rt_ssize_t rt_nvmem_cell_read_u64(struct rt_nvmem_cell *cell, 
+                                  rt_uint64_t *out_val);
+```
+
+**Parameters**:
+- `cell`: NVMEM cell to read
+- `out_val`: Pointer to store the value
+
+**Returns**: Number of bytes read on success, negative error code on failure
+
+**Description**: Convenience functions to read specific integer types from NVMEM cells.
+
+### Provider APIs
+
+#### Register NVMEM Device
+
+```c
+rt_err_t rt_nvmem_device_register(struct rt_nvmem_device *ndev);
+```
+
+**Parameters**:
+- `ndev`: NVMEM device to register
+
+**Returns**: `RT_EOK` on success, negative error code on failure
+
+**Description**: Register an NVMEM device with the framework. Initializes reference counting, parses device tree, and configures write-protect pin if present.
+
+#### Unregister NVMEM Device
+
+```c
+rt_err_t rt_nvmem_device_unregister(struct rt_nvmem_device *ndev);
+```
+
+**Parameters**:
+- `ndev`: NVMEM device to unregister
+
+**Returns**: `RT_EOK` on success, `-RT_EBUSY` if device is still in use
+
+**Description**: Unregister an NVMEM device. Fails if there are outstanding references.
+
+#### Append Cell to Device
+
+```c
+rt_err_t rt_nvmem_device_append_cell(struct rt_nvmem_device *ndev, 
+                                     struct rt_nvmem_cell *cell);
+```
+
+**Parameters**:
+- `ndev`: NVMEM device
+- `cell`: Cell to append
+
+**Returns**: `RT_EOK` on success, negative error code on failure
+
+**Description**: Add a cell to an NVMEM device. Used for runtime cell registration.
+
+## Complete Example: Ethernet Driver with MAC Address
+
+### Device Tree
+
+```dts
+/* EEPROM device with MAC address storage */
+i2c0: i2c@40000000 {
+    compatible = "vendor,i2c";
+    reg = <0x40000000 0x1000>;
+    
+    eeprom@50 {
+        compatible = "atmel,24c32";
+        reg = <0x50>;
+        
+        #address-cells = <1>;
+        #size-cells = <1>;
+        
+        /* MAC address cell */
+        eth_mac: mac@0 {
+            reg = <0x00 6>;
+        };
+        
+        /* Device configuration */
+        eth_config: config@10 {
+            reg = <0x10 16>;
+        };
+    };
+};
+
+/* Ethernet controller referencing MAC address */
+ethernet@50000000 {
+    compatible = "vendor,ethernet";
+    reg = <0x50000000 0x10000>;
+    interrupts = <32 IRQ_TYPE_LEVEL_HIGH>;
+    
+    clocks = <&cru CLK_EMAC>;
+    clock-names = "stmmaceth";
+    
+    /* Reference NVMEM for MAC address */
+    nvmem-cells = <&eth_mac>;
+    nvmem-cell-names = "mac-address";
+};
+```
+
+### Ethernet Driver Implementation
+
+```c
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <drivers/nvmem.h>
+
+struct ethernet_device {
+    struct rt_device parent;
+    void *base;
+    int irq;
+    rt_uint8_t mac_addr[6];
+    /* Other fields... */
+};
+
+static rt_err_t ethernet_load_mac_address(struct ethernet_device *eth_dev)
+{
+    struct rt_nvmem_cell *cell;
+    rt_ssize_t ret;
+    
+    /* Get MAC address cell from device tree */
+    cell = rt_nvmem_get_cell_by_name(&eth_dev->parent, "mac-address");
+    if (!cell) {
+        rt_kprintf("[ETH] No MAC address in NVMEM, using default\n");
+        /* Use default or random MAC */
+        eth_dev->mac_addr[0] = 0x00;
+        eth_dev->mac_addr[1] = 0x11;
+        eth_dev->mac_addr[2] = 0x22;
+        eth_dev->mac_addr[3] = 0x33;
+        eth_dev->mac_addr[4] = 0x44;
+        eth_dev->mac_addr[5] = 0x55;
+        return RT_EOK;
+    }
+    
+    /* Read MAC address from NVMEM */
+    ret = rt_nvmem_cell_read(cell, eth_dev->mac_addr, 6);
+    if (ret != 6) {
+        rt_kprintf("[ETH] Failed to read MAC address: %d\n", ret);
+        rt_nvmem_put_cell(cell);
+        return -RT_ERROR;
+    }
+    
+    /* Release cell */
+    rt_nvmem_put_cell(cell);
+    
+    rt_kprintf("[ETH] MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
+               eth_dev->mac_addr[0], eth_dev->mac_addr[1],
+               eth_dev->mac_addr[2], eth_dev->mac_addr[3],
+               eth_dev->mac_addr[4], eth_dev->mac_addr[5]);
+    
+    return RT_EOK;
+}
+
+static rt_err_t ethernet_write_mac_address(struct ethernet_device *eth_dev, 
+                                            const rt_uint8_t *mac)
+{
+    struct rt_nvmem_cell *cell;
+    rt_ssize_t ret;
+    
+    /* Get MAC address cell */
+    cell = rt_nvmem_get_cell_by_name(&eth_dev->parent, "mac-address");
+    if (!cell) {
+        rt_kprintf("[ETH] No MAC address cell available\n");
+        return -RT_ERROR;
+    }
+    
+    /* Write new MAC address */
+    ret = rt_nvmem_cell_write(cell, (void *)mac, 6);
+    if (ret != 6) {
+        rt_kprintf("[ETH] Failed to write MAC address: %d\n", ret);
+        rt_nvmem_put_cell(cell);
+        return -RT_ERROR;
+    }
+    
+    rt_nvmem_put_cell(cell);
+    
+    /* Update local copy */
+    rt_memcpy(eth_dev->mac_addr, mac, 6);
+    
+    rt_kprintf("[ETH] MAC Address updated successfully\n");
+    
+    return RT_EOK;
+}
+
+static rt_err_t ethernet_probe(struct rt_platform_device *pdev)
+{
+    struct ethernet_device *eth_dev;
+    rt_err_t ret;
+    
+    eth_dev = rt_calloc(1, sizeof(*eth_dev));
+    if (!eth_dev) {
+        return -RT_ENOMEM;
+    }
+    
+    /* Initialize device */
+    eth_dev->parent.ofw_node = pdev->parent.ofw_node;
+    
+    /* Get hardware resources */
+    eth_dev->base = rt_dm_dev_get_address(&pdev->parent);
+    if (!eth_dev->base) {
+        rt_free(eth_dev);
+        return -RT_ERROR;
+    }
+    
+    /* Load MAC address from NVMEM */
+    ret = ethernet_load_mac_address(eth_dev);
+    if (ret != RT_EOK) {
+        rt_kprintf("[ETH] Warning: MAC address load failed\n");
+    }
+    
+    /* Configure hardware with MAC address */
+    /* ... hardware initialization ... */
+    
+    rt_kprintf("[ETH] Ethernet initialized\n");
+    
+    return RT_EOK;
+}
+
+static const struct rt_ofw_node_id ethernet_ofw_match[] = {
+    { .compatible = "vendor,ethernet" },
+    { /* sentinel */ }
+};
+
+static struct rt_platform_driver ethernet_driver = {
+    .name = "vendor-ethernet",
+    .ids = ethernet_ofw_match,
+    .probe = ethernet_probe,
+};
+RT_PLATFORM_DRIVER_EXPORT(ethernet_driver);
+```
+
+## NVMEM Provider Driver Example
+
+### I2C EEPROM Driver
+
+```c
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <drivers/nvmem.h>
+#include <drivers/i2c.h>
+
+struct eeprom_device {
+    struct rt_nvmem_device nvmem;
+    struct rt_i2c_bus_device *i2c_bus;
+    rt_uint16_t i2c_addr;
+    rt_size_t size;
+    rt_uint32_t page_size;
+};
+
+static rt_ssize_t eeprom_reg_read(struct rt_nvmem_device *ndev, 
+                                  int offset, void *val, rt_size_t bytes)
+{
+    struct eeprom_device *eeprom;
+    struct rt_i2c_msg msgs[2];
+    rt_uint8_t addr_buf[2];
+    rt_ssize_t ret;
+    
+    eeprom = rt_container_of(ndev, struct eeprom_device, nvmem);
+    
+    /* Check bounds */
+    if (offset + bytes > eeprom->size) {
+        return -RT_EINVAL;
+    }
+    
+    /* Prepare address (big-endian) */
+    addr_buf[0] = (offset >> 8) & 0xFF;
+    addr_buf[1] = offset & 0xFF;
+    
+    /* Write address */
+    msgs[0].addr = eeprom->i2c_addr;
+    msgs[0].flags = RT_I2C_WR;
+    msgs[0].buf = addr_buf;
+    msgs[0].len = 2;
+    
+    /* Read data */
+    msgs[1].addr = eeprom->i2c_addr;
+    msgs[1].flags = RT_I2C_RD;
+    msgs[1].buf = val;
+    msgs[1].len = bytes;
+    
+    ret = rt_i2c_transfer(eeprom->i2c_bus, msgs, 2);
+    if (ret != 2) {
+        return -RT_ERROR;
+    }
+    
+    return bytes;
+}
+
+static rt_ssize_t eeprom_reg_write(struct rt_nvmem_device *ndev, 
+                                   int offset, void *val, rt_size_t bytes)
+{
+    struct eeprom_device *eeprom;
+    struct rt_i2c_msg msg;
+    rt_uint8_t *write_buf;
+    rt_size_t written = 0;
+    rt_ssize_t ret;
+    
+    eeprom = rt_container_of(ndev, struct eeprom_device, nvmem);
+    
+    /* Check bounds */
+    if (offset + bytes > eeprom->size) {
+        return -RT_EINVAL;
+    }
+    
+    write_buf = rt_malloc(eeprom->page_size + 2);
+    if (!write_buf) {
+        return -RT_ENOMEM;
+    }
+    
+    /* Write page by page */
+    while (written < bytes) {
+        rt_uint32_t page_offset = offset % eeprom->page_size;
+        rt_size_t chunk = RT_MIN(bytes - written, 
+                                 eeprom->page_size - page_offset);
+        
+        /* Prepare write buffer: address + data */
+        write_buf[0] = (offset >> 8) & 0xFF;
+        write_buf[1] = offset & 0xFF;
+        rt_memcpy(&write_buf[2], (rt_uint8_t *)val + written, chunk);
+        
+        msg.addr = eeprom->i2c_addr;
+        msg.flags = RT_I2C_WR;
+        msg.buf = write_buf;
+        msg.len = chunk + 2;
+        
+        ret = rt_i2c_transfer(eeprom->i2c_bus, &msg, 1);
+        if (ret != 1) {
+            rt_free(write_buf);
+            return -RT_ERROR;
+        }
+        
+        /* Wait for write cycle to complete (typ. 5ms for EEPROM) */
+        rt_thread_mdelay(5);
+        
+        written += chunk;
+        offset += chunk;
+    }
+    
+    rt_free(write_buf);
+    
+    return written;
+}
+
+static rt_err_t eeprom_probe(struct rt_platform_device *pdev)
+{
+    struct eeprom_device *eeprom;
+    struct rt_device *dev = &pdev->parent;
+    rt_err_t ret;
+    rt_uint32_t size;
+    
+    eeprom = rt_calloc(1, sizeof(*eeprom));
+    if (!eeprom) {
+        return -RT_ENOMEM;
+    }
+    
+    /* Get I2C bus */
+    eeprom->i2c_bus = rt_i2c_bus_device_find(
+        rt_dm_dev_get_name_id(dev, NULL, 0, "i2c-bus"));
+    if (!eeprom->i2c_bus) {
+        rt_kprintf("[EEPROM] I2C bus not found\n");
+        rt_free(eeprom);
+        return -RT_ERROR;
+    }
+    
+    /* Get I2C address */
+    if (rt_dm_dev_prop_read_u32(dev, "reg", &eeprom->i2c_addr) != RT_EOK) {
+        rt_kprintf("[EEPROM] No I2C address specified\n");
+        rt_free(eeprom);
+        return -RT_ERROR;
+    }
+    
+    /* Get EEPROM size (default 4KB for AT24C32) */
+    if (rt_dm_dev_prop_read_u32(dev, "size", &size) != RT_EOK) {
+        size = 4096;  /* Default 4KB */
+    }
+    eeprom->size = size;
+    
+    /* Get page size (default 32 bytes) */
+    if (rt_dm_dev_prop_read_u32(dev, "pagesize", 
+                                &eeprom->page_size) != RT_EOK) {
+        eeprom->page_size = 32;
+    }
+    
+    /* Initialize NVMEM device */
+    eeprom->nvmem.parent.ofw_node = dev->ofw_node;
+    eeprom->nvmem.reg_read = eeprom_reg_read;
+    eeprom->nvmem.reg_write = eeprom_reg_write;
+    eeprom->nvmem.size = eeprom->size;
+    eeprom->nvmem.word_size = 1;
+    eeprom->nvmem.stride = 1;
+    eeprom->nvmem.priv = eeprom;
+    
+    /* Register NVMEM device */
+    ret = rt_nvmem_device_register(&eeprom->nvmem);
+    if (ret != RT_EOK) {
+        rt_kprintf("[EEPROM] Failed to register NVMEM device\n");
+        rt_free(eeprom);
+        return ret;
+    }
+    
+    rt_kprintf("[EEPROM] Registered %d bytes at I2C address 0x%02X\n",
+               eeprom->size, eeprom->i2c_addr);
+    
+    return RT_EOK;
+}
+
+static const struct rt_ofw_node_id eeprom_ofw_match[] = {
+    { .compatible = "atmel,24c32" },
+    { .compatible = "atmel,24c64" },
+    { .compatible = "atmel,24c256" },
+    { /* sentinel */ }
+};
+
+static struct rt_platform_driver eeprom_driver = {
+    .name = "atmel-eeprom",
+    .ids = eeprom_ofw_match,
+    .probe = eeprom_probe,
+};
+RT_PLATFORM_DRIVER_EXPORT(eeprom_driver);
+```
+
+## Best Practices
+
+### For Consumers
+
+1. **Always Check Return Values**
+   ```c
+   cell = rt_nvmem_get_cell_by_name(dev, "calibration");
+   if (!cell) {
+       /* Handle error - use default values */
+   }
+   ```
+
+2. **Release Resources**
+   ```c
+   cell = rt_nvmem_get_cell_by_name(dev, "data");
+   if (cell) {
+       rt_nvmem_cell_read(cell, buffer, size);
+       rt_nvmem_put_cell(cell);  /* Always release */
+   }
+   ```
+
+3. **Handle Read-Only Memory**
+   ```c
+   ret = rt_nvmem_cell_write(cell, data, len);
+   if (ret < 0) {
+       if (ret == -RT_ENOSYS) {
+           rt_kprintf("Memory is read-only\n");
+       }
+   }
+   ```
+
+4. **Use Typed Reads for Simple Values**
+   ```c
+   rt_uint32_t serial_number;
+   
+   cell = rt_nvmem_get_cell_by_name(dev, "serial");
+   if (cell) {
+       rt_nvmem_cell_read_u32(cell, &serial_number);
+       rt_nvmem_put_cell(cell);
+   }
+   ```
+
+### For Providers
+
+1. **Implement Proper Bounds Checking**
+   ```c
+   if (offset + bytes > nvmem->size) {
+       return -RT_EINVAL;
+   }
+   ```
+
+2. **Support Write Protection**
+   ```c
+   /* Framework handles wp-gpios automatically */
+   /* Just don't set ignore_wp flag */
+   nvmem->ignore_wp = RT_FALSE;
+   ```
+
+3. **Handle Page-Based Writes**
+   ```c
+   /* For devices with page write limits */
+   /* Write in page-sized chunks and wait for completion */
+   rt_thread_mdelay(write_cycle_time_ms);
+   ```
+
+4. **Initialize All Fields**
+   ```c
+   nvmem->size = total_size;
+   nvmem->word_size = 1;  /* Byte-addressable */
+   nvmem->stride = 1;     /* Minimum access unit */
+   nvmem->reg_read = my_read;
+   nvmem->reg_write = my_write;
+   ```
+
+## Troubleshooting
+
+### Cell Not Found
+
+**Problem**: `rt_nvmem_get_cell_by_name()` returns NULL
+
+**Solutions**:
+1. Check device tree `nvmem-cells` and `nvmem-cell-names` properties match
+2. Verify NVMEM provider device is probed before consumer
+3. Check `#address-cells` and `#size-cells` in provider node
+
+### Write Fails
+
+**Problem**: `rt_nvmem_cell_write()` returns error
+
+**Solutions**:
+1. Check if memory is marked `read-only` in device tree
+2. Verify write-protect pin is not active
+3. Check provider's `reg_write` callback is implemented
+4. Verify offset and size are within bounds
+
+### Data Corruption
+
+**Problem**: Read data doesn't match written data
+
+**Solutions**:
+1. Check page-write boundaries for page-based devices
+2. Verify write cycle delays are sufficient
+3. Add proper synchronization if accessing from multiple threads
+4. Check bit-offset calculations for bit-addressable cells
+
+## Performance Considerations
+
+### Read Performance
+
+- **Caching**: Cache frequently-read values (e.g., MAC address) after first read
+- **Batch Reads**: Read multiple cells in one operation if possible
+- **Async Access**: Use separate thread for slow NVMEM operations
+
+### Write Performance
+
+- **Write Caching**: Buffer writes and flush periodically
+- **Wear Leveling**: Distribute writes across memory for EEPROMs
+- **Write Coalescing**: Combine multiple small writes into larger operations
+
+### Resource Usage
+
+- **Cell References**: Release cells promptly with `rt_nvmem_put_cell()`
+- **Memory**: Consider memory cost of buffering for page-based devices
+- **I/O**: EEPROM writes can take several milliseconds per page
+
+## Related Modules
+
+- **OFW (Open Firmware)**: Device tree parsing for NVMEM configuration
+- **PIN**: Write-protect GPIO handling
+- **I2C/SPI**: Common buses for NVMEM devices
+
+## References
+
+- NVMEM header: `components/drivers/include/drivers/nvmem.h`
+- NVMEM implementation: `components/drivers/nvmem/nvmem.c`
+- Linux NVMEM framework: Documentation reference for compatible design