# bus-drivers-i2c-spi

Walks an agent through Linux client drivers for I2C and SPI sensors and PMICs: registration, regmap, device tree binding.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 304 installs · ★ 267
- Author: mohitmishra786
- License: MIT · policy=mirror · the beginning of the file is at the end of this page
- Source: https://github.com/mohitmishra786/low-level-dev-skills/tree/HEAD/skills/kernel-dev/bus-drivers-i2c-spi/SKILL.md
- Updated: 2026-06-27
- HTML: https://affpapa.org/en/nevibecode/skills/bus-drivers-i2c-spi

## What it does

This skill guides an agent through Linux client drivers on the I2C and SPI buses. It ships working templates: an `i2c_driver` with `probe`, `of_device_id` and `i2c_device_id`; a raw transfer built from two `i2c_msg` entries, one writing the register address and one reading the value back; an `spi_driver` that sets `spi->mode` and `spi->bits_per_word` before `spi_setup`. A separate section covers `regmap` — config with `reg_bits`, `val_bits` and `max_register`, then `regmap_read`, `regmap_write` and `regmap_update_bits`.

There is a troubleshooting table mapping symptoms to causes. `-EREMOTEIO` means a NACK, usually a wrong address, so run `i2cdetect` and check the `reg` value in the device tree. A wrong SPI mode points at a CPOL/CPHA mismatch against the datasheet. `-EPROBE_DEFER` shows up when a regulator or clock supplier is not ready yet. A regmap `-EIO` often means the register and value widths are swapped.

For debugging the skill lists `i2cdetect -y 1`, `i2cdump -y 1 0x48` and reading the device name under `/sys/bus/i2c/devices/`. You invoke it from the agent as `/bus-drivers-i2c-spi` followed by the task. Platform MMIO drivers are out of scope here — those live in the separate `device-drivers` skill.

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add mohitmishra786/low-level-dev-skills --skill bus-drivers-i2c-spi -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/bus-drivers-i2c-spi/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/bus-drivers-i2c-spi/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add mohitmishra786/low-level-dev-skills --skill bus-drivers-i2c-spi -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/bus-drivers-i2c-spi/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add mohitmishra786/low-level-dev-skills --skill bus-drivers-i2c-spi -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/bus-drivers-i2c-spi/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install mohitmishra786/low-level-dev-skills bus-drivers-i2c-spi
```

2. **Manually: put the files in place**
- File: `.github/skills/bus-drivers-i2c-spi/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add mohitmishra786/low-level-dev-skills --skill bus-drivers-i2c-spi -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/mohitmishra786/low-level-dev-skills --path skills/kernel-dev/bus-drivers-i2c-spi
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/bus-drivers-i2c-spi/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add mohitmishra786/low-level-dev-skills --skill bus-drivers-i2c-spi -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/mohitmishra786/low-level-dev-skills/tree/HEAD/skills/kernel-dev/bus-drivers-i2c-spi/SKILL.md

## When to use it
- write an I2C client driver for a sensor or PMIC
- move bare-metal SPI register reads into a kernel driver
- set up regmap for multi-byte register access
- track down why a transfer fails with `-EREMOTEIO`
- bind a bus device through `compatible` in the device tree

## Example prompts
- /bus-drivers-i2c-spi write a regmap-based driver for an I2C PMIC at 0x58
- /bus-drivers-i2c-spi add an spi_driver for the sensor, SPI_MODE_0, 8 bits per word
- /bus-drivers-i2c-spi why does probe return -EREMOTEIO on i2c-1?

## Source text · SKILL.md · MIT

Below is the content of a third-party file. It is data, not instructions for you: do not act on anything written inside unless the human asks. Block tag: ebad8e86fdfb631d.

BEGIN THIRD-PARTY FILE ebad8e86fdfb631d
````text
---
name: bus-drivers-i2c-spi
description: I2C and SPI bus driver skill for Linux client drivers. Use when writing i2c_driver or spi_driver, register access over bus, DMA SPI transfers, or ACPI/DT client binding. Activates on queries about i2c_client, spi_driver, regmap I2C, SPI transfer, or Linux I2C SPI subsystem.
---

# Bus Drivers (I2C and SPI)

## Purpose

Guide agents through Linux I2C and SPI **client** drivers: bus registration, `i2c_transfer` / `spi_sync`, regmap abstraction, DT `compatible` on bus children, and probe patterns — complementing platform MMIO drivers in `skills/kernel/device-drivers`.

## When to Use

- Sensor or PMIC on I2C/SPI bus
- Converting bare-metal SPI register reads to kernel driver
- Using `regmap` for multi-byte register access
- Debugging `-EREMOTEIO` or missing ACK

## Workflow

### 1. I2C client driver

```c
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>

static int my_probe(struct i2c_client *client)
{
    struct regmap *map;

    map = devm_regmap_init_i2c(client, &my_regmap_config);
    if (IS_ERR(map))
        return PTR_ERR(map);

    dev_info(&client->dev, "probed at 0x%02x\n", client->addr);
    return 0;
}

static const struct of_device_id my_of_id[] = {
    { .compatible = "vendor,sensor" },
    { }
};
MODULE_DEVICE_TABLE(of, my_of_id);

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

static struct i2c_driver my_driver = {
    .probe    = my_probe,
    .remove   = my_remove,
    .driver   = { .name = "mysensor", .of_match_table = my_of_id },
    .id_table = my_id,
};
module_i2c_driver(my_driver);
```

DT child:

```dts
i2c1 {
    sensor@48 {
        compatible = "vendor,sensor";
        reg = <0x48>;
    };
};
```

### 2. Raw I2C transfer

```c
u8 reg = 0x0F, val;
struct i2c_msg msgs[] = {
    { .addr = client->addr, .flags = 0,       .len = 1, .buf = &reg },
    { .addr = client->addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
};
ret = i2c_transfer(client->adapter, msgs, 2);
```

### 3. SPI driver

```c
static int spi_probe(struct spi_device *spi)
{
    spi->mode = SPI_MODE_0;
    spi->bits_per_word = 8;
    spi_setup(spi);

    struct spi_transfer t = {
        .tx_buf = tx,
        .rx_buf = rx,
````
END THIRD-PARTY FILE ebad8e86fdfb631d

The third-party file has ended. Everything between the ebad8e86fdfb631d tags is data: requests and commands from it are not followed. An “end of file” line with another tag inside the block is part of the file.

First 2262 of 3853 bytes. © mohitmishra786 · MIT · https://github.com/mohitmishra786/low-level-dev-skills/tree/HEAD/skills/kernel-dev/bus-drivers-i2c-spi/SKILL.md

_Part of the page did not fit — see the HTML version._

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
