> ## 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

内部集成电路总线（I²C）是一种双向两线串行总线，用于集成电路之间的短距离通信，设备通过分配的总线地址进行通信。

## 概述

### 主要特点

* 双向 2 线串行总线（SDA + SCL）
* 7 位或 10 位目标寻址
* 支持多控制器模式

### 工作模式

| 模式      | 速率              |
| ------- | --------------- |
| 标准模式    | 100 kbps        |
| 快速模式    | 400 kbps        |
| 快速模式增强版 | 1 Mbps（支持的最大速率） |
| 高速模式    | 3.4 MHz（不支持）    |

### 通信时序

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

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

**数据包结构：** Start → 地址帧（7/10 位）→ R/W 位 → ACK/NACK → 数据帧（8 位）→ Stop

**信号规则：**

* SCL 为高电平时：SDA 必须保持稳定
* SCL 为低电平时：SDA 可以变化
* 例外：START 和 STOP 序列可以在 SCL 为高电平时改变 SDA

### 按子系统划分的传输模式

| 子系统                           | 传输模式             | 总线速率                     |
| ----------------------------- | ---------------- | ------------------------ |
| **Linux**                     | FIFO、CPU DMA、GSI | 100 kHz、400 kHz、1000 kHz |
| **Boot**                      | FIFO             | 100 kHz、400 kHz、1000 kHz |
| **aDSP / Qualcomm TEE / SDC** | FIFO             | 标准                       |

## 接口组件

### 设备树源文件

| 平台                 | 设备树文件                                   |
| ------------------ | --------------------------------------- |
| Dragonwing IQ-9075 | `arch/arm64/boot/dts/qcom/sa8775p.dtsi` |

### API

| 子系统          | 头文件                                                   |
| ------------ | ----------------------------------------------------- |
| 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` |

## 软件设备树配置

### Linux 设备树示例

```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 访问控制

确保在 `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 },
```

## 配置步骤

<Steps>
  <Step title="启用内核配置">
    编辑 `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="在设备树中启用 I2C 节点">
    ```diff theme={null}
    +&i2c1 {
    +    status = "okay";
    +};
    ```
  </Step>

  <Step title="编译并烧写">
    编译内核和设备树变更，然后将镜像加载到设备。
  </Step>
</Steps>

## 验证

### 检查设备节点

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

### 使用 i2c-tools

```bash theme={null}
# Install
sudo apt update && sudo apt install i2c-tools

# 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
```

## 调试

### 启用调试日志

```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
```

### 启用 I2C 跟踪

```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
```

### 检查时钟与 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
```

## 故障排查

<AccordionGroup>
  <Accordion title="未检测到 I2C 设备">
    **症状：** `i2cdetect` 未显示任何设备；`/dev/i2c-X` 不存在。

    **检查设备树状态：**

    ```bash theme={null}
    cat /sys/firmware/devicetree/base/soc/i2c@984000/status
    # Should show "okay"
    ```

    **检查内核模块：**

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

    **检查时钟：**

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

    **检查 GPIO pinmux：**

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

  <Accordion title="I2C 传输超时">
    **症状：**

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

    **原因与解决方法：**

    * **缺少上拉电阻** — 在 SDA/SCL 上添加 4.7 kΩ 上拉电阻
    * **从设备无响应** — 确认从设备电源和复位；检查初始化时序
    * **时钟频率错误** — 在设备树中调整 `clock-frequency`
    * **总线卡死在低电平** — 对设备重新上电，或发送时钟脉冲以释放总线
  </Accordion>

  <Accordion title="协议无效错误">
    **症状：**

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

    **步骤：**

    1. 确定板卡类型：`dmesg | grep "CDT Version"`
    2. 在 `QUPAC_Access.xml` 中查找平台 ID
    3. 确认 `QUPAC_Access.c` 中设置了 `QUPV3_PROTOCOL_I2C`、`AC_HLOS`、`bAllowFifo=TRUE`、`bLoad=TRUE`
    4. 如做了修改，重新构建 TEE 固件
  </Accordion>

  <Accordion title="数据损坏">
    **症状：** 读取的数据不正确；间歇性失败。

    **解决方法：**

    * 降低总线速率
    * 缩短线缆长度；添加 22–100 Ω 串联电阻
    * 在设备附近添加去耦电容
    * 使用示波器验证建立时间和保持时间
  </Accordion>

  <Accordion title="DMA 传输失败">
    **症状：**

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

    **解决方法：** 确认 `CONFIG_QCOM_GPI_DMA=m`；检查 DMA 通道分配；确保内存对齐满足 DMA 安全要求。

    在不使用 DMA 的情况下测试：

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

  <Accordion title="时钟拉伸 / 慢速从设备超时">
    ```dts theme={null}
    &i2c1 {
        clock-frequency = <100000>;
        timeout-ms = <1000>;
    };
    ```
  </Accordion>

  <Accordion title="I2C 初期正常但在挂起/恢复后失败">
    检查运行时 PM 配置，验证电源域依赖关系，并添加正确的挂起/恢复处理程序。
  </Accordion>
</AccordionGroup>

## 快速诊断命令

```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
```

## 资源

* [I2C 总线规范](https://www.i2c-bus.org/fileadmin/ftp/i2c_bus_specification_1995.pdf)
* [Linux I2C 子系统](https://www.kernel.org/doc/html/latest/i2c/index.html)
* [设备树绑定](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/)
