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

\*\*数据包结构:\*\*起始 → 地址帧(7/10 位)→ R/W 位 → ACK/NACK → 数据帧(8 位)→ 停止

**信号规则:**

* 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-8275 | `arch/arm64/boot/dts/qcom/qcs8300.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";
   power-domains = <&rpmhpd SA8295P_CX>;
   dmas = <&gpi_dma3 0 0 QCOM_GPI_I2C>,
          <&gpi_dma3 1 0 QCOM_GPI_I2C>;
   dma-names = "tx", "rx";
   status = "disabled";
};
```

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

## 调试

### 启用调试日志

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

## 故障排除

<AccordionGroup>
  <Accordion title="未检测到 I2C 设备">
    ```bash theme={null}
    cat /proc/device-tree/soc@0/geniqup@*/i2c*/status
    lsmod | grep i2c_qcom_geni
    modprobe i2c_qcom_geni
    cat /sys/kernel/debug/clk/gcc_qupv3_wrap0_s1_clk/clk_enable_count
    ```
  </Accordion>

  <Accordion title="I2C 传输超时">
    \*\*原因:\*\*缺少上拉电阻、从设备无响应、时钟频率错误、总线卡在低电平。

    在 SDA/SCL 上添加 4.7 kΩ 上拉电阻;在设备树中调整 `clock-frequency`。
  </Accordion>

  <Accordion title="无效协议错误">
    **症状:**`geni_i2c a94000.i2c: Invalid proto 1`

    确认 `QUPAC_Access.c` 中设置了 `QUPV3_PROTOCOL_I2C`、`AC_HLOS`、`bAllowFifo=TRUE`、`bLoad=TRUE`。
  </Accordion>

  <Accordion title="DMA 传输失败">
    确认 `CONFIG_QCOM_GPI_DMA=m`;检查设备树中的 `dmas` 和 `dma-names`。

    要在不使用 DMA 的情况下测试:

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

## 快速诊断命令

```bash theme={null}
ls -l /dev/i2c*
i2cdetect -y -r 0
dmesg | grep -i i2c
cat /sys/kernel/debug/clk/clk_summary | grep -i qup
lsmod | grep i2c
```

## 资源

* [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/)
