> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# I2C

Inter-Integrated Circuit (I²C) is a bidirectional, two-wire serial bus for short-distance communication between integrated circuits, where devices communicate using assigned bus addresses.

## Overview

### Key Characteristics

* Bidirectional 2-wire serial bus (SDA + SCL)
* 7-bit or 10-bit target addressing
* Multi-controller mode support

### Operating Modes

| Mode            | Speed                      |
| --------------- | -------------------------- |
| Standard mode   | 100 kbps                   |
| Fast mode       | 400 kbps                   |
| Fast mode plus  | 1 Mbps (maximum supported) |
| High-speed mode | 3.4 MHz (not supported)    |

### Communication Sequence

<img src="https://mintcdn.com/qualcomm-prod/Bh7DlgudKfjY_3Wf/Linux/images/peripheral-interfaces/i2c_communication_sequence.png?fit=max&auto=format&n=Bh7DlgudKfjY_3Wf&q=85&s=5000635a0034efc2245dd6150b0e2708" width="1091" height="299" data-path="Linux/images/peripheral-interfaces/i2c_communication_sequence.png" />

<img src="https://mintcdn.com/qualcomm-prod/Bh7DlgudKfjY_3Wf/Linux/images/peripheral-interfaces/i2c_data_packet_format.png?fit=max&auto=format&n=Bh7DlgudKfjY_3Wf&q=85&s=1b75cb917455b3ef2cbcb36676ebdfde" width="1107" height="394" data-path="Linux/images/peripheral-interfaces/i2c_data_packet_format.png" />

**Packet structure:** Start → Address frame (7/10-bit) → R/W bit → ACK/NACK → Data frames (8-bit) → Stop

**Signal rules:**

* SCL HIGH: SDA must remain stable
* SCL LOW: SDA may change
* Exception: START and STOP sequences may change SDA when SCL is HIGH

### Transfer Modes by Subsystem

| Subsystem                     | Transfer Mode      | Bus Speeds                 |
| ----------------------------- | ------------------ | -------------------------- |
| **Linux**                     | FIFO, CPU DMA, GSI | 100 kHz, 400 kHz, 1000 kHz |
| **Boot**                      | FIFO               | 100 kHz, 400 kHz, 1000 kHz |
| **aDSP / Qualcomm TEE / SDC** | FIFO               | Standard                   |

## Interface Components

### Device Tree Sources

| Platform           | Device Tree File                       |
| ------------------ | -------------------------------------- |
| Dragonwing IQ-9075 | `arch/arm64/boot/dts/qcom/lemans.dtsi` |

### APIs

| Subsystem    | Header                                                |
| ------------ | ----------------------------------------------------- |
| Linux        | `include/linux/i2c.h`, `include/linux/i2c-dev.h`      |
| Boot         | `boot_images/boot/QcomPkg/Include/i2c_api.h`          |
| aDSP         | `adsp_proc/core/api/buses/i2c_api.h`                  |
| Qualcomm TEE | `trustzone_images/core/buses/api/i2c/qupv3/i2c_api.h` |

## Software Device Tree Configuration

### Linux Device Tree Example

```dts theme={null}
i2c21: i2c@b80000 {
   compatible = "qcom,geni-i2c";
   reg = <0x0 0xb80000 0x0 0x4000>;
   #address-cells = <1>;
   #size-cells = <0>;
   interrupts = <GIC_SPI 831 IRQ_TYPE_LEVEL_HIGH>;
   clocks = <&gcc GCC_QUPV3_WRAP3_S0_CLK>;
   clock-names = "se";
   pinctrl-0 = <&qup_i2c21_default>;
   pinctrl-names = "default";
   interconnects = <&clk_virt MASTER_QUP_CORE_3 QCOM_ICC_TAG_ALWAYS
         &clk_virt SLAVE_QUP_CORE_3 QCOM_ICC_TAG_ALWAYS>,
         <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
         &config_noc SLAVE_QUP_3 QCOM_ICC_TAG_ALWAYS>,
         <&aggre1_noc MASTER_QUP_3 QCOM_ICC_TAG_ALWAYS
         &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
   interconnect-names = "qup-core", "qup-config", "qup-memory";
   power-domains = <&rpmhpd SA8775P_CX>;
   dmas = <&gpi_dma3 0 0 QCOM_GPI_I2C>,
          <&gpi_dma3 1 0 QCOM_GPI_I2C>;
   dma-names = "tx", "rx";
   status = "disabled";
};
```

GPIO pinctrl:

```dts theme={null}
qup_i2c21_default: qup-i2c21-state {
   pins = "gpio13", "gpio14";
   function = "qup3_se0";
};
```

### QUPAC Access Control

Ensure the correct protocol is set in `QUPAC_Access.c`:

```c theme={null}
{ QUPV3_0_SE0, QUPV3_PROTOCOL_I2C, QUPV3_MODE_FIFO, AC_HLOS, TRUE, TRUE, FALSE },
{ QUPV3_1_SE5, QUPV3_PROTOCOL_I2C, QUPV3_MODE_GSI,  AC_HLOS, FALSE, TRUE, FALSE },
```

## Configuration Steps

<Steps>
  <Step title="Enable kernel configurations">
    Edit `kernel_platform/kernel/arch/arm64/configs/qcom_defconfig`:

    ```
    CONFIG_QCOM_GENI_SE=y
    CONFIG_I2C_QCOM_GENI=m
    CONFIG_I2C_CHARDEV=m
    CONFIG_QCOM_GPI_DMA=m
    ```
  </Step>

  <Step title="Enable I2C node in device tree">
    ```diff theme={null}
    +&i2c1 {
    +    status = "okay";
    +};
    ```
  </Step>

  <Step title="Compile and flash">
    Compile the kernel and device tree changes, then load images to the device.
  </Step>
</Steps>

## Verification

### Check Device Nodes

```bash theme={null}
ls /dev/i2c*
# Expected: /dev/i2c-0  /dev/i2c-1  /dev/i2c-16
```

### Use i2c-tools

```bash theme={null}
# push tools using SCP or similar tools.
scp i2cdetect root@<IP address>:/usr

#Assign permission to execute
chmod 777 i2cdetect

# Scan bus
i2cdetect -y -r 0

# Dump device registers
i2cdump -r 0-0xff 0 0x2b b

# Read register
i2cget -y 0 0x2b 0x04

# Write register
i2cset -y 0 0x2b 0x04 0xFF
```

## Debugging

### Enable Debug Logs

```bash theme={null}
mount -t debugfs none /sys/kernel/debug

echo -n "file i2c-qcom-geni.c +p" > /sys/kernel/debug/dynamic_debug/control
echo -n "file i2c-core-base.c +p" > /sys/kernel/debug/dynamic_debug/control
echo -n "file gpi.c +p" > /sys/kernel/debug/dynamic_debug/control

dmesg | grep i2c
```

### Enable I2C Tracing

```bash theme={null}
echo 1 > /sys/kernel/debug/tracing/events/i2c/enable
cat /sys/kernel/debug/tracing/trace
echo 0 > /sys/kernel/debug/tracing/events/i2c/enable
```

### Check Clock and GPIO

```bash theme={null}
# Clock status
cat /sys/kernel/debug/clk/clk_summary | grep -i qup

# GPIO pinmux
cat /sys/kernel/debug/pinctrl/*/pinmux-pins | grep -i i2c
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="I2C Device Not Detected">
    **Symptoms:** `i2cdetect` shows no devices; `/dev/i2c-X` not present.

    **Check device tree status:**

    ```bash theme={null}
    cat /proc/device-tree/soc@0/geniqup@*/i2c*/status
    # Should show "okay"
    ```

    **Check kernel module:**

    ```bash theme={null}
    lsmod | grep i2c_qcom_geni
    modprobe i2c_qcom_geni  # Load if missing
    ```

    **Check clock:**

    ```bash theme={null}
    cat /sys/kernel/debug/clk/gcc_qupv3_wrap0_s1_clk/clk_enable_count
    ```

    **Check GPIO pinmux:**

    ```bash theme={null}
    cat /sys/kernel/debug/pinctrl/*/pinmux-pins | grep -i i2c
    ```
  </Accordion>

  <Accordion title="I2C Transfer Timeout">
    **Symptoms:**

    ```
    i2c_qcom_geni 984000.i2c: i2c error :-110
    i2c_qcom_geni 984000.i2c: timeout: CMD:0x08000000
    ```

    **Causes and fixes:**

    * **No pull-up resistors** — Add 4.7 kΩ pull-ups on SDA/SCL
    * **Slave not responding** — Verify slave power and reset; check initialization sequence
    * **Wrong clock frequency** — Adjust `clock-frequency` in device tree
    * **Bus stuck low** — Power cycle devices or send clock pulses to release bus
  </Accordion>

  <Accordion title="Invalid Protocol Error">
    **Symptoms:**

    ```
    geni_i2c a94000.i2c: Invalid proto 1
    ```

    **Steps:**

    1. Identify board type: `dmesg | grep "CDT Version"`
    2. Locate platform ID in `QUPAC_Access.xml`
    3. Verify `QUPAC_Access.c` sets `QUPV3_PROTOCOL_I2C`, `AC_HLOS`, `bAllowFifo=TRUE`, `bLoad=TRUE`
    4. Rebuild TEE firmware if changes were made
  </Accordion>

  <Accordion title="Data Corruption">
    **Symptoms:** Incorrect data read; intermittent failures.

    **Fixes:**

    * Reduce bus speed
    * Shorten wire length; add 22–100 Ω series resistors
    * Add decoupling capacitors near devices
    * Verify setup and hold times with oscilloscope
  </Accordion>

  <Accordion title="DMA Transfer Failures">
    **Symptoms:**

    ```
    qcom-gpi-dma a00000.dma-controller: gpi_process_xfer_compl_event: error:0x4
    ```

    **Fixes:** Verify `CONFIG_QCOM_GPI_DMA=m`; check DMA channel assignment; ensure DMA-safe memory alignment.

    To test without DMA:

    ```dts theme={null}
    &i2c1 {
        /delete-property/ dmas;
        /delete-property/ dma-names;
    };
    ```
  </Accordion>

  <Accordion title="Clock Stretching / Slow Slave Timeouts">
    ```dts theme={null}
    &i2c1 {
        clock-frequency = <100000>;
        timeout-ms = <1000>;
    };
    ```
  </Accordion>

  <Accordion title="I2C Works Initially but Fails After Suspend/Resume">
    Check runtime PM configuration, verify power domain dependencies, and add proper suspend/resume handlers.
  </Accordion>
</AccordionGroup>

## Quick Diagnostic Commands

```bash theme={null}
ls -l /dev/i2c*                                          # List I2C devices
i2cdetect -y -r 0                                        # Scan bus 0
i2cget -y 0 0x2b 0x04                                    # Read register
dmesg | grep -i i2c                                      # Kernel logs
cat /sys/kernel/debug/clk/clk_summary | grep -i qup     # Clock status
cat /sys/kernel/debug/gpio                               # GPIO config
lsmod | grep i2c                                         # Module status
ls -l /sys/firmware/devicetree/base/soc/i2c*            # Device tree nodes
```

## Resources

* [I2C Bus Specification](https://www.i2c-bus.org/fileadmin/ftp/i2c_bus_specification_1995.pdf)
* [Linux I2C Subsystem](https://www.kernel.org/doc/html/latest/i2c/index.html)
* [Device Tree Bindings](https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/i2c/qcom%2Ci2c-geni-qcom.yaml)
* [i2c-tools](https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/)
