Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* |
2 | * Driver for CAM_CAL | |
3 | * | |
4 | * | |
5 | */ | |
6 | ||
7 | #include <linux/i2c.h> | |
8 | #include <linux/platform_device.h> | |
9 | #include <linux/delay.h> | |
10 | #include <linux/cdev.h> | |
11 | #include <linux/uaccess.h> | |
12 | #include <linux/slab.h> | |
13 | #include <linux/fs.h> | |
14 | #include "kd_camera_hw.h" | |
15 | #include "cam_cal.h" | |
16 | #include "cam_cal_define.h" | |
17 | ||
18 | #include "dummy_cam_cal.h" | |
19 | #include <asm/system.h> // for SMP | |
20 | ||
21 | //#define CAM_CALGETDLT_DEBUG //test | |
22 | //#define CAM_CAL_DEBUG //test | |
23 | #ifdef CAM_CAL_DEBUG | |
24 | #define CAM_CALDB printk | |
25 | #else | |
26 | #define CAM_CALDB(x,...) | |
27 | #endif | |
28 | ||
29 | ||
30 | static DEFINE_SPINLOCK(g_CAM_CALLock); // for SMP | |
31 | ||
32 | #define CAM_CAL_I2C_BUSNUM 1 | |
33 | static struct i2c_board_info __initdata kd_cam_cal_dev={ I2C_BOARD_INFO("dummy_cam_cal", 0xAB>>1)}; //make dummy_eeprom co-exist | |
34 | ||
35 | /******************************************************************************* | |
36 | * | |
37 | ********************************************************************************/ | |
38 | #define CAM_CAL_ICS_REVISION 1 //seanlin111208 | |
39 | /******************************************************************************* | |
40 | * | |
41 | ********************************************************************************/ | |
42 | #define CAM_CAL_DRVNAME "dummy_cam_cal" | |
43 | #define CAM_CAL_I2C_GROUP_ID 0 | |
44 | /******************************************************************************* | |
45 | * | |
46 | ********************************************************************************/ | |
47 | /* fix warning MSG | |
48 | static unsigned short g_pu2Normal_i2c[] = {S24CS64A_DEVICE_ID , I2C_CLIENT_END}; | |
49 | static unsigned short g_u2Ignore = I2C_CLIENT_END; | |
50 | static struct i2c_client_address_data g_stCAM_CAL_Addr_data = { | |
51 | .normal_i2c = g_pu2Normal_i2c, | |
52 | .probe = &g_u2Ignore, | |
53 | .ignore = &g_u2Ignore | |
54 | }; */ | |
55 | static struct i2c_client * g_pstI2Cclient = NULL; | |
56 | ||
57 | //81 is used for V4L driver | |
58 | static dev_t g_CAM_CALdevno = MKDEV(CAM_CAL_DEV_MAJOR_NUMBER,0); | |
59 | static struct cdev * g_pCAM_CAL_CharDrv = NULL; | |
60 | //static spinlock_t g_CAM_CALLock; | |
61 | static struct class *CAM_CAL_class = NULL; | |
62 | static atomic_t g_CAM_CALatomic; | |
63 | /******************************************************************************* | |
64 | * | |
65 | ********************************************************************************/ | |
66 | // maximun read length is limited at "I2C_FIFO_SIZE" in I2c-mt65xx.c which is 8 bytes | |
67 | int iWriteCAM_CAL(u16 a_u2Addr , u32 a_u4Bytes, u8 * puDataInBytes) | |
68 | { | |
69 | int i4RetValue = 0; | |
70 | u32 u4Index = 0; | |
71 | char puSendCmd[8] = {(char)(a_u2Addr >> 8) , (char)(a_u2Addr & 0xFF) , | |
72 | 0, 0, 0, 0, 0, 0}; | |
73 | if(a_u4Bytes + 2 > 8) | |
74 | { | |
75 | CAM_CALDB("[CAM_CAL] exceed I2c-mt65xx.c 8 bytes limitation (include address 2 Byte)\n"); | |
76 | return -1; | |
77 | } | |
78 | ||
79 | for(u4Index = 0 ; u4Index < a_u4Bytes ; u4Index += 1 ) | |
80 | { | |
81 | puSendCmd[(u4Index + 2)] = puDataInBytes[u4Index]; | |
82 | } | |
83 | ||
84 | i4RetValue = i2c_master_send(g_pstI2Cclient, puSendCmd, (a_u4Bytes + 2)); | |
85 | if (i4RetValue != (a_u4Bytes + 2)) | |
86 | { | |
87 | CAM_CALDB("[CAM_CAL] I2C write failed!! \n"); | |
88 | return -1; | |
89 | } | |
90 | mdelay(10); //for tWR singnal --> write data form buffer to memory. | |
91 | ||
92 | //CAM_CALDB("[CAM_CAL] iWriteCAM_CAL done!! \n"); | |
93 | return 0; | |
94 | } | |
95 | ||
96 | ||
97 | // maximun read length is limited at "I2C_FIFO_SIZE" in I2c-mt65xx.c which is 8 bytes | |
98 | int iReadCAM_CAL(u16 a_u2Addr, u32 ui4_length, u8 * a_puBuff) | |
99 | { | |
100 | int i4RetValue = 0; | |
101 | char puReadCmd[2] = {(char)(a_u2Addr >> 8) , (char)(a_u2Addr & 0xFF)}; | |
102 | ||
103 | //CAM_CALDB("[CAM_CAL] iReadCAM_CAL!! \n"); | |
104 | ||
105 | if(ui4_length > 8) | |
106 | { | |
107 | CAM_CALDB("[CAM_CAL] exceed I2c-mt65xx.c 8 bytes limitation\n"); | |
108 | return -1; | |
109 | } | |
110 | spin_lock(&g_CAM_CALLock); //for SMP | |
111 | g_pstI2Cclient->addr = g_pstI2Cclient->addr & (I2C_MASK_FLAG | I2C_WR_FLAG); | |
112 | spin_unlock(&g_CAM_CALLock); // for SMP | |
113 | ||
114 | //CAM_CALDB("[EERPOM] i2c_master_send \n"); | |
115 | i4RetValue = i2c_master_send(g_pstI2Cclient, puReadCmd, 2); | |
116 | if (i4RetValue != 2) | |
117 | { | |
118 | CAM_CALDB("[CAM_CAL] I2C send read address failed!! \n"); | |
119 | return -1; | |
120 | } | |
121 | ||
122 | //CAM_CALDB("[EERPOM] i2c_master_recv \n"); | |
123 | i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_puBuff, ui4_length); | |
124 | if (i4RetValue != ui4_length) | |
125 | { | |
126 | CAM_CALDB("[CAM_CAL] I2C read data failed!! \n"); | |
127 | return -1; | |
128 | } | |
129 | spin_lock(&g_CAM_CALLock); //for SMP | |
130 | g_pstI2Cclient->addr = g_pstI2Cclient->addr & I2C_MASK_FLAG; | |
131 | spin_unlock(&g_CAM_CALLock); // for SMP | |
132 | ||
133 | //CAM_CALDB("[CAM_CAL] iReadCAM_CAL done!! \n"); | |
134 | return 0; | |
135 | } | |
136 | ||
137 | ||
138 | static int iWriteData(unsigned int ui4_offset, unsigned int ui4_length, unsigned char * pinputdata) | |
139 | { | |
140 | int i4RetValue = 0; | |
141 | int i4ResidueDataLength; | |
142 | u32 u4IncOffset = 0; | |
143 | u32 u4CurrentOffset; | |
144 | u8 * pBuff; | |
145 | ||
146 | CAM_CALDB("[CAM_CAL] iWriteData\n" ); | |
147 | ||
148 | ||
149 | if (ui4_offset + ui4_length >= 0x2000) | |
150 | { | |
151 | CAM_CALDB("[CAM_CAL] Write Error!! S-24CS64A not supprt address >= 0x2000!! \n" ); | |
152 | return -1; | |
153 | } | |
154 | ||
155 | i4ResidueDataLength = (int)ui4_length; | |
156 | u4CurrentOffset = ui4_offset; | |
157 | pBuff = pinputdata; | |
158 | CAM_CALDB("[CAM_CAL] iWriteData u4CurrentOffset is %d \n",u4CurrentOffset); | |
159 | do | |
160 | { | |
161 | if(i4ResidueDataLength >= 6) | |
162 | { | |
163 | i4RetValue = iWriteCAM_CAL((u16)u4CurrentOffset, 6, pBuff); | |
164 | if (i4RetValue != 0) | |
165 | { | |
166 | CAM_CALDB("[CAM_CAL] I2C iWriteData failed!! \n"); | |
167 | return -1; | |
168 | } | |
169 | u4IncOffset += 6; | |
170 | i4ResidueDataLength -= 6; | |
171 | u4CurrentOffset = ui4_offset + u4IncOffset; | |
172 | pBuff = pinputdata + u4IncOffset; | |
173 | } | |
174 | else | |
175 | { | |
176 | i4RetValue = iWriteCAM_CAL((u16)u4CurrentOffset, i4ResidueDataLength, pBuff); | |
177 | if (i4RetValue != 0) | |
178 | { | |
179 | CAM_CALDB("[CAM_CAL] I2C iWriteData failed!! \n"); | |
180 | return -1; | |
181 | } | |
182 | u4IncOffset += 6; | |
183 | i4ResidueDataLength -= 6; | |
184 | u4CurrentOffset = ui4_offset + u4IncOffset; | |
185 | pBuff = pinputdata + u4IncOffset; | |
186 | //break; | |
187 | } | |
188 | }while (i4ResidueDataLength > 0); | |
189 | CAM_CALDB("[CAM_CAL] iWriteData done\n" ); | |
190 | ||
191 | return 0; | |
192 | } | |
193 | ||
194 | //int iReadData(stCAM_CAL_INFO_STRUCT * st_pOutputBuffer) | |
195 | static int iReadData(unsigned int ui4_offset, unsigned int ui4_length, unsigned char * pinputdata) | |
196 | { | |
197 | int i4RetValue = 0; | |
198 | int i4ResidueDataLength; | |
199 | u32 u4IncOffset = 0; | |
200 | u32 u4CurrentOffset; | |
201 | u8 * pBuff; | |
202 | CAM_CALDB("[CAM_CAL] iReadData \n" ); | |
203 | ||
204 | if (ui4_offset + ui4_length >= 0x2000) | |
205 | { | |
206 | CAM_CALDB("[CAM_CAL] Read Error!! S-24CS64A not supprt address >= 0x2000!! \n" ); | |
207 | return -1; | |
208 | } | |
209 | ||
210 | i4ResidueDataLength = (int)ui4_length; | |
211 | u4CurrentOffset = ui4_offset; | |
212 | pBuff = pinputdata; | |
213 | do | |
214 | { | |
215 | if(i4ResidueDataLength >= 8) | |
216 | { | |
217 | i4RetValue = iReadCAM_CAL((u16)u4CurrentOffset, 8, pBuff); | |
218 | if (i4RetValue != 0) | |
219 | { | |
220 | CAM_CALDB("[CAM_CAL] I2C iReadData failed!! \n"); | |
221 | return -1; | |
222 | } | |
223 | u4IncOffset += 8; | |
224 | i4ResidueDataLength -= 8; | |
225 | u4CurrentOffset = ui4_offset + u4IncOffset; | |
226 | pBuff = pinputdata + u4IncOffset; | |
227 | } | |
228 | else | |
229 | { | |
230 | i4RetValue = iReadCAM_CAL((u16)u4CurrentOffset, i4ResidueDataLength, pBuff); | |
231 | if (i4RetValue != 0) | |
232 | { | |
233 | CAM_CALDB("[CAM_CAL] I2C iReadData failed!! \n"); | |
234 | return -1; | |
235 | } | |
236 | u4IncOffset += 8; | |
237 | i4ResidueDataLength -= 8; | |
238 | u4CurrentOffset = ui4_offset + u4IncOffset; | |
239 | pBuff = pinputdata + u4IncOffset; | |
240 | //break; | |
241 | } | |
242 | }while (i4ResidueDataLength > 0); | |
243 | //fix warning MSG CAM_CALDB("[CAM_CAL] iReadData finial address is %d length is %d buffer address is 0x%x\n",u4CurrentOffset, i4ResidueDataLength, pBuff); | |
244 | CAM_CALDB("[CAM_CAL] iReadData done\n" ); | |
245 | return 0; | |
246 | } | |
247 | ||
248 | ||
249 | /******************************************************************************* | |
250 | * | |
251 | ********************************************************************************/ | |
252 | #define NEW_UNLOCK_IOCTL | |
253 | #ifndef NEW_UNLOCK_IOCTL | |
254 | static int CAM_CAL_Ioctl(struct inode * a_pstInode, | |
255 | struct file * a_pstFile, | |
256 | unsigned int a_u4Command, | |
257 | unsigned long a_u4Param) | |
258 | #else | |
259 | static long CAM_CAL_Ioctl( | |
260 | struct file *file, | |
261 | unsigned int a_u4Command, | |
262 | unsigned long a_u4Param | |
263 | ) | |
264 | #endif | |
265 | { | |
266 | int i4RetValue = 0; | |
267 | u8 * pBuff = NULL; | |
268 | u8 * pWorkingBuff = NULL; | |
269 | stCAM_CAL_INFO_STRUCT *ptempbuf; | |
270 | ||
271 | #ifdef CAM_CALGETDLT_DEBUG | |
272 | struct timeval ktv1, ktv2; | |
273 | unsigned long TimeIntervalUS; | |
274 | #endif | |
275 | ||
276 | if(_IOC_NONE == _IOC_DIR(a_u4Command)) | |
277 | { | |
278 | } | |
279 | else | |
280 | { | |
281 | pBuff = (u8 *)kmalloc(sizeof(stCAM_CAL_INFO_STRUCT),GFP_KERNEL); | |
282 | ||
283 | if(NULL == pBuff) | |
284 | { | |
285 | CAM_CALDB("[CAM_CAL] ioctl allocate mem failed\n"); | |
286 | return -ENOMEM; | |
287 | } | |
288 | ||
289 | if(_IOC_WRITE & _IOC_DIR(a_u4Command)) | |
290 | { | |
291 | if(copy_from_user((u8 *) pBuff , (u8 *) a_u4Param, sizeof(stCAM_CAL_INFO_STRUCT))) | |
292 | { //get input structure address | |
293 | kfree(pBuff); | |
294 | CAM_CALDB("[CAM_CAL] ioctl copy from user failed\n"); | |
295 | return -EFAULT; | |
296 | } | |
297 | } | |
298 | } | |
299 | ||
300 | ptempbuf = (stCAM_CAL_INFO_STRUCT *)pBuff; | |
301 | pWorkingBuff = (u8*)kmalloc(ptempbuf->u4Length,GFP_KERNEL); | |
302 | if(NULL == pWorkingBuff) | |
303 | { | |
304 | kfree(pBuff); | |
305 | CAM_CALDB("[CAM_CAL] ioctl allocate mem failed\n"); | |
306 | return -ENOMEM; | |
307 | } | |
308 | //fix warning MSG CAM_CALDB("[CAM_CAL] init Working buffer address 0x%x command is 0x%08x\n", pWorkingBuff, a_u4Command); | |
309 | ||
310 | ||
311 | if(copy_from_user((u8*)pWorkingBuff , (u8*)ptempbuf->pu1Params, ptempbuf->u4Length)) | |
312 | { | |
313 | kfree(pBuff); | |
314 | kfree(pWorkingBuff); | |
315 | CAM_CALDB("[CAM_CAL] ioctl copy from user failed\n"); | |
316 | return -EFAULT; | |
317 | } | |
318 | ||
319 | switch(a_u4Command) | |
320 | { | |
321 | case CAM_CALIOC_S_WRITE: | |
322 | CAM_CALDB("[CAM_CAL] Write CMD \n"); | |
323 | #ifdef CAM_CALGETDLT_DEBUG | |
324 | do_gettimeofday(&ktv1); | |
325 | #endif | |
326 | i4RetValue = iWriteData((u16)ptempbuf->u4Offset, ptempbuf->u4Length, pWorkingBuff); | |
327 | #ifdef CAM_CALGETDLT_DEBUG | |
328 | do_gettimeofday(&ktv2); | |
329 | if(ktv2.tv_sec > ktv1.tv_sec) | |
330 | { | |
331 | TimeIntervalUS = ktv1.tv_usec + 1000000 - ktv2.tv_usec; | |
332 | } | |
333 | else | |
334 | { | |
335 | TimeIntervalUS = ktv2.tv_usec - ktv1.tv_usec; | |
336 | } | |
337 | printk("Write data %d bytes take %lu us\n",ptempbuf->u4Length, TimeIntervalUS); | |
338 | #endif | |
339 | break; | |
340 | case CAM_CALIOC_G_READ: | |
341 | CAM_CALDB("[CAM_CAL] Read CMD \n"); | |
342 | #ifdef CAM_CALGETDLT_DEBUG | |
343 | do_gettimeofday(&ktv1); | |
344 | #endif | |
345 | CAM_CALDB("[CAM_CAL] offset %d \n", ptempbuf->u4Offset); | |
346 | CAM_CALDB("[CAM_CAL] length %d \n", ptempbuf->u4Length); | |
347 | //fix warning MSG CAM_CALDB("[CAM_CAL] Before read Working buffer address 0x%x \n", pWorkingBuff); | |
348 | ||
349 | i4RetValue = iReadData((u16)ptempbuf->u4Offset, ptempbuf->u4Length, pWorkingBuff); | |
350 | //fix warning MSG CAM_CALDB("[CAM_CAL] After read Working buffer address 0x%x \n", pWorkingBuff); | |
351 | ||
352 | ||
353 | #ifdef CAM_CALGETDLT_DEBUG | |
354 | do_gettimeofday(&ktv2); | |
355 | if(ktv2.tv_sec > ktv1.tv_sec) | |
356 | { | |
357 | TimeIntervalUS = ktv1.tv_usec + 1000000 - ktv2.tv_usec; | |
358 | } | |
359 | else | |
360 | { | |
361 | TimeIntervalUS = ktv2.tv_usec - ktv1.tv_usec; | |
362 | } | |
363 | printk("Read data %d bytes take %lu us\n",ptempbuf->u4Length, TimeIntervalUS); | |
364 | #endif | |
365 | ||
366 | break; | |
367 | default : | |
368 | CAM_CALDB("[CAM_CAL] No CMD \n"); | |
369 | i4RetValue = -EPERM; | |
370 | break; | |
371 | } | |
372 | ||
373 | if(_IOC_READ & _IOC_DIR(a_u4Command)) | |
374 | { | |
375 | //copy data to user space buffer, keep other input paremeter unchange. | |
376 | CAM_CALDB("[CAM_CAL] to user length %d \n", ptempbuf->u4Length); | |
377 | //fix warning MSG CAM_CALDB("[CAM_CAL] to user Working buffer address 0x%x \n", pWorkingBuff); | |
378 | if(copy_to_user((u8 __user *) ptempbuf->pu1Params , (u8 *)pWorkingBuff , ptempbuf->u4Length)) | |
379 | { | |
380 | kfree(pBuff); | |
381 | kfree(pWorkingBuff); | |
382 | CAM_CALDB("[CAM_CAL] ioctl copy to user failed\n"); | |
383 | return -EFAULT; | |
384 | } | |
385 | } | |
386 | ||
387 | kfree(pBuff); | |
388 | kfree(pWorkingBuff); | |
389 | return i4RetValue; | |
390 | } | |
391 | ||
392 | ||
393 | static u32 g_u4Opened = 0; | |
394 | //#define | |
395 | //Main jobs: | |
396 | // 1.check for device-specified errors, device not ready. | |
397 | // 2.Initialize the device if it is opened for the first time. | |
398 | static int CAM_CAL_Open(struct inode * a_pstInode, struct file * a_pstFile) | |
399 | { | |
400 | CAM_CALDB("[S24CAM_CAL] CAM_CAL_Open\n"); | |
401 | spin_lock(&g_CAM_CALLock); | |
402 | if(g_u4Opened) | |
403 | { | |
404 | spin_unlock(&g_CAM_CALLock); | |
405 | return -EBUSY; | |
406 | } | |
407 | else | |
408 | { | |
409 | g_u4Opened = 1; | |
410 | atomic_set(&g_CAM_CALatomic,0); | |
411 | } | |
412 | spin_unlock(&g_CAM_CALLock); | |
413 | ||
414 | //#if defined(MT6572) | |
415 | // do nothing | |
416 | //#else | |
417 | //if(TRUE != hwPowerOn(MT65XX_POWER_LDO_VCAMA, VOL_2800, "S24CS64A")) | |
418 | //{ | |
419 | // CAM_CALDB("[CAM_CAL] Fail to enable analog gain\n"); | |
420 | // return -EIO; | |
421 | //} | |
422 | //#endif | |
423 | ||
424 | return 0; | |
425 | } | |
426 | ||
427 | //Main jobs: | |
428 | // 1.Deallocate anything that "open" allocated in private_data. | |
429 | // 2.Shut down the device on last close. | |
430 | // 3.Only called once on last time. | |
431 | // Q1 : Try release multiple times. | |
432 | static int CAM_CAL_Release(struct inode * a_pstInode, struct file * a_pstFile) | |
433 | { | |
434 | spin_lock(&g_CAM_CALLock); | |
435 | ||
436 | g_u4Opened = 0; | |
437 | ||
438 | atomic_set(&g_CAM_CALatomic,0); | |
439 | ||
440 | spin_unlock(&g_CAM_CALLock); | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | static const struct file_operations g_stCAM_CAL_fops = | |
446 | { | |
447 | .owner = THIS_MODULE, | |
448 | .open = CAM_CAL_Open, | |
449 | .release = CAM_CAL_Release, | |
450 | //.ioctl = CAM_CAL_Ioctl | |
451 | .unlocked_ioctl = CAM_CAL_Ioctl | |
452 | }; | |
453 | ||
454 | #define CAM_CAL_DYNAMIC_ALLOCATE_DEVNO 1 | |
455 | inline static int RegisterCAM_CALCharDrv(void) | |
456 | { | |
457 | struct device* CAM_CAL_device = NULL; | |
458 | ||
459 | #if CAM_CAL_DYNAMIC_ALLOCATE_DEVNO | |
460 | if( alloc_chrdev_region(&g_CAM_CALdevno, 0, 1,CAM_CAL_DRVNAME) ) | |
461 | { | |
462 | CAM_CALDB("[CAM_CAL] Allocate device no failed\n"); | |
463 | ||
464 | return -EAGAIN; | |
465 | } | |
466 | #else | |
467 | if( register_chrdev_region( g_CAM_CALdevno , 1 , CAM_CAL_DRVNAME) ) | |
468 | { | |
469 | CAM_CALDB("[CAM_CAL] Register device no failed\n"); | |
470 | ||
471 | return -EAGAIN; | |
472 | } | |
473 | #endif | |
474 | ||
475 | //Allocate driver | |
476 | g_pCAM_CAL_CharDrv = cdev_alloc(); | |
477 | ||
478 | if(NULL == g_pCAM_CAL_CharDrv) | |
479 | { | |
480 | unregister_chrdev_region(g_CAM_CALdevno, 1); | |
481 | ||
482 | CAM_CALDB("[CAM_CAL] Allocate mem for kobject failed\n"); | |
483 | ||
484 | return -ENOMEM; | |
485 | } | |
486 | ||
487 | //Attatch file operation. | |
488 | cdev_init(g_pCAM_CAL_CharDrv, &g_stCAM_CAL_fops); | |
489 | ||
490 | g_pCAM_CAL_CharDrv->owner = THIS_MODULE; | |
491 | ||
492 | //Add to system | |
493 | if(cdev_add(g_pCAM_CAL_CharDrv, g_CAM_CALdevno, 1)) | |
494 | { | |
495 | CAM_CALDB("[CAM_CAL] Attatch file operation failed\n"); | |
496 | ||
497 | unregister_chrdev_region(g_CAM_CALdevno, 1); | |
498 | ||
499 | return -EAGAIN; | |
500 | } | |
501 | ||
502 | CAM_CAL_class = class_create(THIS_MODULE, "CAM_CALdrv"); | |
503 | if (IS_ERR(CAM_CAL_class)) { | |
504 | int ret = PTR_ERR(CAM_CAL_class); | |
505 | CAM_CALDB("Unable to create class, err = %d\n", ret); | |
506 | return ret; | |
507 | } | |
508 | CAM_CAL_device = device_create(CAM_CAL_class, NULL, g_CAM_CALdevno, NULL, CAM_CAL_DRVNAME); | |
509 | ||
510 | return 0; | |
511 | } | |
512 | ||
513 | inline static void UnregisterCAM_CALCharDrv(void) | |
514 | { | |
515 | //Release char driver | |
516 | cdev_del(g_pCAM_CAL_CharDrv); | |
517 | ||
518 | unregister_chrdev_region(g_CAM_CALdevno, 1); | |
519 | ||
520 | device_destroy(CAM_CAL_class, g_CAM_CALdevno); | |
521 | class_destroy(CAM_CAL_class); | |
522 | } | |
523 | ||
524 | ||
525 | ////////////////////////////////////////////////////////////////////// | |
526 | #ifndef CAM_CAL_ICS_REVISION | |
527 | static int CAM_CAL_i2c_detect(struct i2c_client *client, int kind, struct i2c_board_info *info); | |
528 | #elif 0 | |
529 | static int CAM_CAL_i2c_detect(struct i2c_client *client, struct i2c_board_info *info); | |
530 | #else | |
531 | #endif | |
532 | static int CAM_CAL_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); | |
533 | static int CAM_CAL_i2c_remove(struct i2c_client *); | |
534 | ||
535 | static const struct i2c_device_id CAM_CAL_i2c_id[] = {{CAM_CAL_DRVNAME,0},{}}; | |
536 | #if 0 //test110314 Please use the same I2C Group ID as Sensor | |
537 | static unsigned short force[] = {CAM_CAL_I2C_GROUP_ID, S24CS64A_DEVICE_ID, I2C_CLIENT_END, I2C_CLIENT_END}; | |
538 | #else | |
539 | //static unsigned short force[] = {CAM_CAL_I2C_GROUP_ID, S24CS64A_DEVICE_ID, I2C_CLIENT_END, I2C_CLIENT_END}; | |
540 | #endif | |
541 | //static const unsigned short * const forces[] = { force, NULL }; | |
542 | //static struct i2c_client_address_data addr_data = { .forces = forces,}; | |
543 | ||
544 | ||
545 | static struct i2c_driver CAM_CAL_i2c_driver = { | |
546 | .probe = CAM_CAL_i2c_probe, | |
547 | .remove = CAM_CAL_i2c_remove, | |
548 | // .detect = CAM_CAL_i2c_detect, | |
549 | .driver.name = CAM_CAL_DRVNAME, | |
550 | .id_table = CAM_CAL_i2c_id, | |
551 | }; | |
552 | ||
553 | #ifndef CAM_CAL_ICS_REVISION | |
554 | static int CAM_CAL_i2c_detect(struct i2c_client *client, int kind, struct i2c_board_info *info) { | |
555 | strcpy(info->type, CAM_CAL_DRVNAME); | |
556 | return 0; | |
557 | } | |
558 | #endif | |
559 | static int CAM_CAL_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { | |
560 | int i4RetValue = 0; | |
561 | CAM_CALDB("[CAM_CAL] Attach I2C \n"); | |
562 | // spin_lock_init(&g_CAM_CALLock); | |
563 | ||
564 | //get sensor i2c client | |
565 | spin_lock(&g_CAM_CALLock); //for SMP | |
566 | g_pstI2Cclient = client; | |
567 | g_pstI2Cclient->addr = S24CS64A_DEVICE_ID>>1; | |
568 | spin_unlock(&g_CAM_CALLock); // for SMP | |
569 | ||
570 | CAM_CALDB("[CAM_CAL] g_pstI2Cclient->addr = 0x%8x \n",g_pstI2Cclient->addr); | |
571 | //Register char driver | |
572 | i4RetValue = RegisterCAM_CALCharDrv(); | |
573 | ||
574 | if(i4RetValue){ | |
575 | CAM_CALDB("[CAM_CAL] register char device failed!\n"); | |
576 | return i4RetValue; | |
577 | } | |
578 | ||
579 | ||
580 | CAM_CALDB("[CAM_CAL] Attached!! \n"); | |
581 | return 0; | |
582 | } | |
583 | ||
584 | static int CAM_CAL_i2c_remove(struct i2c_client *client) | |
585 | { | |
586 | return 0; | |
587 | } | |
588 | ||
589 | static int CAM_CAL_probe(struct platform_device *pdev) | |
590 | { | |
591 | return i2c_add_driver(&CAM_CAL_i2c_driver); | |
592 | } | |
593 | ||
594 | static int CAM_CAL_remove(struct platform_device *pdev) | |
595 | { | |
596 | i2c_del_driver(&CAM_CAL_i2c_driver); | |
597 | return 0; | |
598 | } | |
599 | ||
600 | // platform structure | |
601 | static struct platform_driver g_stCAM_CAL_Driver = { | |
602 | .probe = CAM_CAL_probe, | |
603 | .remove = CAM_CAL_remove, | |
604 | .driver = { | |
605 | .name = CAM_CAL_DRVNAME, | |
606 | .owner = THIS_MODULE, | |
607 | } | |
608 | }; | |
609 | ||
610 | ||
611 | static struct platform_device g_stCAM_CAL_Device = { | |
612 | .name = CAM_CAL_DRVNAME, | |
613 | .id = 0, | |
614 | .dev = { | |
615 | } | |
616 | }; | |
617 | ||
618 | static int __init CAM_CAL_i2C_init(void) | |
619 | { | |
620 | i2c_register_board_info(CAM_CAL_I2C_BUSNUM, &kd_cam_cal_dev, 1); | |
621 | if(platform_driver_register(&g_stCAM_CAL_Driver)){ | |
622 | CAM_CALDB("failed to register CAM_CAL driver\n"); | |
623 | return -ENODEV; | |
624 | } | |
625 | ||
626 | if (platform_device_register(&g_stCAM_CAL_Device)) | |
627 | { | |
628 | CAM_CALDB("failed to register CAM_CAL driver\n"); | |
629 | return -ENODEV; | |
630 | } | |
631 | ||
632 | return 0; | |
633 | } | |
634 | ||
635 | static void __exit CAM_CAL_i2C_exit(void) | |
636 | { | |
637 | platform_driver_unregister(&g_stCAM_CAL_Driver); | |
638 | } | |
639 | ||
640 | module_init(CAM_CAL_i2C_init); | |
641 | module_exit(CAM_CAL_i2C_exit); | |
642 | ||
643 | MODULE_DESCRIPTION("CAM_CAL driver"); | |
644 | MODULE_AUTHOR("Sean Lin <Sean.Lin@Mediatek.com>"); | |
645 | MODULE_LICENSE("GPL"); | |
646 | ||
647 |