ov5640_mipi.c中ov5640_init_mode 函数分析

函数首先是获取mipi_csi2_info:

mipi_csi2_info = mipi_csi2_get_info();

这句代码返回mipi_csi2_info,那么这个mipi csi2 information是什么呢?

查看mipi_csi2_get_info()的原函数在Mxc_mipi_csi2.c中

struct mipi_csi2_info *mipi_csi2_get_info(void)

{

return gmipi_csi2;

}

可以看出该函数返回值为gmipi_csi2,那么gmipi_csi2又是什么呢。

gmipi_csi2的定义在Mxc_mipi_csi2.c文件的最前面

static struct mipi_csi2_info *gmipi_csi2;

其中struct mipi_csi2_info的数据结构为:

/* driver private data */

struct mipi_csi2_info {

bool mipi_en;

int ipu_id;

unsigned int csi_id;

unsigned int v_channel;

unsigned int lanes;

unsigned int datatype;

struct clk *dphy_clk;

struct clk *pixel_clk;

unsigned int *mipi_csi2_base;

struct platform_device *pdev;

struct mutex mutex_lock;

};

那么gmipi_csi2是干什么的呢,在Mxc_mipi_csi2.c的mipi_csi2_probe函数中,开辟了gmipi_csi2 的内存空间:

gmipi_csi2 = kmalloc(sizeof(struct mipi_csi2_info), GFP_KERNEL);

然后是配置gmipi_csi2结构体的值:

mutex_init(&gmipi_csi2->mutex_lock);

/* get mipi csi2 informaiton */

gmipi_csi2->pdev = pdev;

gmipi_csi2->mipi_en = false;

gmipi_csi2->ipu_id = plat_data->ipu_id;

gmipi_csi2->csi_id = plat_data->csi_id;

gmipi_csi2->v_channel = plat_data->v_channel;

gmipi_csi2->lanes = plat_data->lanes;

gmipi_csi2->dphy_clk = clk_get(&pdev->dev, plat_data->dphy_clk);

gmipi_csi2->pixel_clk = clk_get(&pdev->dev, plat_data->pixel_clk);

gmipi_csi2->mipi_csi2_base = ioremap(res->start, PAGE_SIZE);

然后通过gmipi_csi2去设置CSI2:

/* mipi dphy clk enable for register access */

clk_enable(gmipi_csi2->dphy_clk);

/* get mipi csi2 dphy version */

mipi_csi2_dphy_ver = mipi_csi2_read(gmipi_csi2, CSI2_VERSION);

clk_disable(gmipi_csi2->dphy_clk);

platform_set_drvdata(pdev, gmipi_csi2);

到这里就可以说明gmipi_csi2是控制CSI2的结构体。驱动中配置CSI2都是通过gmipi_csi2实现的。

下面回到ov5640_init_mode函数:

if (mipi_csi2_info) {

if (!mipi_csi2_get_status(mipi_csi2_info))

mipi_csi2_enable(mipi_csi2_info);

其中mipi_csi2_get_status函数为:

bool mipi_csi2_get_status(struct mipi_csi2_info *info)

{

bool status;

_mipi_csi2_lock(info);

status = info->mipi_en;

_mipi_csi2_unlock(info);

return status;

}

其实就是查看gmipi_csi2结构体中的mipi_en是否为1,为1就说明CSI2已经使能,如果mipi_en为0,就说明CSI2没有使能,就需要通过mipi_csi2_enable函数来进行使能了。

那么mipi_csi2_enable都干了啥工作呢?其实也就是将gmipi_csi2结构体中的mipi_en设置为1.并且使能CSI2的物理时钟gmipi_csi2->dphy_clk。

bool mipi_csi2_enable(struct mipi_csi2_info *info)

{

bool status;

_mipi_csi2_lock(info);

if (!info->mipi_en) {

info->mipi_en = true;

clk_enable(info->dphy_clk);

} else

mipi_dbg("mipi csi2 already enabled!\n");

status = info->mipi_en;

_mipi_csi2_unlock(info);

return status;

}

接下来就是设置MIPI的lane的数量:

if (mipi_csi2_get_status(mipi_csi2_info)) {

mipi_csi2_set_lanes(mipi_csi2_info);

unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info)

{

unsigned int lanes;

_mipi_csi2_lock(info);

mipi_csi2_write(info, info->lanes - 1, CSI2_N_LANES);

lanes = mipi_csi2_read(info, CSI2_N_LANES);

_mipi_csi2_unlock(info);

return lanes;

}

那么这个lane的数量是怎么确定的呢?

该函数中info->lanes也就是gmipi_csi2->lanes即为lane的数量。该数量在mipi_csi2_probe函数中设置:gmipi_csi2->lanes = plat_data->lanes;那么plat_data->lanes是怎么来的呢?该函数在board-mx6q_sabresd.c文件中通过

imx6q_add_mipi_csi2(&mipi_csi2_pdata);进行注册。其中,mipi_csi2_pdata的设置为:

static struct mipi_csi2_platform_data mipi_csi2_pdata = {

.ipu_id = 0,

.csi_id = 1,

.v_channel = 0,

.lanes = 2,

.dphy_clk = "mipi_pllref_clk",

.pixel_clk = "emi_clk",

};

可以看到该MIPI是2lanes的。

再次回到ov5640_init_mode函数。设置完mipi的lane后,就要设置mipi传输的数据类型了:

if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_UYVY)

mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_YUV422);

else if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_RGB565)

mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_RGB565);

else

pr_err("currently this sensor format can not be supported!\n");

其中mipi_csi2_set_datatype函数为:

unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info,

unsigned int datatype)

{

unsigned int dtype;

_mipi_csi2_lock(info);

info->datatype = datatype;

dtype = info->datatype;

_mipi_csi2_unlock(info);

return dtype;

}

其实也就是设置gmipi_csi2->datatype的数据类型。再次看出,驱动中配置mipi其实就是配置结构体gmipi_csi2。

下面就是通过I2C来配置OV5640的寄存器:

dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode;

orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode;

if (mode == ov5640_mode_INIT) {

pModeSetting = ov5640_init_setting_30fps_VGA;

ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);

ov5640_data.pix.width = 640;

ov5640_data.pix.height = 480;

retval = ov5640_download_firmware(pModeSetting, ArySize);

if (retval < 0)

goto err;

pModeSetting = ov5640_setting_30fps_VGA_640_480;

ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480);

retval = ov5640_download_firmware(pModeSetting, ArySize);

} else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||

(dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {

/* change between subsampling and scaling

* go through exposure calucation */

retval = ov5640_change_mode_exposure_calc(frame_rate, mode);

} else {

/* change inside subsampling or scaling

* download firmware directly */

retval = ov5640_change_mode_direct(frame_rate, mode);

}

if (retval < 0)

goto err;

OV5640_set_AE_target(AE_Target);

OV5640_get_light_freq();

OV5640_set_bandingfilter();

ov5640_set_virtual_channel(ov5640_data.csi);

/* add delay to wait for sensor stable */

if (mode == ov5640_mode_QSXGA_2592_1944) {

/* dump the first two frames: 1/7.5*2

* the frame rate of QSXGA is 7.5fps */

msec_wait4stable = 267;

} else if (frame_rate == ov5640_15_fps) {

/* dump the first nine frames: 1/15*9 */

msec_wait4stable = 600;

} else if (frame_rate == ov5640_30_fps) {

/* dump the first nine frames: 1/30*9 */

msec_wait4stable = 300;

}

msleep(msec_wait4stable);

该部分不是此次分析的重点,下回有机会再细说。

接下来就是获取IMX6中MIPI模块的工作状态了:

mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info);

unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info)

{

unsigned int status;

_mipi_csi2_lock(info);

status = mipi_csi2_read(info, CSI2_PHY_STATE);

_mipi_csi2_unlock(info);

return status;

}

该函数会返回mipi dphy的status.

如果mipi模块的状态不是ready状态的话,就会每个10ms询问一次,总共会询问10次。

while ((mipi_reg == 0x200) && (i < 10))

{

mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info);

i++;

msleep(10);

}

if (i >= 10)

{

pr_err("mipi csi2 can not receive sensor clk!\n");

return -1;

}

如果询问10次mipi都不是ready的话,就说明mipi模块可能挂掉了(也许是内核阻塞。。。)此时,就要打印"mipi csi2 can not receive sensor clk!\n"告诉我们CSI2出问题啦,快点过来帮我解决。

接下来就是检查mipi CSI2模块是否出现错误:

mipi_reg = mipi_csi2_get_error1(mipi_csi2_info);

while ((mipi_reg != 0x0) && (i < 10))

{

mipi_reg = mipi_csi2_get_error1(mipi_csi2_info);

i++;

msleep(10);

}

if (i >= 10)

{

pr_err("mipi csi2 can not reveive data correctly!\n");

return -1;

}

其中mipi_csi2_get_error1函数为:

unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info)

{

unsigned int err1;

_mipi_csi2_lock(info);

err1 = mipi_csi2_read(info, CSI2_ERR1);

_mipi_csi2_unlock(info);

return err1;

}

当发现有错误时,再每隔10ms查询1次,看看IMX6芯片自己能解决不。如果再查询10次,仍然发现mipi CSI2模块有错误的话,就说明IMX6芯片不能自己解决该错误。这就很可能是配置的错误了。10次后还是会打印"mipi csi2 can not reveive data correctly!\n"错误来提示我们。

猜你喜欢

转载自blog.csdn.net/u011652362/article/details/81284689