/* Kirby: add new-style driver {*/ static int OV8825AF_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int i4RetValue = 0; OV8825AFDB("[OV8825AF] Attach I2C \n"); /* Kirby: add new-style driver { */ g_pstOV8825AF_I2Cclient = client; //g_pstOV8825AF_I2Cclient->addr = g_pstOV8825AF_I2Cclient->addr >> 1; g_pstOV8825AF_I2Cclient->addr = OV8825AF_VCM_WRITE_ID >> 1; //Register char driver i4RetValue = Register_OV8825AF_CharDrv(); if(i4RetValue){ OV8825AFDB("[OV8825AF] register char device failed!\n"); return i4RetValue; } spin_lock_init(&g_OV8825AF_SpinLock); OV8825AFDB("[OV8825AF] Attached!! \n"); return 0; }
inline static int Register_OV8825AF_CharDrv(void) { struct device* vcm_device = NULL; //Allocate char driver no. if( alloc_chrdev_region(&g_OV8825AF_devno, 0, 1,OV8825AF_DRVNAME) ) { OV8825AFDB("[OV8825AF] Allocate device no failed\n"); return -EAGAIN; } //Allocate driver g_pOV8825AF_CharDrv = cdev_alloc(); if(NULL == g_pOV8825AF_CharDrv) { unregister_chrdev_region(g_OV8825AF_devno, 1); OV8825AFDB("[OV8825AF] Allocate mem for kobject failed\n"); return -ENOMEM; } //Attatch file operation. cdev_init(g_pOV8825AF_CharDrv, &g_stOV8825AF_fops); g_pOV8825AF_CharDrv->owner = THIS_MODULE; //Add to system if(cdev_add(g_pOV8825AF_CharDrv, g_OV8825AF_devno, 1)) { OV8825AFDB("[OV8825AF] Attatch file operation failed\n"); unregister_chrdev_region(g_OV8825AF_devno, 1); return -EAGAIN; } actuator_class = class_create(THIS_MODULE, "actuatordrv5"); if (IS_ERR(actuator_class)) { int ret = PTR_ERR(actuator_class); OV8825AFDB("Unable to create class, err = %d\n", ret); return ret; } vcm_device = device_create(actuator_class, NULL, g_OV8825AF_devno, NULL, OV8825AF_DRVNAME); if(NULL == vcm_device) { return -EIO; } return 0; }
static int s4OV8825AF_WriteReg(u16 a_u2Data) { u16 temp,SlewRate=1; OV8825AFDB("s4OV8825AF_WriteReg = %d \n", a_u2Data); temp=(a_u2Data<<4)+SlewRate; OV8825AFDB("-----stemp=(a_u2Data<<4)+SlewRate = %d----- \n", temp); OV8825AF_write_cmos_sensor(0x3619,(temp>>8)&0xff); OV8825AF_write_cmos_sensor(0x3618,temp&0xff); return 0; }
static int __init OV8825AF_i2C_init(void) { i2c_register_board_info(LENS_I2C_BUSNUM, &kd_lens_dev, 1); if(platform_device_register(&g_stOV8825AF_device)){ OV8825AFDB("failed to register AF driver\n"); return -ENODEV; } if (platform_driver_register(&g_stOV8825AF_Driver)) { OV8825AFDB("failed to register OV8825AF driver\n"); return -ENODEV; } return 0; }
static long OV8825AF_Ioctl( struct file * a_pstFile, unsigned int a_u4Command, unsigned long a_u4Param) { long i4RetValue = 0; switch(a_u4Command) { case OV8825AFIOC_G_MOTORINFO : i4RetValue = getOV8825AFInfo((__user stOV8825AF_MotorInfo *)(a_u4Param)); break; case OV8825AFIOC_T_MOVETO : i4RetValue = moveOV8825AF(a_u4Param); break; case OV8825AFIOC_T_SETINFPOS : i4RetValue = setOV8825AFInf(a_u4Param); break; case OV8825AFIOC_T_SETMACROPOS : i4RetValue = setOV8825AFMacro(a_u4Param); break; default : OV8825AFDB("[OV8825AF] No CMD \n"); i4RetValue = -EPERM; break; } return i4RetValue; }
//Main jobs: //Break down move step for eliminating noise static int breakDownSteps(int max_step, int interval, int CurrentPos, int TargetPos) { unsigned short tmpTargetPos; short sign = 0; OV8825AFDB("[OV8825AF] break down steps from=%d, to=%d \n", CurrentPos, TargetPos); if (TargetPos < CurrentPos) sign = -1; else if (TargetPos > CurrentPos) sign = 1; while( abs(CurrentPos - TargetPos) > max_step ){ tmpTargetPos = CurrentPos + max_step * sign; OV8825AFDB("tmpTargetPos=%d\n", tmpTargetPos); if(s4OV8825AF_WriteReg(tmpTargetPos) == 0) { CurrentPos = tmpTargetPos; OV8825AFDB("CurrentPos=%d\n", CurrentPos); } else { OV8825AFDB("[OV8825AF] set I2C failed when moving the motor \n"); g_i4MotorStatus = -1; } //Delay for few milli-second OV8825AFDB("start delay \n"); msleep(interval); OV8825AFDB("after delay \n"); } OV8825AFDB("Last step from=%d, to=%d \n", CurrentPos, TargetPos); if(s4OV8825AF_WriteReg(TargetPos) == 0) { CurrentPos = TargetPos; } else { OV8825AFDB("[OV8825AF] set I2C failed when moving the motor \n"); g_i4MotorStatus = -1; } g_u4CurrPosition = CurrentPos; OV8825AFDB("Leave breakdown\n"); return 0; }
static int s4OV8825AF_ReadReg(unsigned short * a_pu2Result) { int temp = 0; char pBuff[2]; temp = (OV8825AF_read_cmos_sensor(0x3618)+ (OV8825AF_read_cmos_sensor(0x3619)<<8))>>4; *a_pu2Result = temp; OV8825AFDB("s4OV8825AF_ReadReg = %d \n", temp); return 0; }
/* Q1 : Try release multiple times. */ static int OV8825AF_Release(struct inode *a_pstInode, struct file *a_pstFile) { if (g_s4OV8825AF_Opened == 2) { g_sr = 5; if (g_u4CurrPosition > 700) { s4OV8825AF_WriteReg(700); msleep(3); } if (g_u4CurrPosition > 600) { s4OV8825AF_WriteReg(600); msleep(3); } if (g_u4CurrPosition > 500) { s4OV8825AF_WriteReg(500); msleep(3); } if (g_u4CurrPosition > 400) { s4OV8825AF_WriteReg(400); msleep(3); } if (g_u4CurrPosition > 300) { s4OV8825AF_WriteReg(300); msleep(3); } if (g_u4CurrPosition > 200) { s4OV8825AF_WriteReg(200); msleep(3); } if (g_u4CurrPosition > 100) { s4OV8825AF_WriteReg(100); msleep(3); } } if (g_s4OV8825AF_Opened) { OV8825AFDB("[OV8825AF] feee\n"); spin_lock(&g_OV8825AF_SpinLock); g_s4OV8825AF_Opened = 0; spin_unlock(&g_OV8825AF_SpinLock); } return 0; }
/* CAM_RESET */ static int OV8825AF_Open(struct inode *a_pstInode, struct file *a_pstFile) { if (g_s4OV8825AF_Opened) { OV8825AFDB("[OV8825AF] the device is opened\n"); return -EBUSY; } spin_lock(&g_OV8825AF_SpinLock); g_s4OV8825AF_Opened = 1; spin_unlock(&g_OV8825AF_SpinLock); return 0; }
inline static int getOV8825AFInfo(__user stOV8825AF_MotorInfo * pstMotorInfo) { stOV8825AF_MotorInfo stMotorInfo; stMotorInfo.u4MacroPosition = g_u4OV8825AF_MACRO; stMotorInfo.u4InfPosition = g_u4OV8825AF_INF; stMotorInfo.u4CurrentPosition = g_u4CurrPosition; if (g_i4MotorStatus == 1) {stMotorInfo.bIsMotorMoving = TRUE;} else {stMotorInfo.bIsMotorMoving = FALSE;} if (g_s4OV8825AF_Opened >= 1) {stMotorInfo.bIsMotorOpen = TRUE;} else {stMotorInfo.bIsMotorOpen = FALSE;} if(copy_to_user(pstMotorInfo , &stMotorInfo , sizeof(stOV8825AF_MotorInfo))) { OV8825AFDB("[OV8825AF] copy to user failed when getting motor information \n"); } return 0; }
//Main jobs: // 1.Deallocate anything that "open" allocated in private_data. // 2.Shut down the device on last close. // 3.Only called once on last time. // Q1 : Try release multiple times. static int OV8825AF_Release(struct inode * a_pstInode, struct file * a_pstFile) { if (g_s4OV8825AF_Opened) { OV8825AFDB("[OV8825AF] feee \n"); g_sr = 5; s4OV8825AF_WriteReg(200); msleep(10); s4OV8825AF_WriteReg(100); msleep(10); spin_lock(&g_OV8825AF_SpinLock); g_s4OV8825AF_Opened = 0; spin_unlock(&g_OV8825AF_SpinLock); } return 0; }
inline static int moveOV8825AF(unsigned long a_u4Position) { if((a_u4Position > g_u4OV8825AF_MACRO) || (a_u4Position < g_u4OV8825AF_INF)) { OV8825AFDB("[OV8825AF] out of range \n"); return -EINVAL; } if (g_s4OV8825AF_Opened == 1) { unsigned short InitPos; if(s4OV8825AF_ReadReg(&InitPos) == 0) { OV8825AFDB("[OV8825AF] Init Pos %6d \n", InitPos); g_u4CurrPosition = (unsigned long)InitPos; } else { g_u4CurrPosition = 0; } g_s4OV8825AF_Opened = 2; } if (g_u4CurrPosition < a_u4Position) {g_i4Dir = 1;} else if (g_u4CurrPosition > a_u4Position) {g_i4Dir = -1;} else {return 0;} if (1) { g_i4Position = (long)g_u4CurrPosition; g_u4TargetPosition = a_u4Position; if (g_i4Dir == 1) { //if ((g_u4TargetPosition - g_u4CurrPosition)<60) { g_i4MotorStatus = 0; if(s4OV8825AF_WriteReg((unsigned short)g_u4TargetPosition) == 0) { g_u4CurrPosition = (unsigned long)g_u4TargetPosition; } else { OV8825AFDB("[OV8825AF] set I2C failed when moving the motor \n"); g_i4MotorStatus = -1; } } //else //{ // g_i4MotorStatus = 1; //} } else if (g_i4Dir == -1) { //if ((g_u4CurrPosition - g_u4TargetPosition)<60) { g_i4MotorStatus = 0; if(s4OV8825AF_WriteReg((unsigned short)g_u4TargetPosition) == 0) { g_u4CurrPosition = (unsigned long)g_u4TargetPosition; } else { OV8825AFDB("[OV8825AF] set I2C failed when moving the motor \n"); g_i4MotorStatus = -1; } } //else //{ // g_i4MotorStatus = 1; //} } } else { g_i4Position = (long)g_u4CurrPosition; g_u4TargetPosition = a_u4Position; g_i4MotorStatus = 1; } return 0; }
inline static int moveOV8825AF(unsigned long a_u4Position) { int ret = 0; if ((a_u4Position > g_u4OV8825AF_MACRO) || (a_u4Position < g_u4OV8825AF_INF)) { OV8825AFDB("[OV8825AF] out of range\n"); return -EINVAL; } if (g_s4OV8825AF_Opened == 1) { unsigned short InitPos; ret = s4OV8825AF_ReadReg(&InitPos); if (ret == 0) { OV8825AFDB("[OV8825AF] Init Pos %6d\n", InitPos); spin_lock(&g_OV8825AF_SpinLock); g_u4CurrPosition = (unsigned long)InitPos; spin_unlock(&g_OV8825AF_SpinLock); } else { spin_lock(&g_OV8825AF_SpinLock); g_u4CurrPosition = 0; spin_unlock(&g_OV8825AF_SpinLock); } spin_lock(&g_OV8825AF_SpinLock); g_s4OV8825AF_Opened = 2; spin_unlock(&g_OV8825AF_SpinLock); } if (g_u4CurrPosition < a_u4Position) { spin_lock(&g_OV8825AF_SpinLock); g_i4Dir = 1; spin_unlock(&g_OV8825AF_SpinLock); } else if (g_u4CurrPosition > a_u4Position) { spin_lock(&g_OV8825AF_SpinLock); g_i4Dir = -1; spin_unlock(&g_OV8825AF_SpinLock); } else { return 0; } spin_lock(&g_OV8825AF_SpinLock); g_u4TargetPosition = a_u4Position; spin_unlock(&g_OV8825AF_SpinLock); /* OV8825AFDB("[OV8825AF] move [curr] %d [target] %d\n", g_u4CurrPosition, g_u4TargetPosition); */ spin_lock(&g_OV8825AF_SpinLock); g_sr = 3; g_i4MotorStatus = 0; spin_unlock(&g_OV8825AF_SpinLock); if (s4OV8825AF_WriteReg((unsigned short)g_u4TargetPosition) == 0) { spin_lock(&g_OV8825AF_SpinLock); g_u4CurrPosition = (unsigned long)g_u4TargetPosition; spin_unlock(&g_OV8825AF_SpinLock); } else { OV8825AFDB("[OV8825AF] set I2C failed when moving the motor\n"); spin_lock(&g_OV8825AF_SpinLock); g_i4MotorStatus = -1; spin_unlock(&g_OV8825AF_SpinLock); } return 0; }
inline static int moveOV8825AF(unsigned long a_u4Position) { int ret = 0; OV8825AFDB("a_u4Position = %d \n", a_u4Position); if((a_u4Position > g_u4OV8825AF_MACRO) || (a_u4Position < g_u4OV8825AF_INF)) { OV8825AFDB("[OV8825AF] out of range \n"); return -EINVAL; } if (g_s4OV8825AF_Opened == 1) { unsigned short InitPos; ret = s4OV8825AF_ReadReg(&InitPos); spin_lock(&g_OV8825AF_SpinLock); if(ret == 0) { OV8825AFDB("[OV8825AF] Init Pos %6d \n", InitPos); g_u4CurrPosition = (unsigned long)InitPos; } else { g_u4CurrPosition = 0; } g_s4OV8825AF_Opened = 2; spin_unlock(&g_OV8825AF_SpinLock); } if (g_u4CurrPosition < a_u4Position) { spin_lock(&g_OV8825AF_SpinLock); g_i4Dir = 1; spin_unlock(&g_OV8825AF_SpinLock); } else if (g_u4CurrPosition > a_u4Position) { spin_lock(&g_OV8825AF_SpinLock); g_i4Dir = -1; spin_unlock(&g_OV8825AF_SpinLock); } else {return 0;} spin_lock(&g_OV8825AF_SpinLock); //g_i4Position = (long)g_u4CurrPosition; g_u4TargetPosition = a_u4Position; g_sr = 3; g_i4MotorStatus = 0; spin_unlock(&g_OV8825AF_SpinLock); if(abs(g_u4CurrPosition - g_u4TargetPosition) > MAX_MOVE_STEP) { OV8825AFDB("[OV8825AF] in small stepLeave breakdown \n"); breakDownSteps(MAX_MOVE_STEP, MOVE_INTERVAL, g_u4CurrPosition, g_u4TargetPosition); } else { if(s4OV8825AF_WriteReg((unsigned short)g_u4TargetPosition) == 0) { spin_lock(&g_OV8825AF_SpinLock); g_u4CurrPosition = (unsigned long)g_u4TargetPosition; spin_unlock(&g_OV8825AF_SpinLock); } else { OV8825AFDB("[OV8825AF] set I2C failed when moving the motor \n"); spin_lock(&g_OV8825AF_SpinLock); g_i4MotorStatus = -1; spin_unlock(&g_OV8825AF_SpinLock); } } return 0; }