RK3588 I2C应用详解

本文详细介绍了RK3588芯片的I2C控制器特性,包括I2C复用机制、电平设置、DTS配置、上拉电阻、i2cdetect工具的使用以及在sensor驱动和应用代码中的应用示例。
摘要由CSDN通过智能技术生成

一.硬件资源
   RK3588 芯片拥有 9 个 通用I2C 控制器,分别复用在几个不同的电源域,用后缀_M0/_M1/_M2/_M3/_M4
区分不同复用位置。_M0/_M1/_M2/_M3/_M4 不能同时使用,分配时只能选择其中一组,例如:不能选择了 I2C1_M0,又选择了 I2C1_M1 或其它 M*。


   i2c的电平通过VCCIOx来设置,比如下图:i2c5和i2c8,电平都是1.8V,因为VCCIO4的电平设置为1.8V。


二.软件配置

1.i2c的dts配置。
下面以i2c3 m0 为例,下面的i2c的dts设置方法。
i2c节点定义,一般在rk3588.dtsi 中定义。文件路径为/nvr/kernel/arch/arm64/boot/dts/rockchip/rk3588.dtsi。
 

i2c3: i2c@feab0000 {
        compatible = "rockchip,rk3588-i2c", "rockchip,rk3399-i2c";
        reg = <0x0 0xfeab0000 0x0 0x1000>;
        clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>;
        clock-names = "i2c", "pclk";
        interrupts = <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2c3m0_xfer>;
        #address-cells = <1>;
        #size-cells = <0>;
        status = "disabled";
    };

i2c的dts引用

&i2c3 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&i2c3m0_xfer>;

    /*i2c设备*/
}  

    对于i2c的dts配置,需要注意i2c信号的复用,是否有别的复用功能在使用,否则会无法编译通过,或者不能正常工作。

2.上拉配置。
  i2c要想正常工作,一定需要配置上拉电阻,可以通过外部配置,或者通过内核来内部配置。
下面是在内核把i2c5设为上拉。文件位置在nvr/u-boot/arch/arm/dts/rk3588s-pinctrl.dtsi
  

  i2c5m0_xfer: i2c5m0-xfer {
            rockchip,pins =
                /* i2c5_scl_m0 */
                <3 RK_PC7 9 &pcfg_pull_up>,
                /* i2c5_sda_m0 */
                <3 RK_PD0 9 &pcfg_pull_up>;
        };

3.i2c常用调试命令
列出所有i2c资源

i2cdetect -l

查询i2c总线上识别的芯片id

i2cdetect -y  x

查询io的复用功能可以通过下面的命令
 

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins

4.i2c在sensor驱动中使用
  i2c 添加完dts之后,就可以在驱动中或者应用代码里进行调用了。下面为使用例子。
  sensor驱动里的调用
  主要是读写函数的实现,下面为实现代码。
 
写函数实现
static int i2c_wr8(struct v4l2_subdev *sd, u8 reg, u8 val)
{
    struct imx415 *imx415 = to_state(sd);
    struct i2c_client *client = imx415->i2c_client;
    struct i2c_msg msgs[1];
    int err;
    u8 buf[2];

    buf[0] = reg;
    buf[1] = val;

    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 2;
    msgs[0].buf = buf;

    err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
    if (err < 0) {

        # if DEBUG_INFO
        v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
                __func__, reg, client->addr);
        #endif  

        return -EIO;
    }

    return 0;

}

读函数实现
static u8 i2c_rd8(struct v4l2_subdev *sd, u8 reg)
{
    struct imx415 *imx415 = to_state(sd);
    struct i2c_client *client = imx415->i2c_client;
    struct i2c_msg msgs[2];
    int err;
    u8 val;

    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
    msgs[0].buf = &reg;

    msgs[1].addr = client->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = 1;
    msgs[1].buf = &val;


    err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
    if (err != ARRAY_SIZE(msgs)) {
         # if DEBUG_INFO
        v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
                __func__, reg, client->addr);
        #endif         
        return 0;
    }

    return val;
}
5.i2c 在应用代码里使用。
  对于有些应用,需要在app里实现i2c功能。因为在应用里实现比较灵活,也方便进行快速的调试测试。
  i2c初始化代码,以i2c5为例。
 
初始化函数
int i2c_fd;
int i2c_init(void)
{
    int ret;
    i2c_fd = open("/dev/i2c-5", O_RDWR);
    if (i2c_fd < 0) {
        printf("Open /dev/i2c-5 error!\n");
        return -1;
    }

    printf("Open /dev/i2c-7 ok!\n");
   printf("i2c_fd =%d\n", i2c_fd);
      ret = ioctl(i2c_fd, I2C_SLAVE_FORCE, LT9211_I2C_ADDR);
       if (ret < 0) {
        printf("I2C_SLAVE_FORCE error!\n");
        return ret;
    }

    return 0;
}


/*i2c读函数
only can read one byte
*/
int read_register(unsigned int reg_addr, uint16_t *val)
{
    int retval;
    unsigned char buf[4];
    static struct i2c_rdwr_ioctl_data rdwr;
    static struct i2c_msg msg[2];

    unsigned int dev_addr = LT9211_I2C_ADDR;

    retval = ioctl(i2c_fd, I2C_SLAVE_FORCE, dev_addr);
    if (retval < 0) {
        printf("addr error!\n");
        return -1;
    }

    msg[0].addr = dev_addr;
    msg[0].flags = 0;
    msg[0].len = 1;
    msg[0].buf = buf;

    msg[1].addr = dev_addr;
    msg[1].flags = 0;
    msg[1].flags |= I2C_M_RD;
    msg[1].len = 1;
    msg[1].buf = buf;

    rdwr.msgs = &msg[0];
    rdwr.nmsgs = (__uint32_t)2;

    buf[0] = reg_addr & 0xff;

    retval = ioctl(i2c_fd, I2C_RDWR, &rdwr);
    if (retval != 2) {
        printf("CMD_I2C_READ error!\n");
        return -1;
    }

    *val = (uint16_t)(buf[0]);
    retval = 0;
//    printf("read addr:0x%02x date:0x%02x\n", reg_addr, buf[0]);

    return retval;
}

/*i2c写函数*/
int write_register(int addr, int data)
{
    int idx = 0;
    int ret;
    char buf[8];

    buf[idx] = addr & 0xff;
    idx++;

    buf[idx] = data & 0xff;
    idx++;

    printf("write addr:0x%02x date:0x%02x\n", addr, data);
    ret = write(i2c_fd, buf, 2);
    if (ret < 0) {
        printf("I2C_WRITE error!\n");
        return -1;
    }

    return 0;
}

static uint8_t i2c_rd8(uint8_t reg)
{
    uint16_t val;
    read_register(reg, &val);
    return val & 0xff;
}

static int i2c_wr8(uint8_t reg, uint8_t val)
{
    return write_register(reg, val);
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霸气小路飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值