How to tune a new closeloop vcm, for instance, LC898214?

When I got a new camera module with LC898214, I intuitively thought that I could use LC898212 driver for test, but it’s not true, it didn’t work anyway. I feel a little upset because I have to tune a new AF driver just for testing the module. Fortunately, it’s very easy to design the driver with Onsemi FAE’s help.

Modify LC898212 driver for LC898214,

In “msm_LC898212_InitForQualcomm” function

         uint16_t chip_id = 0;

         uint16_t temp_id = 0, check_data = 0xFF, step = 0;

         uint16_t macro_low, macro_hi, inf_low, inf_hi;

         struct msm_camera_cci_client *cci_client = NULL;

 

         a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0xF0,&chip_id, MSM_CAMERA_I2C_BYTE_DATA);

         if(chip_id == 0x42)

                   {

                            printk("xiaolifeng@ find LC898214 success, chip_id = 0x%x\n", chip_id);

                   }

         else

                   {

                            printk("xiaolifeng@ find LC898214 failure, chip_id = 0x%x\n", chip_id);

                   }

          a_ctrl->i2c_client.i2c_func_tbl->i2c_write(&a_ctrl->i2c_client,0x87, 0x00, MSM_CAMERA_I2C_BYTE_DATA);

          cci_client = a_ctrl->i2c_client.cci_client;

          temp_id = cci_client->sid;

          printk("xiaolifeng@ temp_id = 0x%x\n", temp_id);

          cci_client->sid = 0xE7 >>1;

          a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0x39,&macro_low, MSM_CAMERA_I2C_BYTE_DATA);

          a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0x38,&macro_hi, MSM_CAMERA_I2C_BYTE_DATA);

          a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0x3b,&inf_low, MSM_CAMERA_I2C_BYTE_DATA);

          a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0x3a,&inf_hi, MSM_CAMERA_I2C_BYTE_DATA);

        

        if(a_ctrl-> cci_master == 0)

                   {

                            g_macro_pos_0 = macro_low|macro_hi<<8;

                          g_inf_pos_0 = inf_low|inf_hi<<8;

                   }

         else

                   {

                            g_macro_pos_1 = macro_low|macro_hi<<8;

                          g_inf_pos_1 = inf_low|inf_hi<<8;

                   }       

          printk("xiaolifeng@ Read macro&infinity position from EEprom:cci_master=> %d\n macro_low = 0x%x, macro_hi= 0x%x, inf_low = 0x%x, inf_hi = 0x%x \n macro_pos = 0x%x, inf_pos= 0x%x\n", a_ctrl-> cci_master, macro_low, macro_hi, inf_low, inf_hi, macro_low|macro_hi<<8, inf_low|inf_hi<<8);

                

          cci_client->sid = temp_id;

          a_ctrl->i2c_client.i2c_func_tbl->i2c_write(&a_ctrl->i2c_client,0xe0, 0x01, MSM_CAMERA_I2C_BYTE_DATA);

          msleep(2);

 

          while(1)

                 {

                           a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0xe0,&check_data, MSM_CAMERA_I2C_BYTE_DATA);

                             if(check_data == 0)

                                    break;

                             step++;

                             if(step == 3)

                                    {

                                             printk("xiaolifeng@ Break check loop because of time out\n");

                                               break;

                                    }

                 }

 

Notice that LC898214 have built-in eeprom for storaging macro and infinity position. So after check ID of LC898214, we need to change i2c slave address to eeprom, that is why we can see such line: “cci_client->sid = 0xE7 >>1;”

Modify transformation function which change “code” range 0~1023 from user space into real vcm hardware register value.

int msm_LC898212_convert(uint16_t code,uint32_t subdev_id){

    int HallPos;

    int    HallRange;

    int    PosRange;

    if(subdev_id == 0) //0 means imx214 1means imx214_R

    {

        HallRange = g_macro_pos_0 + (0x10000 - g_inf_pos_0);                  

    }

    else

    {

        HallRange = g_macro_pos_1 + (0x10000 - g_inf_pos_1);     

    }

    PosRange = abs_closeloop(tinfo.pos_high - tinfo.pos_low);

    if(subdev_id == 0)

         {

                       HallPos = ((tinfo.pos_high - code) * HallRange / PosRange) + g_inf_pos_0;

         }

    else

         {

                   HallPos = ((tinfo.pos_high - code) * HallRange / PosRange) + g_inf_pos_1;

         }

return HallPos & 0xFFFF;        

}

how to understand these mapping codes?

For a given module, I read macro_pos is 0x2e07, inf_pos is 0xe8b1, its hardware range is 0~0x2e07 plus 0xe8b1~0xffff. We want to map the unique range to 0~1023 for user space application. Firstly, total hardware range is “HallRange = g_macro_pos_0 + (0x10000 - g_inf_pos_0);”, secondly, use HallRange divide PosRange which is 0~1023, then multiply “tinfo.pos_high – code” in order to change the value 1023 as micro and 0 as infinity. It is also unique too. Then add g_inf_pos_0, it probably beyond 0x10000, so finally use “HallPos & 0xFFFF” for changing value under 0x2e07, it is a trick, right?

Modify “moveto” function to make the motor run to the position we expect,

uint16_t msm_LC898212_moveto(struct msm_actuator_ctrl_t *a_ctrl,uint16_t SsSmvEnd ){

         uint16_t check_data = 0xFF, step = 0;

 

         a_ctrl->i2c_client.i2c_func_tbl->i2c_write(&a_ctrl->i2c_client,0xA0, SsSmvEnd, MSM_CAMERA_I2C_WORD_DATA);

          msleep(5);

          while(1)

                 {

                           a_ctrl->i2c_client.i2c_func_tbl->i2c_read(&a_ctrl->i2c_client, 0x8F,&check_data, MSM_CAMERA_I2C_BYTE_DATA);

                             if(check_data == 0)

                                    break;

                             msleep(5);

                             step++;

                             check_data = 0xFF;

                             if(step == 3)

                                    {

                                             printk("xiaolifeng@ Break VCM moveto because of time out\n");

                                               break;

                                    }

                 }

         return check_data;

}

0xA0 is the register for controlling the motor’s position, we’d better read 0x8F for checking if there are something wrong when it work.

Above are summary codes for back-up, other codes should be modified, such as reading the feedback of motor real position and judge whether difference between position we want it go and its real position are reliable. But I just want to make the new dual cameras work, so I am lazy and omit a lot of work.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值