3. 配置Sensor分辨率

任务目标

编写驱动函数,将Camera Sensor输出分辨率配置为1080p(1920×1080),并通过读取寄存器回读值验证配置已正确写入。

实现方案

Sensor分辨率由一组寄存器(0x3808~0x380F)控制,分别对应输出宽高的高字节与低字节。配置流程为:通过I2C写入目标分辨率对应的寄存器值,再回读同一组寄存器,比对写入值与回读值是否一致。

关键完整代码

#include <linux/i2c.h>
#include <linux/delay.h>

#define SENSOR_I2C_ADDR  0x36
#define REG_WIDTH_H      0x3808
#define REG_WIDTH_L      0x3809
#define REG_HEIGHT_H     0x380A
#define REG_HEIGHT_L     0x380B
#define REG_CTRL_MODE    0x0100

/* 1080p 分辨率寄存器配置表 */
struct sensor_res_cfg {
    u16 reg;
    u8  val;
};

static const struct sensor_res_cfg res_1080p[] = {
    { REG_WIDTH_H,  0x07 },  /* 1920 >> 8 = 0x07 */
    { REG_WIDTH_L,  0x80 },  /* 1920 & 0xFF = 0x80 */
    { REG_HEIGHT_H, 0x04 },  /* 1080 >> 8 = 0x04 */
    { REG_HEIGHT_L, 0x38 },  /* 1080 & 0xFF = 0x38 */
};

static int sensor_write_reg(struct i2c_client *client, u16 reg, u8 val)
{
    u8 buf[3] = { (reg >> 8) & 0xFF, reg & 0xFF, val };
    return i2c_master_send(client, buf, 3);
}

static int sensor_read_reg(struct i2c_client *client, u16 reg, u8 *val)
{
    u8 addr[2] = { (reg >> 8) & 0xFF, reg & 0xFF };
    int ret = i2c_master_send(client, addr, 2);
    if (ret < 0)
        return ret;
    return i2c_master_recv(client, val, 1);
}

/* 设置Sensor输出分辨率 */
int sensor_set_resolution(struct i2c_client *client, u16 width, u16 height)
{
    u8 w_h = (width >> 8) & 0xFF;
    u8 w_l = width & 0xFF;
    u8 h_h = (height >> 8) & 0xFF;
    u8 h_l = height & 0xFF;
    int ret;

    /* 先停止Sensor输出,避免配置过程中产生异常帧 */
    ret = sensor_write_reg(client, REG_CTRL_MODE, 0x00);
    if (ret < 0)
        return ret;
    msleep(10);

    /* 写入宽高寄存器 */
    ret = sensor_write_reg(client, REG_WIDTH_H, w_h);
    if (ret < 0) return ret;
    ret = sensor_write_reg(client, REG_WIDTH_L, w_l);
    if (ret < 0) return ret;
    ret = sensor_write_reg(client, REG_HEIGHT_H, h_h);
    if (ret < 0) return ret;
    ret = sensor_write_reg(client, REG_HEIGHT_L, h_l);
    if (ret < 0) return ret;

    /* 重新启动Sensor输出 */
    ret = sensor_write_reg(client, REG_CTRL_MODE, 0x01);
    if (ret < 0)
        return ret;
    msleep(20);

    return 0;
}

/* 验证寄存器配置是否生效 */
int sensor_verify_resolution(struct i2c_client *client, u16 width, u16 height)
{
    u8 w_h, w_l, h_h, h_l;
    int ret;

    ret = sensor_read_reg(client, REG_WIDTH_H, &w_h);
    if (ret < 0) return ret;
    ret = sensor_read_reg(client, REG_WIDTH_L, &w_l);
    if (ret < 0) return ret;
    ret = sensor_read_reg(client, REG_HEIGHT_H, &h_h);
    if (ret < 0) return ret;
    ret = sensor_read_reg(client, REG_HEIGHT_L, &h_l);
    if (ret < 0) return ret;

    if (w_h != ((width >> 8) & 0xFF) || w_l != (width & 0xFF) ||
        h_h != ((height >> 8) & 0xFF) || h_l != (height & 0xFF))
        return -EINVAL;

    return 0;
}

/* 调用示例 */
int sensor_config_1080p(struct i2c_client *client)
{
    int ret;

    ret = sensor_set_resolution(client, 1920, 1080);
    if (ret < 0)
        return ret;

    return sensor_verify_resolution(client, 1920, 1080);
}

编译与加载

# 将上述代码编译为内核模块或编入驱动,需包含I2C子系统头文件
# 在驱动probe函数中调用 sensor_config_1080p(client)
# 若返回0,表示配置成功且寄存器回读一致

验证方法

在驱动probe流程中调用sensor_config_1080p(),若函数返回0,说明分辨率寄存器已正确写入且回读值一致。也可在用户空间通过I2C工具直接读取0x3808~0x380F寄存器,预期值应为:

0x3808 = 0x07
0x3809 = 0x80
0x380A = 0x04
0x380B = 0x38

以上为预期输出,由代码逻辑直接推出。实际验证时以I2C总线上的真实回读值为准。