Skip to content

Day26 - Sensor Core Architecture (Core + Bus Layer)

🎯 Objective

Refactor the existing I2C sensor driver into a bus-agnostic architecture:

  • Separate sensor core logic from bus transport layer
  • Introduce hardware abstraction via ops interface
  • Prepare the design for future SPI support

🧠 Motivation

Before refactor:

  • Driver tightly coupled with I2C (i2c_smbus_*)
  • Difficult to extend to SPI
  • Core logic mixed with transport logic

After refactor:

  • Clean separation of concerns
  • Reusable sensor core
  • Easier to scale and maintain

🏗️ Architecture Overview

        +---------------------------+
        |   User Space (hwmon)      |
        +-------------+-------------+
                      |
                      v
        +---------------------------+
        |     Sensor Core           |
        | (mysensor_core.c)         |
        |                           |
        | - Cache & update policy   |
        | - Polling / IRQ / hybrid  |
        | - Cooldown control        |
        | - Debug counters          |
        +-------------+-------------+
                      |
                      v
        +---------------------------+
        |   Bus Abstraction (ops)   |
        +-------------+-------------+
                      |
        +-------------+-------------+
        |                           |
        v                           v
+---------------+        +----------------+
|  I2C Driver   |        |   SPI Driver   |
| (current)     |        |  (future)      |
+---------------+        +----------------+

🔧 Key Design Concepts

1. Bus Abstraction (bus_ops)

struct mysensor_bus_ops {
    int (*read_reg)(void *bus_ctx, u8 reg, u8 *val);
    int (*write_reg)(void *bus_ctx, u8 reg, u8 val);
};
  • Core never touches I2C/SPI directly
  • All HW access goes through bus_ops
  • Enables transport independence

2. Core Data Structure

struct mysensor_core {
    struct device *dev;

    void *bus_ctx;
    const struct mysensor_bus_ops *bus_ops;

    struct mutex lock;

    bool cache_valid;
    long temp_mc_cached;

    unsigned long last_update;

    unsigned int cache_interval_ms;
    unsigned int min_update_interval_ms;

    /* Counters */
    unsigned int irq_event_count;
    unsigned int poll_event_count;
};

Responsibilities:

  • Store runtime state
  • Maintain cache
  • Track update statistics

3. Hardware Access Layer

mysensor_hw_read_reg()
mysensor_hw_write_reg()
  • Centralized hardware access
  • Prevents direct dependency on transport layer
  • Improves maintainability

4. Update Policy

Three update triggers:

Trigger Description
IRQ Event-driven update
Polling Periodic refresh
On-demand Read-triggered update

5. Cooldown (Min Update Interval)

min_update_interval_ms
  • Prevents excessive hardware access
  • Shared across all update paths
  • Applies to IRQ, Polling, and On-demand

6. Hybrid Mode

When both enabled:

  • IRQ = primary update source
  • Polling = backup refresh

📦 File Structure After Refactor

mysensor.h
mysensor_reg.h
mysensor_core.c
mysensor_i2c.c

mysensor_core.c

  • Core logic
  • hwmon
  • sysfs
  • update policy

mysensor_i2c.c

  • I2C transport
  • probe/remove
  • bus_ops implementation

🚀 Benefits

  • Clear separation of concerns
  • Easier to add SPI support
  • Reusable sensor framework
  • Improved debugging via counters

🔮 Future Extension

Next step (Day27):

  • Add mysensor_spi.c
  • Reuse existing core without modification