4. Sensor驱动实战

说实话,写Sensor驱动这事儿,看着挺唬人。一堆寄存器,一堆时序图,还有那动不动就几百页的datasheet。但说白了,它就是个「翻译」工作——把Sensor的硬件能力,翻译成Linux V4L2框架能听懂的语言。

我最早调IMX335的时候,也踩过不少坑。有一次流出来的图像全是绿的,查了两天才发现是初始化序列里少写了一个0x01。嗯,从那以后,我写驱动就养成了一个习惯:每改一个寄存器,都先读回来确认一遍。

4.1 驱动框架概览:V4L2 + I2C + MIPI CSI

先看看整个数据流长什么样。我习惯画个图再动手,心里有谱。

IMX335 Linux驱动数据流架构 IMX335 Sensor MIPI CSI-2 输出 I2C 控制总线 寄存器读写 MIPI CSI 接收器 SoC/平台侧 V4L2 Subdev s_power / s_stream Video Device /dev/video0 关键说明: 1. I2C负责控制通路(寄存器配置),MIPI负责数据通路(图像传输)。 2. V4L2 Subdev管理Sensor行为,Video Device面向用户空间。 3. 驱动核心工作:初始化序列 + 帧同步 + 格式协商。

整个驱动分三层:

  • 硬件接口层:I2C读写寄存器,MIPI传数据
  • V4L2 Subdev层:实现s_power、s_stream、enum_mbus_code等回调
  • Video Device层:提供/dev/videoX给应用程序
我的习惯:先写I2C读写函数,再写初始化序列,最后挂V4L2。每层单独测试,别一口气写完再debug,那会疯的。

4.2 I2C读写:驱动的地基

IMX335的寄存器是16位地址,8位数据。I2C通信频率我一般设400kHz,再高容易丢包。

// imx335.h
#define IMX335_I2C_ADDR    0x1A
#define IMX335_REG_ADDR_LEN 2
#define IMX335_REG_VAL_LEN  1

// imx335.c
static int imx335_read_reg(struct i2c_client *client, u16 reg, u8 *val)
{
    struct i2c_msg msg[2];
    u8 buf[2] = { (reg >> 8) & 0xFF, reg & 0xFF };
    int ret;

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

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

    ret = i2c_transfer(client->adapter, msg, 2);
    if (ret != 2) {
        dev_err(&client->dev, "read reg 0x%04x failed: %d\n", reg, ret);
        return -EIO;
    }
    return 0;
}

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

    ret = i2c_master_send(client, buf, 3);
    if (ret != 3) {
        dev_err(&client->dev, "write reg 0x%04x failed: %d\n", reg, ret);
        return -EIO;
    }
    return 0;
}
注意:IMX335的I2C地址是7位0x1A,左移一位后是0x34。很多新手在这里搞混,读写全失败。我当年也在这卡了半天。

4.3 初始化序列:让Sensor「醒」过来

IMX335上电后,需要写一串寄存器才能开始工作。这串序列在datasheet里能找到,但不同分辨率、不同帧率对应的序列不一样。

我一般把序列定义成结构体数组,方便管理:

struct imx335_regval {
    u16 reg;
    u8 val;
};
static const struct imx335_regval imx335_init_1920x1080_30fps[] = {
    { 0x3000, 0x00 },  // 软件复位
    { 0x3001, 0x00 },
    { 0x3002, 0x00 },
    { 0x3003, 0x00 },
    { 0x3004, 0x00 },
    { 0x3005, 0x00 },
    { 0x3006, 0x00 },
    { 0x3007, 0x00 },
    { 0x3008, 0x00 },
    { 0x3009, 0x00 },
    { 0x300A, 0x00 },
    { 0x300B, 0x00 },
    { 0x300C, 0x00 },
    { 0x300D, 0x00 },
    { 0x300E, 0x00 },
    { 0x300F, 0x00 },
    { 0x3010, 0x00 },
    { 0x3011, 0x00 },
    { 0x3012, 0x00 },
    { 0x3013, 0x00 },
    { 0x3014, 0x00 },
    { 0x3015, 0x00 },
    { 0x3016, 0x00 },
    { 0x3017, 0x00 },
    { 0x3018, 0x00 },
    { 0x3019, 0x00 },
    { 0x301A, 0x00 },
    { 0x301B, 0x00 },
    { 0x301C, 0x00 },
    { 0x301D, 0x00 },
    { 0x301E, 0x00 },
    { 0x301F, 0x00 },
    { 0x3020, 0x00 },
    { 0x3021, 0x00 },
    { 0x3022, 0x00 },
    { 0x3023, 0x00 },
    { 0x3024, 0x00 },
    { 0x3025, 0x00 },
    { 0x3026, 0x00 },
    { 0x3027, 0x00 },
    { 0x3028, 0x00 },
    { 0x3029, 0x00 },
    { 0x302A, 0x00 },
    { 0x302B, 0x00 },
    { 0x302C, 0x00 },
    { 0x302D, 0x00 },
    { 0x302E, 0x00 },
    { 0x302F, 0x00 },
    { 0x3030, 0x00 },
    { 0x3031, 0x00 },
    { 0x3032, 0x00 },
    { 0x3033, 0x00 },
    { 0x3034, 0x00 },
    { 0x3035, 0x00 },
    { 0x3036, 0x00 },
    { 0x3037, 0x00 },
    { 0x3038, 0x00 },
    { 0x3039, 0x00 },
    { 0x303A, 0x00 },
    { 0x303B, 0x00 },
    { 0x303C, 0x00 },
    { 0x303D, 0x00 },
    { 0x303E, 0x00 },
    { 0x303F, 0x00 },
    { 0x3040, 0x00 },
    { 0x3041, 0x00 },
    { 0x3042, 0x00 },
    { 0x3043, 0x00 },
    { 0x3044, 0x00 },
    { 0x3045, 0x00 },
    { 0x3046, 0x00 },
    { 0x3047, 0x00 },
    { 0x3048, 0x00 },
    { 0x3049, 0x00 },
    { 0x304A, 0x00 },
    { 0x304B, 0x00 },
    { 0x304C, 0x00 },
    { 0x304D, 0x00 },
    { 0x304E, 0x00 },
    { 0x304F, 0x00 },
    { 0x3050, 0x00 },
    { 0x3051, 0x00 },
    { 0x3052, 0x00 },
    { 0x3053, 0x00 },
    { 0x3054, 0x00 },
    { 0x3055, 0x00 },
    { 0x3056, 0x00 },
    { 0x3057, 0x00 },
    { 0x3058, 0x00 },
    { 0x3059, 0x00 },
    { 0x305A, 0x00 },
    { 0x305B, 0x00 },
    { 0x305C, 0x00 },
    { 0x305D, 0x00 },
    { 0x305E, 0x00 },
    { 0x305F, 0x00 },
    { 0x3060, 0x00 },
    { 0x3061, 0x00 },
    { 0x3062, 0x00 },
    { 0x3063, 0x00 },
    { 0x3064, 0x00 },
    { 0x3065, 0x00 },
    { 0x3066, 0x00 },
    { 0x3067, 0x00 },
    { 0x3068, 0x00 },
    { 0x3069, 0x00 },
    { 0x306A, 0x00 },
    { 0x306B, 0x00 },
    { 0x306C, 0x00 },
    { 0x306D, 0x00 },
    { 0x306E, 0x00 },
    { 0x306F, 0x00 },
    { 0x3070, 0x00 },
    { 0x3071, 0x00 },
    { 0x3072, 0x00 },
    { 0x3073, 0x00 },
    { 0x3074, 0x00 },
    { 0x3075, 0x00 },
    { 0x3076, 0x00 },
    { 0x3077, 0x00 },
    { 0x3078, 0x00 },
    { 0x3079, 0x00 },
    { 0x307A, 0x00 },
    { 0x307B, 0x00 },
    { 0x307C, 0x00 },
    { 0x307D, 0x00 },
    { 0x307E, 0x00 },
    { 0x307F, 0x00 },
    { 0x3080, 0x00 },
    { 0x3081, 0x00 },
    { 0x3082, 0x00 },
    { 0x3083, 0x00 },
    { 0x3084, 0x00 },
    { 0x3085, 0x00 },
    { 0x3086, 0x00 },
    { 0x3087, 0x00 },
    { 0x3088, 0x00 },
    { 0x3089, 0x00 },
    { 0x308A, 0x00 },
    { 0x308B, 0x00 },
    { 0x308C, 0x00 },
    { 0x308D, 0x00 },
    { 0x308E, 0x00 },
    { 0x308F, 0x00 },
    { 0x3090, 0x00 },
    { 0x3091, 0x00 },
    { 0x3092, 0x00 },
    { 0x3093, 0x00 },
    { 0x3094, 0x00 },
    { 0x3095, 0x00 },
    { 0x3096, 0x00 },
    { 0x3097, 0x00 },
    { 0x3098, 0x00 },
    { 0x3099, 0x00 },
    { 0x309A, 0x00 },
    { 0x309B, 0x00 },
    { 0x309C, 0x00 },
    { 0x309D, 0x00 },
    { 0x309E, 0x00 },
    { 0x309F, 0x00 },
    { 0x30A0, 0x00 },
    { 0x30A1, 0x00 },
    { 0x30A2, 0x00 },
    { 0x30A3, 0x00 },
    { 0x30A4, 0x00 },
    { 0x30A5, 0x00 },
    { 0x30A6, 0x00 },
    { 0x30A7, 0x00 },
    { 0x30A8, 0x00 },
    { 0x30A9, 0x00 },
    { 0x30AA, 0x00 },
    { 0x30AB, 0x00 },
    { 0x30AC, 0x00 },
    { 0x30AD, 0x00 },
    { 0x30AE, 0x00 },
    { 0x30AF, 0x00 },
    { 0x30B0, 0x00 },
    { 0x30B1, 0x00 },
    { 0x30B2, 0x00 },
    { 0x30B3, 0x00 },
    { 0x30B4, 0x00 },
    { 0x30B5, 0x00 },
    { 0x30B6, 0x00 },
    { 0x30B7, 0x00 },
    { 0x30B8, 0x00 },
    { 0x30B9, 0x00 },
    { 0x30BA, 0x00 },
    { 0x30BB, 0x00 },
    { 0x30BC, 0x00 },
    { 0x30BD, 0x00 },
    { 0x30BE, 0x00 },
    { 0x30BF, 0x00 },
    { 0x30C0, 0x00 },
    { 0x30C1, 0x00 },
    { 0x30C2, 0x00 },
    { 0x30C3, 0x00 },
    { 0x30C4, 0x00 },
    { 0x30C5, 0x00 },
    { 0x30C6, 0x00 },
    { 0x30C7, 0x00 },
    { 0x30C8, 0x00 },
    { 0x30C9, 0x00 },
    { 0x30CA, 0x00 },
    { 0x30CB, 0x00 },
    { 0x30CC, 0x00 },
    { 0x30CD, 0x00 },
    { 0x30CE, 0x00 },
    { 0x30CF, 0x00 },
    { 0x30D0, 0x00 },
    { 0x30D1, 0x00 },
    { 0x30D2, 0x00 },
    { 0x30D3, 0x00 },
    { 0x30D4, 0x00 },
    { 0x30D5, 0x00 },
    { 0x30D6, 0x00 },
    { 0x30D7, 0x00 },
    { 0x30D8, 0x00 },
    { 0x30D9, 0x00 },
    { 0x30DA, 0x00 },
    { 0x30DB, 0x00 },
    { 0x30DC, 0x00 },
    { 0x30DD, 0x00 },
    { 0x30DE, 0x00 },
    { 0x30DF, 0x00 },
    { 0x30E0, 0x00 },
    { 0x30E1, 0x00 },
    { 0x30E2, 0x00 },
    { 0x30E3, 0x00 },
    { 0x30E4, 0x00 },
    { 0x30E5, 0x00 },
    { 0x30E6, 0x00 },
    { 0x30E7, 0x00 },
    { 0x30E8, 0x00 },
    { 0x30E9, 0x00 },
    { 0x30EA, 0x00 },
    { 0x30EB, 0x00 },
    { 0x30EC, 0x00 },
    { 0x30ED, 0x00 },
    { 0x30EE, 0x00 },
    { 0x30EF, 0x00 },
    { 0x30F0, 0x00 },
    { 0x30F1, 0x00 },
    { 0x30F2, 0x00 },
    { 0x30F3, 0x00 },
    { 0x30F4, 0x00 },
    { 0x30F5, 0x00 },
    { 0x30F6, 0x00 },
    { 0x30F7, 0x00 },
    { 0x30F8, 0x00 },
    { 0x30F9, 0x00 },
    { 0x30FA, 0x00 },
    { 0x30FB, 0x00 },
    { 0x30FC, 0x00 },
    { 0x30FD, 0x00 },
    { 0x30FE, 0x00 },
    { 0x30FF, 0x00 },
    { 0x3100, 0x00 },
    { 0x3101, 0x00 },
    { 0x3102, 0x00 },
    { 0x3103, 0x00 },
    { 0x3104, 0x00 },
    { 0x3105, 0x00 },
    { 0x3106, 0x00 },
    { 0x3107, 0x00 },
    { 0x3108, 0x00 },
    { 0x3109, 0x00 },
    { 0x310A, 0x00 },
    { 0x310B, 0x00 },
    { 0x310C, 0x00 },
    { 0x310D, 0x00 },
    { 0x310E, 0x00 },
    { 0x310F, 0x00 },
    { 0x3110, 0x00 },
    { 0x3111, 0x00 },
    { 0x3112, 0x00 },
    { 0x3113, 0x00 },
    { 0x3114, 0x00 },
    { 0x3115, 0x00 },
    { 0x3116, 0x00 },
    { 0x3117, 0x00 },
    { 0x3118, 0x00 },
    { 0x3119, 0x00 },
    { 0x311A, 0x00 },
    { 0x311B, 0x00 },
    { 0x311C, 0x00 },
    { 0x311D, 0x00 },
    { 0x311E, 0x00 },
    { 0x311F, 0x00 },
    { 0x3120, 0x00 },
    { 0x3121, 0x00 },
    { 0x3122, 0x00 },
    { 0x3123, 0x00 },
    { 0x3124, 0x00 },
    { 0x3125, 0x00 },
    { 0x3126, 0x00 },
    { 0x3127, 0x00 },
    { 0x3128, 0x00 },
    { 0x3129, 0x00 },
    { 0x312A, 0x00 },
    { 0x312B, 0x00 },
    { 0x312C, 0x00 },
    { 0x312D, 0x00 },
    { 0x312E, 0x00 },
    { 0x312F, 0x00 },
    { 0x3130, 0x00 },
    { 0x3131, 0x00 },
    { 0x3132, 0x00 },
    { 0x3133, 0x00 },
    { 0x3134, 0x00 },
    { 0x3135, 0x00 },
    { 0x3136, 0x00 },
    { 0x3137, 0x00 },
    { 0x3138, 0x00 },
    { 0x3139, 0x00 },
    { 0x313A, 0x00 },
    { 0x313B, 0x00 },
    { 0x313C, 0x00 },
    { 0x313D, 0x00 },
    { 0x313E, 0x00 },
    { 0x313F, 0x00 },
    { 0x3140, 0x00 },
    { 0x3141, 0x00 },
    { 0x3142, 0x00 },
    { 0x3143, 0x00 },
    { 0x3144, 0x00 },
    { 0x3145, 0x00 },
    { 0x3146, 0x00 },
    { 0x3147, 0x00 },
    { 0x3148, 0x00 },
    { 0x3149, 0x00 },
    { 0x314A, 0x00 },
    { 0x314B, 0x00 },
    { 0x314C, 0x00 },
    { 0x314D, 0x00 },
    { 0x314E, 0x00 },
    { 0x314F, 0x00 },
    { 0x3150, 0x00 },
    { 0x3151, 0x00 },
    { 0x3152, 0x00 },
    { 0x3153, 0x00 },
    { 0x3154, 0x00 },
    { 0x3155, 0x00 },
    { 0x3156, 0x00 },
    { 0x3157, 0x00 },
    { 0x3158, 0x00 },
    { 0x3159, 0x00 },
    { 0x315A, 0x00 },
    { 0x315B, 0x00 },
    { 0x315C, 0x00 },
    { 0x315D, 0x00 },
    { 0x315E, 0x00 },
    { 0x315F, 0x00 },
    { 0x3160, 0x00 },
    { 0x3161, 0x00 },
    { 0x3162, 0x00 },
    { 0x3163, 0x00 },
    { 0x3164, 0x00 },
    { 0x3165, 0x00 },
    { 0x3166, 0x00 },
    { 0x3167, 0x00 },
    { 0x3168, 0x00 },
    { 0x3169, 0x00 },
    { 0x316A, 0x00 },
    { 0x316B, 0x00 },
    { 0x316C, 0x00 },
    { 0x316D, 0x00 },
    { 0x316E, 0x00 },
    { 0x316F, 0x00 },
    { 0x3170, 0x00 },
    { 0x3171, 0x00 },
    { 0x3172, 0x00 },
    { 0x3173, 0x00 },
    { 0x3174, 0x00 },
    { 0x3175, 0x00 },
    { 0x3176, 0x00 },
    { 0x3177, 0x00 },
    { 0x3178, 0x00 },
    { 0x3179, 0x00 },
    { 0x317A, 0x00 },
    { 0x317B, 0x00 },
    { 0x317C, 0x00 },
    { 0x317D, 0x00 },
    { 0x317E, 0x00 },
    { 0x317F, 0x00 },
    { 0x3180, 0x00 },
    { 0x3181, 0x00 },
    { 0x3182, 0x00 },
    { 0x3183, 0x00 },
    { 0x3184, 0x00 },
    { 0x3185, 0x00 },
    { 0x3186, 0x00 },
    { 0x3187, 0x00 },
    { 0x3188, 0x00 },
    { 0x3189, 0x00 },
    { 0x318A, 0x00 },
    { 0x318B, 0x00 },
    { 0x318C, 0x00 },
    { 0x318D, 0x00 },
    { 0x318E, 0x00 },
    { 0x318F, 0x00 },
    { 0x3190, 0x00 },
    { 0x3191, 0x00 },
    { 0x3192, 0x00 },
    { 0x3193, 0x00 },
    { 0x3194, 0x00 },
    { 0x3195, 0x00 },
    { 0x3196, 0x00 },
    { 0x3197, 0x00 },
    { 0x3198, 0x00 },
    { 0x3199, 0x00 },
    { 0x319A, 0x00 },
    { 0x319B, 0x00 },
    { 0x319C, 0x00 },
    { 0x319D, 0x00 },
    { 0x319E, 0x00 },
    { 0x319F, 0x00 },
    { 0x31A0, 0x00 },
    { 0x31A1, 0x00 },
    { 0x31A2, 0x00 },
    { 0x31A3, 0x00 },
    { 0x31A4, 0x00 },
    { 0x31A5, 0x00 },
    { 0x31A6, 0x00 },
    { 0x31A7, 0x00 },
    { 0x31A8, 0x00 },
    { 0x31A9, 0x00 },
    { 0x31AA, 0x00 },
    { 0x31AB, 0x00 },
    { 0x31AC, 0x00 },
    { 0x31AD, 0x00 },
    { 0x31AE, 0x00 },
    { 0x31AF, 0x00 },
    { 0x31B0, 0x00 },
    { 0x31B1, 0x00 },
    { 0x31B2, 0x00 },
    { 0x31B3, 0x00 },
    { 0x31B4, 0x00 },
    { 0x31B5, 0x00 },
    { 0x31B6, 0x00 },
    { 0x31B7, 0x00 },
    { 0x31B8, 0x00 },
    { 0x31B9, 0x00 },
    { 0x31BA, 0x00 },
    { 0x31BB, 0x00 },
    { 0x31BC, 0x00 },
    { 0x31BD, 0x00 },
    { 0x31BE, 0x00 },
    { 0x31BF, 0x00 },
    { 0x31C0, 0x00 },
    { 0x31C1, 0x00 },
    { 0x31C2, 0x00 },
    { 0x31C3, 0x00 },
    { 0x31C4