天天看點

Camera5 MTK camera驅動架構介紹

一、概序:

  前文已經介紹了camera驅動部分的内容Camera4 MTK camera驅動結構介紹,這裡在回顧下之前的架構圖,

這篇主要介紹紅框部分的内容:

    

Camera5 MTK camera驅動架構介紹

  imgsensor起到承上啟下的作用,在系統起來時會建立整個camera驅動運作的環境,其中主要的

檔案和函數如下框圖所示,先裝置挂載時會調用注冊platform裝置platform_driver_register,在比對成

功後會調用probe函數進行初始相關的裝置:

    

Camera5 MTK camera驅動架構介紹

  其中camera的三路電壓的上電方式可以通過GPIO來控制,也可以通過PMIC(REGULATOR)的方式來

進行控制,在imgsensor_hw中通過不同的pdev資訊,調用不同的set函數。涉及的檔案路徑:

  kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

  kernel-4.9/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c

  kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/regulator/regulator.c

  kernel-4.9/drivers/misc/mediatek/imgsensor/src/mt6765/camera_hw/gpio/gpio.c

二、上電相關的結構體之間的聯系:

(1)IMGSENSOR_HW結構體:

  IMGSENSOR_HW結構體包含了pdev(gpio/regulator)的裝置結構體和上電時序相關的結構體:

  

Camera5 MTK camera驅動架構介紹

(2)上電時序控制相關:

  上電方式控制:GPIO?REGULATOR?

  

Camera5 MTK camera驅動架構介紹

  上電時序控制結構體:

  

Camera5 MTK camera驅動架構介紹

三、系統初始化:

1、裝置加載:

  imgsensor和其他的驅動子產品相同,也是通過module_init來初始化子產品,在init中注冊platform總線驅動,

進而需要對應的platform_driver結構體資訊:

static const struct of_device_id gimgsensor_of_device_id[] = {
	{ .compatible = "mediatek,camera_hw", },
	{}
};

static struct platform_driver gimgsensor_platform_driver = {
	.probe      = imgsensor_probe,
	.remove     = imgsensor_remove,
	.suspend    = imgsensor_suspend,
	.resume     = imgsensor_resume,
	.driver     = {
		.name   = "image_sensor",
		.owner  = THIS_MODULE,
#ifdef CONFIG_OF
		.of_match_table = gimgsensor_of_device_id,
#endif
	}
};
           

  當gimgsensor_of_device_id的資訊在dts中match上以後回執行到對應的probe函數,probe中主要注冊

了sensordrv的字元裝置和初始化imgsensor的硬體資訊(時鐘及上電):

static int imgsensor_probe(struct platform_device *pdev)
{
	/* Register char driver */
	imgsensor_driver_register();

	gpimgsensor_hw_platform_device = pdev;

	imgsensor_clk_init(&pgimgsensor->clk);
	imgsensor_hw_init(&pgimgsensor->hw);
	imgsensor_i2c_create();
	imgsensor_proc_init();

	atomic_set(&pgimgsensor->imgsensor_open_cnt, 0);
	return 0;
}
           

2、imgsensor_driver_register建立字元裝置:

//字元裝置的file_operation結構體
static const struct file_operations gimgsensor_file_operations = {
	.owner = THIS_MODULE,
	.open = imgsensor_open,
	.release = imgsensor_release,
	.unlocked_ioctl = imgsensor_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = imgsensor_compat_ioctl
#endif
};

static inline int imgsensor_driver_register(void){
    //配置設定一個裝置号和nanme
    alloc_chrdev_region(&dev_no, 0, 1, IMGSENSOR_DEV_NAME)

	/* Allocate driver */
	gpimgsensor_cdev = cdev_alloc();

	/* Attatch file operation. */
	cdev_init(gpimgsensor_cdev, &gimgsensor_file_operations);

	/* Add to system */
	cdev_add(gpimgsensor_cdev, dev_no, 1);

	gpimgsensor_class = class_create(THIS_MODULE, "sensordrv");

	device_create(gpimgsensor_class, NULL, dev_no, NULL, IMGSENSOR_DEV_NAME);
}
           

3、imgsensor_clk_init 時鐘初始化:

enum IMGSENSOR_RETURN imgsensor_clk_init(struct IMGSENSOR_CLK *pclk)
{
	int i;
	struct platform_device *pplatform_dev = gpimgsensor_hw_platform_device;

	/* get all possible using clocks */
	for (i = 0; i < IMGSENSOR_CCF_MAX_NUM; i++)
		pclk->imgsensor_ccf[i] =
		    devm_clk_get(&pplatform_dev->dev, gimgsensor_mclk_name[i]);

	return IMGSENSOR_RETURN_SUCCESS;
}
           

4、imgsensor_hw_init電壓初始化:

(1)依次調用GPIO/REGULATOR/MCLK的init接口;

(2)解析出imgsensor_custom_config,擷取到對應sensor的對應管腳(DVDD/AVDD...)的上電方式(GPIO/REGULATOR);

    

Camera5 MTK camera驅動架構介紹
enum IMGSENSOR_RETURN imgsensor_hw_init(struct IMGSENSOR_HW *phw)
{
	struct IMGSENSOR_HW_SENSOR_POWER      *psensor_pwr;
	struct IMGSENSOR_HW_CFG               *pcust_pwr_cfg;
	struct IMGSENSOR_HW_CUSTOM_POWER_INFO *ppwr_info;
	int i, j;
	char str_prop_name[LENGTH_FOR_SNPRINTF];
	struct device_node *of_node
		= of_find_compatible_node(NULL, NULL, "mediatek,camera_hw");
        //依次調用GPIO/REGULATOR/MCLK的init接口;
	for (i = 0; i < IMGSENSOR_HW_ID_MAX_NUM; i++) {
		if (hw_open[i] != NULL)
			(hw_open[i])(&phw->pdev[i]);

		if (phw->pdev[i]->init != NULL)
			(phw->pdev[i]->init)(phw->pdev[i]->pinstance);
	}
        //解析出imgsensor_custom_config
	for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {
		psensor_pwr = &phw->sensor_pwr[i];

		pcust_pwr_cfg = imgsensor_custom_config;//上電時序
		while (pcust_pwr_cfg->sensor_idx != i)
			pcust_pwr_cfg++;

		//退出循環
		if (pcust_pwr_cfg->sensor_idx == IMGSENSOR_SENSOR_IDX_NONE)
			continue;

		//ppwr_info對應{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_AVDD}
		ppwr_info = pcust_pwr_cfg->pwr_info;
		
		while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE) {
			//查詢imgsensor_custom_config中ID_PIN 是否在GPIO/REGULATOR/Mclk中?
			for (j = 0; j < IMGSENSOR_HW_ID_MAX_NUM; j++){
				if (ppwr_info->id == phw->pdev[j]->id)
					break;
			 }
			//将對應sensor的對應PIN(DVDD/AVDD...)設定為系統的ID_PIN(GPIO/REGULATOR/MCKL)
			psensor_pwr->id[ppwr_info->pin] = j;
			ppwr_info++;
		}
	}

	//判斷dts中是否設定對應的index為對應的name,如:cam3_enable_sensor = "gc2375hmain3_mipi_raw";
	for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {
		memset(str_prop_name, 0, sizeof(str_prop_name));
		snprintf(str_prop_name,
					sizeof(str_prop_name),
					"cam%d_%s",
					i,
					"enable_sensor");
		if (of_property_read_string(
			of_node,
			str_prop_name,
			&phw->enable_sensor_by_index[i]) < 0) {
			pr_info("Property cust-sensor not defined\n");
			phw->enable_sensor_by_index[i] = NULL;
		}
	}
	return IMGSENSOR_RETURN_SUCCESS;
}
           

5、imgsensor_i2c_create I2C裝置初始化:

enum IMGSENSOR_RETURN imgsensor_i2c_create(void)
{
	int i;

	for (i = 0; i < IMGSENSOR_I2C_DEV_MAX_NUM; i++)
		i2c_add_driver(&gi2c_driver[i]);

	return IMGSENSOR_RETURN_SUCCESS;
}
           

6、具體類型的上電介紹(以pmic控制的regulator方式為例)

  前面imgsensor_hw_init中有去調用imgsensor_hw_regulator_open和regulator_init:

(1)傳入對應的裝置的device結構體:

static struct IMGSENSOR_HW_DEVICE device = {
	.pinstance = (void *)&reg_instance,
	.init      = regulator_init,//開機初始化時調用
	.set       = regulator_set,//在上電設定電壓時會調用
	.release   = regulator_release,
	.id        = IMGSENSOR_HW_ID_REGULATOR
};

enum IMGSENSOR_RETURN imgsensor_hw_regulator_open(
	struct IMGSENSOR_HW_DEVICE **pdevice)
{
	*pdevice = &device;
	return IMGSENSOR_RETURN_SUCCESS;
}
           

(2)調用對應的init進行初始化:

  因為MTK 平台的PMIC上電是通過統一的REGULATOR進行統一管理的,每一種上電方式需要申請對應type

的regulator控制的結構體,才可以來進行設定:

enum REGULATOR_TYPE {
	REGULATOR_TYPE_VCAMA,
	REGULATOR_TYPE_VCAMD,
	REGULATOR_TYPE_VCAMIO,
	REGULATOR_TYPE_MAX_NUM
};

static enum IMGSENSOR_RETURN regulator_init(void *pinstance)
{
	struct REGULATOR *preg = (struct REGULATOR *)pinstance;
	struct device            *pdevice;
	struct device_node       *pof_node;
	int j, i;
	char str_regulator_name[LENGTH_FOR_SNPRINTF];

	pdevice  = gimgsensor_device;

	for (j = IMGSENSOR_SENSOR_IDX_MIN_NUM;j < IMGSENSOR_SENSOR_IDX_MAX_NUM;j++) {
		for (i = 0; i < REGULATOR_TYPE_MAX_NUM; i++) {
			snprintf(str_regulator_name,
				sizeof(str_regulator_name),
				"cam%d_%s", j,
				regulator_control[i].pregulator_type);
			preg->pregulator[j][i] =
			    regulator_get(pdevice, str_regulator_name);

			if (preg->pregulator[j][i] == NULL)
				pr_err("regulator[%d][%d]  %s fail!\n",
					j, i, str_regulator_name);

			atomic_set(&preg->enable_cnt[j][i], 0);
		}
	}
	pdevice->of_node = pof_node;
	imgsensor_oc_init();
	return IMGSENSOR_RETURN_SUCCESS;
}
           

  到這裡imgsensor部分的内容還有對上(hal層)承接的ioctl相關的内容沒有介紹,這部分的内容會在後續的

整個系統調用流程中進行梳理。

作者:frank_zyp

您的支援是對部落客最大的鼓勵,感謝您的認真閱讀。

本文無所謂版權,歡迎轉載。