I2C SMBus Functions Linux Driver- Free Linux Device Drivers Course

I2C SMBus Functions Linux Driver

Free Linux Device Drivers Course — I2C Client Drivers, Part 4

Kernel 6.x Ready
Original Driver Code
Free Embedded Linux Course
i2c smbus functions linux kernel
free linux device drivers course
free linux kernel development course
free embedded systems course
free embedded linux course

If you have been following this free linux device drivers course, you already know how to talk to an I2C device using raw i2c_msg structures with i2c_transfer(). In this lecture we look at a friendlier, higher-level way to do the same job: the i2c smbus functions linux kernel API. These helper functions hide the message-building work and are the recommended choice for the majority of sensor, EEPROM, RTC, and GPIO expander drivers you will write in real embedded Linux projects.

What You Will Learn

  • What SMBus is and how it differs from plain I2C
  • Why the kernel prefers SMBus calls when a device supports them
  • The full i2c_smbus_* function family with parameters and return values
  • How the kernel falls back to i2c_transfer() when the adapter has no native SMBus support
  • How to write and test an original SMBus-based sensor driver on kernel 6.x

Prerequisites

  • Part 1 – I2C bus fundamentals and driver registration
  • Part 2 – probe/remove and module_i2c_driver()
  • Part 3 – i2c_transfer() and struct i2c_msg
  • A Linux machine with kernel headers installed, or a Raspberry Pi / BeagleBone with an I2C sensor

SMBus vs I2C: What Is the Difference?

System Management Bus (SMBus) is a two-wire protocol that Intel derived from I2C for monitoring power supplies, batteries, and system health on PC motherboards. It reuses the same SDA/SCL electrical signalling as I2C but adds stricter rules on timing, packet length, and transaction format.

SMBus and I2C Compatibility
Property I2C SMBus
Clock speed Up to 5 MHz (Ultra Fast mode) 10 kHz – 100 kHz
Clock stretching Allowed, no timeout Bus timeout defined (~35 ms)
Transaction format Free-form, driver defined Fixed protocols (byte, word, block)
Compatibility Not guaranteed to run on SMBus hardware Every SMBus device works on an I2C bus

Because every SMBus device is also a valid I2C device (but not the other way around), the Linux kernel documentation recommends using the SMBus call if you are unsure which category your chip falls into. Most modern sensors, EEPROMs, and PMICs implement one of the standard SMBus protocols, so the i2c_smbus_* API covers the majority of real-world drivers.

The i2c_smbus_* Function Family

These functions are declared in include/linux/i2c.h and implemented in drivers/i2c/i2c-core-smbus.c on modern kernels. They all take a struct i2c_client * so the kernel already knows the target address, and they return a negative errno on failure.

s32 i2c_smbus_read_byte(struct i2c_client *client);
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value);

s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(struct i2c_client *client,
                               u8 command, u8 value);

s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command);
s32 i2c_smbus_write_word_data(struct i2c_client *client,
                               u8 command, u16 value);

s32 i2c_smbus_read_block_data(struct i2c_client *client,
                               u8 command, u8 *values);
s32 i2c_smbus_write_block_data(struct i2c_client *client,
                                u8 command, u8 length,
                                const u8 *values);
Choosing the Right SMBus Call
Function Typical use case
read/write_byte Devices with no internal register map
read/write_byte_data One register, one byte – most common case (config, status registers)
read/write_word_data 16-bit registers such as ADC or temperature results
read/write_block_data Variable-length data such as EEPROM pages or firmware blobs

The command parameter you see in every call is simply the register address inside the device — the same byte you would normally send as the first byte of an I2C write before reading or writing the actual data.

How the Kernel Executes an SMBus Call

Not every I2C controller understands SMBus transactions natively. On kernel 6.x, when you call an i2c_smbus_* function, the I2C core checks the adapter’s algo->smbus_xfer callback:

SMBus Call Resolution Path
1. Driver calls i2c_smbus_read_byte_data()
2. I2C core checks if the adapter supports native SMBus (algo->smbus_xfer)
3a. Native support present → adapter driver handles the transaction directly
3b. No native support → core builds equivalent i2c_msg array and calls i2c_transfer()
4. Result (data or negative errno) returned to your driver

This is exactly why client drivers should almost always prefer the SMBus API over hand-built i2c_msg arrays: your driver stays portable across every I2C adapter on the system, whether or not that adapter has SMBus acceleration in hardware.

Hands-On: An Original SMBus Sensor Driver

Let us build ep_smbus_sensor, a small driver that reads a one-byte configuration register and a two-byte temperature register from an imaginary sensor at I2C address 0x48, using only SMBus calls.

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/kernel.h>

#define EP_REG_CONFIG   0x01
#define EP_REG_TEMP     0x02

struct ep_smbus_dev {
    struct i2c_client *client;
};

static int ep_smbus_read_temp(struct ep_smbus_dev *dev)
{
    s32 raw;

    raw = i2c_smbus_read_word_data(dev->client, EP_REG_TEMP);
    if (raw < 0) {
        dev_err(&dev->client->dev,
                "failed to read temperature: %d\n", raw);
        return raw;
    }

    dev_info(&dev->client->dev, "raw temperature word = 0x%04x\n", raw);
    return 0;
}

static int ep_smbus_probe(struct i2c_client *client)
{
    struct ep_smbus_dev *dev;
    s32 cfg;
    int ret;

    dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;

    dev->client = client;
    i2c_set_clientdata(client, dev);

    /* Put the sensor into normal operating mode */
    ret = i2c_smbus_write_byte_data(client, EP_REG_CONFIG, 0x00);
    if (ret < 0)
        return ret;

    cfg = i2c_smbus_read_byte_data(client, EP_REG_CONFIG);
    if (cfg < 0)
        return cfg;

    dev_info(&client->dev, "config register readback = 0x%02x\n", cfg);

    return ep_smbus_read_temp(dev);
}

static const struct i2c_device_id ep_smbus_id[] = {
    { "ep_smbus_sensor", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, ep_smbus_id);

static struct i2c_driver ep_smbus_driver = {
    .driver = {
        .name = "ep_smbus_sensor",
    },
    .probe = ep_smbus_probe,
    .id_table = ep_smbus_id,
};
module_i2c_driver(ep_smbus_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Original SMBus example driver for the free linux kernel development course");

Notice that the driver never touches struct i2c_msg at all — every register access goes through i2c_smbus_write_byte_data() or i2c_smbus_read_word_data(), and the I2C core takes care of building the correct bus transaction underneath.

Building and Testing on Real Hardware

Compile it as a normal out-of-tree module against your running kernel headers:

obj-m += ep_smbus_sensor.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
$ make
$ sudo insmod ep_smbus_sensor.ko
$ dmesg | tail -5

Expected output on a board that actually has a matching sensor at address 0x48:

[  912.104521] ep_smbus_sensor 1-0048: config register readback = 0x00
[  912.104688] ep_smbus_sensor 1-0048: raw temperature word = 0x0164

If no device answers at that address, i2c_smbus_write_byte_data() returns -EREMOTEIO or -ENXIO and the probe exits cleanly with that error logged — a good sign that your error handling path is working as expected.

Common Mistakes to Avoid

  • Forgetting to check the return value — every i2c_smbus_* call can fail on a busy or disconnected bus.
  • Using read_byte_data on a 16-bit register and only getting half the value.
  • Assuming block reads are always available — some adapters restrict block transfer length; check i2c_check_functionality() with I2C_FUNC_SMBUS_BLOCK_DATA if your driver depends on it.
  • Mixing raw i2c_transfer() calls and SMBus calls in the same driver without a clear reason — pick one style per device unless the datasheet requires both.

Debugging SMBus Transactions From User Space

Before you even load a kernel driver, it helps to confirm the device answers correctly using the i2c-tools package. These user-space utilities call the exact same SMBus protocols your driver will use, which makes them a fast way to sanity check wiring and register addresses.

$ sudo apt install i2c-tools
$ i2cdetect -y 1
$ i2cget -y 1 0x48 0x02 w
$ i2cset -y 1 0x48 0x01 0x00 b

i2cdetect scans the bus and prints a grid of responding addresses, i2cget performs a single SMBus read (the trailing w means word data, matching i2c_smbus_read_word_data()), and i2cset performs a byte-data write, matching i2c_smbus_write_byte_data(). If these commands succeed but your kernel driver does not, the problem is almost always in the driver’s probe logic rather than the wiring.

Suggested Images for This Post

  • A labelled photo of an I2C temperature sensor breakout board wired to a Raspberry Pi via SDA/SCL
  • A terminal screenshot showing i2cdetect -y 1 output with the sensor address visible
  • A close-up of an oscilloscope capture showing an SMBus byte-data transaction

Frequently Asked Questions

Is every I2C device also an SMBus device?

No. SMBus devices are a stricter subset, so they always work over I2C, but not every I2C device follows SMBus timing and packet rules. When you are unsure, try the SMBus calls first since that is what the kernel documentation recommends.

What happens if my I2C adapter does not support SMBus in hardware?

The I2C core automatically translates your SMBus call into an equivalent i2c_transfer() call using i2c_msg structures, so your driver code does not need to change.

Which function should I use for a 16-bit sensor register?

i2c_smbus_read_word_data() and i2c_smbus_write_word_data() are built for exactly this case and handle the register address plus two data bytes in one call.

Can I use SMBus block functions for reading an EEPROM?

Yes, i2c_smbus_read_block_data() and i2c_smbus_write_block_data() are commonly used for EEPROM pages, though many EEPROM drivers also use plain i2c_transfer() because of stricter length or addressing needs.

Do these functions work the same way on every kernel version?

The core API has been stable for a long time, which makes this part of the free linux kernel development course directly usable on both older LTS kernels and the latest 6.x releases.

Continue the Free Linux Device Drivers Course

Next we bring device tree into the picture and see how I2C client devices are declared and matched on modern embedded Linux boards.

Leave a Reply

Your email address will not be published. Required fields are marked *