一.主要文件
kernel-4.19/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c
1.1 主要函数
imgsensor_hw.c共计就四个函数:
- imgsensor_hw_init
- imgsensor_hw_power
- imgsensor_hw_power_sequence
- imgsensor_hw_release_all
看名字就可以知道函数实现的功能。
1.2 上电相关的结构体
- pdev[IMGSENSOR_HW_ID_MAX_NUM]这个结构体指针数组用来保存控制上电方式的设备(gpio/regulator)和控制时钟相关的设备,这个结构主要保存了一些函数指针,用来调用设备的init、set等方法。
- sensor_pwr[IMGSENSOR_SENSOR_IDX_MAX_NUM]用来保存上电方式和上电顺序等信息,这是一个数组,可以保存多个sensor的信息。
ppwr_info保存pin的信息,比如状态,延迟等,指针类型,通过加减操作移动到下一个位置,和数组差不多,能保存多个pin。
id[]数组用来保存每个pin的上电方式。
二.上电流程
2.1 imgsensor_hw_init()
在probe()函数中已经初始化上电所需要的信息,用到了imgsensor_hw_init()函数:
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];//LENGTH_FOR_SNPRINTF 256
struct device_node *of_node
= of_find_compatible_node(NULL, NULL, "mediatek,camera_hw");
/* 初始化pdev数组,绑定上电和时钟控制设备 */
for (i = 0; i < IMGSENSOR_HW_ID_MAX_NUM; i++) {//IMGSENSOR_HW_ID_MAX_NUM 3
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);
}
for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {//IMGSENSOR_SENSOR_IDX_MAX_NUM 3
psensor_pwr = &phw->sensor_pwr[i];
pcust_pwr_cfg = imgsensor_custom_config;
while (pcust_pwr_cfg->sensor_idx != i &&
pcust_pwr_cfg->sensor_idx != IMGSENSOR_SENSOR_IDX_NONE)//IMGSENSOR_SENSOR_IDX_NONE 6
pcust_pwr_cfg++;
if (pcust_pwr_cfg->sensor_idx == IMGSENSOR_SENSOR_IDX_NONE)
continue;
ppwr_info = pcust_pwr_cfg->pwr_info;
while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE) {//IMGSENSOR_HW_PIN_NONE 0
for (j = 0; j < IMGSENSOR_HW_ID_MAX_NUM; j++)//IMGSENSOR_HW_ID_MAX_NUM 3
if (ppwr_info->id == phw->pdev[j]->id)
break;
psensor_pwr->id[ppwr_info->pin] = j;
ppwr_info++;
}
}
/* 读设备树,? */
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;
}
分析这个函数,依次做了下面这些事:
1.第一个for循环初始化了pdev数组,绑定上电和时钟控制设备。程序中hw_open数组定义如下:
enum IMGSENSOR_RETURN
(*hw_open[IMGSENSOR_HW_ID_MAX_NUM])(struct IMGSENSOR_HW_DEVICE **) = {
imgsensor_hw_regulator_open,
imgsensor_hw_gpio_open,
imgsensor_hw_mclk_open
};
也就是保存了三个函数指针,调用这三个函数就可以初始化pdev数组,例如imgsensor_hw_regulator_open()函数定义如下:
static struct IMGSENSOR_HW_DEVICE device = {
.pinstance = (void *) ®_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;
}
可以看到就是绑定了一些操作函数,通过对某个pin脚调用set函数就可以完成对它的上电操作。
2.第二个for循环是为sensor设置上电顺序,前面提到的enum IMGSENSOR_HW_ID id[IMGSENSOR_HW_PIN_MAX_NUM]数组就保存了当前sensor引脚的上电方式。
分析代码,这里有一个数组imgsensor_custom_config[ ],它的作用是配置sensor每个引脚的上电方式,在imgsensor_cfg_table.c中:
struct IMGSENSOR_HW_CFG imgsensor_custom_config[] = {
{
IMGSENSOR_SENSOR_IDX_MAIN,//sensor_id
IMGSENSOR_I2C_DEV_0,//sensor_i2c dev
{
//上电方式 pin脚
{IMGSENSOR_HW_ID_MCLK, IMGSENSOR_HW_PIN_MCLK},
{IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_AVDD},
{IMGSENSOR_HW_ID_REGULATOR, IMGSENSOR_HW_PIN_DOVDD},
{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_DVDD},
{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_PDN},
{IMGSENSOR_HW_ID_GPIO, IMGSENSOR_HW_PIN_RST},
{IMGSENSOR_HW_ID_NONE, IMGSENSOR_HW_PIN_NONE},
},
},
/* 省略部分代码 */
};
首先通过第一个while循环将sensorid和当前要操作的sensor对应起来,然后通过第二个while循环来拿到imgsensor_custom_config[]中的上电方式,将这个上电方式与一开始初始化的pdev中的设备对应起来,得到pdev对应设备的索引 j ,最后通过赋值操作把上电方式和引脚保存到enum IMGSENSOR_HW_ID id[IMGSENSOR_HW_PIN_MAX_NUM]这个数组中,匹配结果如下:
3.最后一个for循环读设备树,读到的是sensor的名字,在后面imgsensor_hw_power()函数会进行字符串匹配验证,这里的作用以后在探究。
2.2imgsensor_hw_power()
就是用来上电的函数:
enum IMGSENSOR_RETURN imgsensor_hw_power(
struct IMGSENSOR_HW *phw,
struct IMGSENSOR_SENSOR *psensor,
char *curr_sensor_name,
enum IMGSENSOR_HW_POWER_STATUS pwr_status) {
enum IMGSENSOR_SENSOR_IDX sensor_idx = psensor->inst.sensor_idx;
char str_index[LENGTH_FOR_SNPRINTF];
int ret = 0;
pr_info(
"sensor_idx %d, power %d curr_sensor_name %s, enable list %s\n",
sensor_idx,
pwr_status,
curr_sensor_name,
phw->enable_sensor_by_index[(uint32_t) sensor_idx] == NULL
? "NULL"
: phw->enable_sensor_by_index[(uint32_t) sensor_idx]);
if (phw->enable_sensor_by_index[(uint32_t) sensor_idx] &&
!strstr(phw->enable_sensor_by_index[(uint32_t) sensor_idx], curr_sensor_name))
return IMGSENSOR_RETURN_ERROR;
ret = snprintf(str_index, sizeof(str_index), "%d", sensor_idx);
if (ret == 0) {
pr_info("Error! snprintf allocate 0");
ret = IMGSENSOR_RETURN_ERROR;
return ret;
}
imgsensor_hw_power_sequence(
phw,
sensor_idx,
pwr_status,
platform_power_sequence,
str_index);
imgsensor_hw_power_sequence(
phw,
sensor_idx,
pwr_status,
sensor_power_sequence,
curr_sensor_name);
return IMGSENSOR_RETURN_SUCCESS;
}
这个函数主要就调用了imgsensor_hw_power_sequence(),这里调用了两次,主要是第四个参数不同,platform_power_sequence[]配置的是平台上电顺序,sensor_power_sequence[]配置的是sensor上电顺序,它们都在imgsensor_cfg_table.c中。在某个sensor上电的时候会匹配上其中一种进行上电。
2.3 imgsensor_hw_power_sequence()
static enum IMGSENSOR_RETURN imgsensor_hw_power_sequence(
struct IMGSENSOR_HW *phw,
enum IMGSENSOR_SENSOR_IDX sensor_idx,
enum IMGSENSOR_HW_POWER_STATUS pwr_status,
struct IMGSENSOR_HW_POWER_SEQ *ppower_sequence,
char *pcurr_idx) {
struct IMGSENSOR_HW_SENSOR_POWER *psensor_pwr =
&phw->sensor_pwr[sensor_idx];
struct IMGSENSOR_HW_POWER_SEQ *ppwr_seq = ppower_sequence;
struct IMGSENSOR_HW_POWER_INFO *ppwr_info;
struct IMGSENSOR_HW_DEVICE *pdev;
int pin_cnt = 0;
/* 匹配上电的方式,是platform还是sensor */
while (ppwr_seq < ppower_sequence + IMGSENSOR_HW_SENSOR_MAX_NUM &&
ppwr_seq->name != NULL) {
if (!strcmp(ppwr_seq->name, PLATFORM_POWER_SEQ_NAME)) {
if (sensor_idx == ppwr_seq->_idx)
break;
} else {
if (!strcmp(ppwr_seq->name, pcurr_idx))
break;
}
ppwr_seq++;
}
if (ppwr_seq->name == NULL) {
return IMGSENSOR_RETURN_ERROR;
}
ppwr_info = ppwr_seq->pwr_info;
/* 依次为pin上电 */
while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE &&
ppwr_info < ppwr_seq->pwr_info + IMGSENSOR_HW_POWER_INFO_MAX) {
if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON &&
ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) {
/* 匹配上电的设备,是gpio还是regulator等等 */
pdev = phw->pdev[psensor_pwr->id[ppwr_info->pin]];
if (pdev->set != NULL)
/* 调用设备的set()进行上电 */
pdev->set(
pdev->pinstance,
sensor_idx,
ppwr_info->pin,
ppwr_info->pin_state_on);
mdelay(ppwr_info->pin_on_delay);
}
ppwr_info++;
pin_cnt++;
}
/* 下电方式类似 */
if (pwr_status == IMGSENSOR_HW_POWER_STATUS_OFF) {
while (pin_cnt) {
ppwr_info--;
pin_cnt--;
if (ppwr_info->pin != IMGSENSOR_HW_PIN_UNDEF) {
pdev =
phw->pdev[psensor_pwr->id[ppwr_info->pin]];
mdelay(ppwr_info->pin_on_delay);
if (pdev->set != NULL)
pdev->set(
pdev->pinstance,
sensor_idx,
ppwr_info->pin,
ppwr_info->pin_state_off);
}
}
}
/* wait for power stable */
if (pwr_status == IMGSENSOR_HW_POWER_STATUS_ON)
mdelay(5);
return IMGSENSOR_RETURN_SUCCESS;
}
这里匹配上电的设备就用到了上面那个id[]数组,通过pin的序号拿到其上电所需要的对应的设备,然后set即可完成上电。文章来源:https://www.toymoban.com/news/detail-435763.html
暂时写到这里,别的后面在写,希望大家提出意见,共同学习。文章来源地址https://www.toymoban.com/news/detail-435763.html
到了这里,关于MTK camera驱动浅析(2)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!