飛思卡爾 imx6 GC0308 攝像頭驅動配置除錯過程

weixin_34088583發表於2017-05-15

GC0308攝像頭驅動程式使用的是linux v4l2協議,通過i2c訊號進行控制。GC0308攝像頭。對上電時序要求非常嚴格,一定要依據datasheet初始化攝像頭。

本驅動使用的3.10核心,所以首先要配置dts,在核心啟動階段支援攝像頭,結合硬體原理圖。首先配置硬體介面屬性:

pinctrl_ipu1_4: ipu1grp-4 { /*++++  GC0308  camera */
            fsl,pins = <
                MX6QDL_PAD_GPIO_3__CCM_CLKO2               0x130b0    /*時鐘*/
                MX6QDL_PAD_CSI0_DAT10__GPIO5_IO28          0x80000000  <span style="font-family: Arial, Helvetica, sans-serif;">/*CAM_nRST_CSI0_DAT10*/</span>
                MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29          0x80000000 /* DAT11 */ <span style="font-family: Arial, Helvetica, sans-serif;">/*CAM_SHDN_CSI0_DAT11*/</span>
                MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12    0x80000000  /*12-19八條資料線*/
                MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13    0x80000000
                MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14    0x80000000
                MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15    0x80000000
                MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16    0x80000000
                MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17    0x80000000
                MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18    0x80000000
                MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19    0x80000000
                MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x80000000  /* 硬體懸空*/
                MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK   0x80000000   /*畫素時鐘*/
                MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC      0x80000000
                MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC     0x80000000
                >;
        };

然後配置攝像頭屬性:

&i2c3{
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c3_1>;
    status = "okay";

    gc0308: gc0308@21{
        compatible = "gc0308-capture";
        reg = <0x21>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ipu1_4>; /* GC0308  camera*/
        clocks = <&clks 201>;
        clock-names = "csi_mclk";
        DOVDD-supply = <&vgen4_reg>; /* 1.8v */
        AVDD-supply = <&vgen3_reg>;  /* 2.8v, on rev C board is VGEN3,
                        on rev B board is VGEN5 */
        DVDD-supply = <&vgen2_reg>;  /* 1.5v*/
        pwn-gpios = <&gpio5 29 1>;   /* active low: SD1_DAT0 */
        rst-gpios = <&gpio5 28 0>;   /* active high: SD1_DAT1 */
        csi_id = <0>;
        mclk = <24000000>;
        mclk_source = <0>;
    };

};

部分核心驅動程式碼分析:

static const struct i2c_device_id gc0308_id[] = {                                                                     
    {"gc0308-capture", 0},                                                                                            
    {},                                                                                                               
};                                                                                                                    
                                                                                                                      
MODULE_DEVICE_TABLE(i2c, gc0308_id);

將gc0308_id增加i2c佇列。當在dts中有對應名字的裝置宣告時,呼叫驅動程式的probe函式。


static struct i2c_driver gc0308_i2c_driver = {
    .driver = {
          .owner = THIS_MODULE,
          .name  = "gc0308-capture",
          },
    .probe  = gc0308_probe,
    .remove = gc0308_remove,
    .id_table = gc0308_id,
};
驅動程式初始化的時候,增加到i2c裝置。


static s32 gc0308_write_reg(u8 reg, u8 val)
{
    u8 au8Buf[3] = {0};

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

  
    if (i2c_master_send(gc0308_data.i2c_client, au8Buf, 2) < 0) {
        pr_err("%s:write reg error:reg=%x,val=%x\n",
            __func__, reg, val);
        return -1;
    }

    return 0;
}

static s32 gc0308_read_reg(u8 reg, u8 *val)
{
    u8 au8RegBuf[2] = {0};
    u8 u8RdVal = 0;

    au8RegBuf[0] = reg;


    if (1 != i2c_master_send(gc0308_data.i2c_client, au8RegBuf, 1)) {
        pr_err("%s:write reg error:reg=%x\n",
                __func__, reg);
        return -1;
    }

    if (1 != i2c_master_recv(gc0308_data.i2c_client, &u8RdVal, 1)) {
        pr_err("%s:read reg error:reg=%x,val=%x\n",
                __func__, reg, u8RdVal);
        return -1;
    }

    return u8RdVal;
}
I2C資料讀寫


static struct v4l2_int_ioctl_desc gc0308_ioctl_desc[] = {
    {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *)ioctl_dev_init},
    {vidioc_int_dev_exit_num, ioctl_dev_exit},
    {vidioc_int_s_power_num, (v4l2_int_ioctl_func *)ioctl_s_power},
    {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *)ioctl_g_ifparm},
    {vidioc_int_init_num, (v4l2_int_ioctl_func *)ioctl_init},
    {vidioc_int_enum_fmt_cap_num,
                (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap},
    {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},
    {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *)ioctl_g_parm},
    {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *)ioctl_s_parm},
    {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *)ioctl_g_ctrl},
    {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *)ioctl_s_ctrl},
    {vidioc_int_enum_framesizes_num,
                (v4l2_int_ioctl_func *)ioctl_enum_framesizes},
    {vidioc_int_g_chip_ident_num,
                (v4l2_int_ioctl_func *)ioctl_g_chip_ident},
};
一系列ioctl函式的指標陣列,供應用程式呼叫。


static int get_device_id(void)
{
    u8 au8RegBuf[2] = {0};
    u8 u8RdVal = 0;
    au8RegBuf[0] = 0x00;

    if (1 != i2c_master_send(gc0308_data.i2c_client, au8RegBuf, 1)) {
        pr_err("%s:write reg error:reg=%x\n",
                __func__, 0xfb);
        return -1;
    }

    if (1 != i2c_master_recv(gc0308_data.i2c_client, &u8RdVal, 1)) {
        pr_err("%s:read reg error:reg=%x,val=%x\n",
                __func__, 0xfb, u8RdVal);
        return -1;
    }

    printk(KERN_INFO "u8RdVal=%x\n\n", u8RdVal);

    return u8RdVal;
}
讀取裝置ID,詳細讀ID的指令,依據datasheet確定。

當ID成功讀到了。接下來。設定多個攝像頭屬性,通常做成一個陣列。此時攝像頭基本能工作了。


當插入驅動模組以後會在/dev/ 資料夾下產生一個videoX 裝置。這時候能夠使用cheese xawtv等程式進行測試。





相關文章