import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / isp.c
1 /******************************************************************************
2 * isp.c - MT6589 Linux ISP Device Driver
3 *
4 * Copyright 2008-2009 MediaTek Co.,Ltd.
5 *
6 * DESCRIPTION:
7 * This file provid the other drivers ISP relative functions
8 *
9 ******************************************************************************/
10
11 #include <linux/types.h>
12 #include <linux/device.h>
13 #include <linux/cdev.h>
14 #include <linux/platform_device.h>
15 #include <linux/interrupt.h>
16 #include <asm/io.h>
17 //seanlin 111223 fix conpilier error #include <asm/tcm.h>
18 #include <linux/proc_fs.h> //proc file use
19 //
20 #include <linux/spinlock.h>
21 #include <linux/io.h>
22 #include <linux/delay.h>
23 #include <linux/uaccess.h>
24 #include <asm/atomic.h>
25 #include <linux/sched.h>
26 #include <linux/mm.h>
27 //
28 #include <mach/mt_reg_base.h> //seanlin 111223 fix conpilier error #include <mach/hardware.h>
29
30 //#include <mach/mt6575_pll.h>
31 #include <mach/isp.h> //seanlin 111223
32 //
33
34 /*******************************************************************************
35 *
36 ********************************************************************************/
37 #define ISP_TAG "[ISP] "
38 #define ISP_LOG(fmt, arg...) printk(ISP_TAG fmt, ##arg)//printk()//seanlin@110715
39 #define ISP_ERR(fmt, arg...) printk(ISP_TAG "Err: %5d:, "fmt, __LINE__, ##arg)
40 //
41 #define ISP_WR32(addr, data) iowrite32(data, addr)
42 #define ISP_RD32(addr) ioread32(addr)
43 #define ISP_SET_BIT(reg, bit) ((*(volatile u32*)(reg)) |= (u32)(1 << (bit)))
44 #define ISP_CLR_BIT(reg, bit) ((*(volatile u32*)(reg)) &= ~((u32)(1 << (bit))))
45 //
46 #define ISP_BASE CAMINF_BASE
47 #define ISP_BASE_SHIFT (CAMINF_BASE+0x4000) //seanlin 120105
48 #define ISP_DEV_NAME "mt-isp" // senalin111228 "mt6589-isp"
49
50 /*******************************************************************************
51 *
52 ********************************************************************************/
53 // Register definition
54 #define ISP_PHSCNT (ISP_BASE + 0x000)
55 #define ISP_VFCON (ISP_BASE + 0x018)
56 #define ISP_INTEN (ISP_BASE + 0x01c)
57 #define ISP_INTSTA (ISP_BASE + 0x020)
58 #define ISP_PATH (ISP_BASE + 0x024)
59 #define ISP_RAWGAIN0 (ISP_BASE + 0x16C)
60 #define ISP_RAWGAIN1 (ISP_BASE + 0x170)
61 #define ISP_RESET (ISP_BASE + 0x1D8)
62 #define ISP_TGSTATUS (ISP_BASE + 0x1DC)
63 #define ISP_SHADING1 (ISP_BASE + 0x214)
64 #define ISP_VERSION (ISP_BASE + 0x274)
65 //
66 #define ISP_G1MEMPDN (MMSYS1_CONFIG_BASE + 0x30c)
67 //
68
69 #define ISP_INT_OVERRUN_MASK ((u32)0x6)
70 #define ISP_INT_EXP_DONE ((u32)0x1)
71 #define ISP_INT_IDLE ((u32)0x1 << 3)
72 #define ISP_INT_ISP_DONE ((u32)0x1 << 4)
73 #define ISP_INT_VSYNC ((u32)0x1 << 10)
74
75 #define ISP_DBG_INT 0x0001
76 #define ISP_DBG_HOLD_REG 0x0002
77 #define ISP_DBG_READ_REG 0x0004
78 #define ISP_DBG_WRITE_REG 0x0008
79 #define ISP_DBG_CLK 0x0010
80 #define ISP_DBG_TASKLET 0x0020
81 #define ISP_DBG_WORKQUEUE 0x0040
82 //
83 /*******************************************************************************
84 *
85 ********************************************************************************/
86 static spinlock_t isp_lock;
87 static u8 *pcmd_buf = NULL;
88 static u8 *pread_buf = NULL;
89 static u8 *pwrite_buf = NULL;
90 static u32 buf_size = 4096;
91 static atomic_t hold_reg;
92 static atomic_t writing_reg;
93 static u32 hold_count;
94 static wait_queue_head_t isp_wait_queue;
95 static u32 irq_status;
96 static u32 dbgMask = 0x000000FF;
97 static struct work_struct isp_work_queue;
98
99 /*******************************************************************************
100 *
101 ********************************************************************************/
102 static unsigned long ms_to_jiffies(unsigned long ms)
103 {
104 return ((ms * HZ + 512) >> 10);
105 }
106
107 /*******************************************************************************
108 *
109 ********************************************************************************/
110 static int mt_isp_clk_ctrl(int en)
111 {
112 if (dbgMask & ISP_DBG_CLK) {
113 ISP_LOG("[mt_isp_clk_ctrl] %d \n", en);
114 }
115 //
116 if (en) {
117 //hwEnableClock(MT65XX_PDN_MM_ISP, "ISP");
118 //hwEnableClock(MT65XX_PDN_MM_RESZ_LB, "ISP");
119 // ISP_CLR_BIT(ISP_G1MEMPDN, 9);
120 }
121 else {
122 //hwDisableClock(MT65XX_PDN_MM_ISP, "ISP");
123 //hwDisableClock(MT65XX_PDN_MM_RESZ_LB, "ISP");
124 // ISP_SET_BIT(ISP_G1MEMPDN, 9);
125 }
126
127 return 0;
128 }
129
130 /*******************************************************************************
131 *
132 ********************************************************************************/
133 static inline void mt_isp_reset(void)
134 {
135 #if 0 //seanlin 111226
136 // ensure the view finder is disabe
137 ISP_CLR_BIT(ISP_VFCON, 6);
138 // do hw reset
139 ISP_WR32(ISP_RESET, 1);
140 // delay at least 100us for reset the ISp (HW suggest)
141 udelay(120);
142 ISP_WR32(ISP_RESET, 0);
143 //
144 irq_status = 0;
145 #endif
146 }
147
148 /*******************************************************************************
149 *
150 ********************************************************************************/
151 static int mt_isp_read_reg(mt_isp_reg_io_t *preg_io)
152 {
153 int ret = 0;
154 int size = preg_io->count * sizeof(mt_isp_reg_t);
155 mt_isp_reg_t *preg = (mt_isp_reg_t *) pread_buf;
156 int i;
157
158 if (dbgMask & ISP_DBG_READ_REG) {
159 // ISP_LOG("[mt_isp_read_reg] data: 0x%x, count: %d \n", (u32) preg_io->data, (u32) preg_io->count);
160 }
161 //
162 if (size > buf_size) {
163 ISP_ERR("size too big \n");
164 }
165 //
166 if (copy_from_user((u8 *)preg, (u8 *) preg_io->data, size) != 0) {
167 ISP_ERR("copy_from_user failed \n");
168 ret = -EFAULT;
169 goto mt_isp_read_reg_exit;
170 }
171 //
172 for (i = 0; i < preg_io->count; i++) {
173 preg[i].val = ISP_RD32(ISP_BASE + preg[i].addr);
174 if (dbgMask & ISP_DBG_READ_REG) {
175 // ISP_LOG(" addr/val: 0x%08x/0x%08x \n", (u32) (ISP_BASE + preg[i].addr), (u32) preg[i].val);
176 }
177 }
178 //
179 if (copy_to_user((u8 *) preg_io->data, (u8 *) preg, size) != 0) {
180 ISP_ERR("copy_to_user failed \n");
181 ret = -EFAULT;
182 goto mt_isp_read_reg_exit;
183 }
184
185 mt_isp_read_reg_exit:
186
187 return ret;
188 }
189
190 /*******************************************************************************
191 *
192 ********************************************************************************/
193 static int mt_isp_write_reg_to_hw(mt_isp_reg_t *preg, u32 count)
194 {
195 int ret = 0;
196 int i;
197
198 if (dbgMask & ISP_DBG_WRITE_REG) {
199 //seanlin ISP_LOG("[mt_isp_write_reg_to_hw] \n");
200 }
201 //
202 for (i = 0; i < count; i++) {
203 if (dbgMask & ISP_DBG_WRITE_REG) {
204 //seanlin ISP_LOG(" addr/val: 0x%08x/0x%08x \n", (u32) (ISP_BASE + preg[i].addr), (u32) preg[i].val);
205 }
206 if(preg[i].addr<0xa000) //seanlin if(preg[i].addr<0x7100) //seanlin
207 {
208 ISP_WR32(ISP_BASE + preg[i].addr, preg[i].val);
209 }
210 else
211 {
212 ISP_LOG("SKIP 0x%8x\n",preg[i].addr); //seanlin 120103
213 }
214 }
215
216 return ret;
217 }
218
219 /*******************************************************************************
220 *
221 ********************************************************************************/
222 void mt_isp_tasklet_write_reg(unsigned long arg)
223 {
224 mt_isp_reg_t *preg = (mt_isp_reg_t *) pwrite_buf;
225
226 if (dbgMask & ISP_DBG_HOLD_REG) {
227 //seanlin ISP_LOG("[mt_isp_tasklet_write_reg] preg: 0x%x, count: %d \n", (u32) preg, hold_count);
228 }
229 //
230 mt_isp_write_reg_to_hw(preg, hold_count);
231 hold_count = 0;
232 //
233 atomic_set(&writing_reg , 0);
234 wake_up_interruptible(&isp_wait_queue);
235 }
236
237 DECLARE_TASKLET(tasklet_write_reg, mt_isp_tasklet_write_reg, 0);
238
239 /*******************************************************************************
240 *
241 ********************************************************************************/
242 //extern int kdSensorSyncFunctionPtr(UINT16 *pRAWGain);
243 //extern int kdSetSensorSyncFlag(BOOL bSensorSync);
244 void mt_isp_work_queue(unsigned long param)
245 {
246 u16 rawGain[4];
247
248 // Synchronization the exposure time, sensor gain and raw gain.
249 //kdSensorSyncFunctionPtr(&rawGain[0]);
250 //kdSetSensorSyncFlag(FALSE);
251 //
252 if ((rawGain[0] != 0) && (rawGain[1] != 0) && (rawGain[2] != 0) && (rawGain[3] != 0) ) {
253 ISP_WR32(ISP_RAWGAIN0, ((u32) rawGain[0] << 0) | ((u32) rawGain[1] << 16));
254 ISP_WR32(ISP_RAWGAIN1, ((u32) rawGain[2] << 0) | ((u32) rawGain[3] << 16));
255 }
256 }
257
258 /*******************************************************************************
259 *
260 ********************************************************************************/
261 static int mt_isp_write_reg(mt_isp_reg_io_t *preg_io)
262 {
263 int ret = 0;
264 int size = preg_io->count * sizeof(mt_isp_reg_t);
265 int hold_size = hold_count * sizeof(mt_isp_reg_t);
266 mt_isp_reg_t *preg = (mt_isp_reg_t *) (pwrite_buf + hold_size);
267
268 if (dbgMask & ISP_DBG_WRITE_REG) {
269 //seanlin ISP_LOG("[mt_isp_write_reg] data: 0x%x, count: %d \n", (u32) preg_io->data, (u32) preg_io->count);
270 }
271 //
272 if (atomic_read(&hold_reg)) {
273 if (atomic_read(&writing_reg)) {
274 int timeout;
275 // Should wait until write done
276 if (dbgMask & ISP_DBG_TASKLET) {
277 //seanlin ISP_LOG("[mt_isp_write_reg] Start wait ... \n");
278 }
279 timeout = wait_event_interruptible_timeout(
280 isp_wait_queue, atomic_read(&writing_reg) == 0 , ms_to_jiffies(500));
281 if (dbgMask & ISP_DBG_TASKLET) {
282 //seanlin ISP_LOG("[mt_isp_write_reg] End wait \n");
283 }
284 if (timeout == 0) {
285 ISP_ERR("Should not happen \n");
286 ret = -EFAULT;
287 goto mt_isp_write_reg_exit;
288 }
289 }
290 }
291 //
292 if ((size + hold_size) > buf_size) {
293 ISP_ERR("size too big \n");
294 ret = -EFAULT;
295 goto mt_isp_write_reg_exit;
296 }
297 //
298 if (copy_from_user((u8 *)preg, (u8 *) preg_io->data, size) != 0) {
299 ISP_ERR("copy_from_user failed \n");
300 ret = -EFAULT;
301 goto mt_isp_write_reg_exit;
302 }
303 //
304 if (atomic_read(&hold_reg)) {
305 // Write register to buffer
306 hold_count += preg_io->count;
307 }
308 else {
309 // Write register to hw
310 ret = mt_isp_write_reg_to_hw(preg, preg_io->count);
311 }
312 //
313 mt_isp_write_reg_exit:
314
315 return ret;
316 }
317
318 /*******************************************************************************
319 *
320 ********************************************************************************/
321 static int mt_isp_hold_reg(u32 is_hold)
322 {
323 int ret = 0;
324
325 if (dbgMask & ISP_DBG_HOLD_REG) {
326 ISP_LOG("[mt_isp_hold_reg] %d, %d \n", is_hold, atomic_read(&hold_reg));
327 }
328
329 if (is_hold == 0) {
330 if (atomic_read(&hold_reg)) {
331 // Hold is switching from on to off,
332 // Should write register to hw now
333 atomic_set(&writing_reg, 1);
334 }
335 }
336 atomic_set(&hold_reg, is_hold);
337
338 return ret;
339 }
340
341 /*******************************************************************************
342 *
343 ********************************************************************************/
344 static int mt_isp_wait_irq(u32 wait_irq_status)
345 {
346 int ret = 0;
347 int timeout;
348
349 if (dbgMask & ISP_DBG_INT) {
350 ISP_LOG("[mt_isp_wait_irq] \n" );
351 }
352
353 timeout = wait_event_interruptible_timeout(
354 isp_wait_queue, (wait_irq_status & irq_status), 3 * HZ);
355 if (timeout == 0) {
356 ISP_ERR("wait_event_interruptible_timeout timeout, %d, %d \n", wait_irq_status, irq_status);
357 return -EAGAIN;
358 }
359 //
360 spin_lock_irq(&isp_lock);
361 //
362 if (dbgMask & ISP_DBG_INT) {
363 ISP_LOG("irq_status: 0x%x \n", irq_status);
364 }
365 //
366 irq_status &= ~(wait_irq_status);
367 //
368 spin_unlock_irq(&isp_lock);
369
370 return ret;
371 }
372
373 /*******************************************************************************
374 *
375 ********************************************************************************/
376 static int mt_isp_dump_reg(void)
377 {
378 int ret = 0;
379 int i;
380
381 ISP_LOG("[mt_isp_dump_reg] E \n" );
382 //
383 spin_lock_irq(&isp_lock);
384 //
385 for (i = 0x4000; i < 0x5e10; i += 4) {
386 ISP_LOG(" addr, val: 0x%08x, 0x%08x \n", ISP_BASE+ i, ISP_RD32(ISP_BASE + i));
387 }
388 //
389 spin_unlock_irq(&isp_lock);
390 //
391 ISP_LOG("[mt_isp_dump_reg] X \n" );
392
393 return ret;
394 }
395 #if 0 // seanlin 111223 fix conpilier error
396 /*******************************************************************************
397 *
398 ********************************************************************************/
399 static __tcmfunc irqreturn_t mt_isp_irq(int irq, void *dev_id)
400 {
401 // Read irq status
402 irq_status |= ISP_RD32(ISP_INTSTA);
403
404 //if (dbgMask & ISP_DBG_INT) {
405 ISP_LOG("[mt_isp_irq] 0x%x \n", irq_status);
406 //}
407 //
408 if (irq_status & ISP_INT_OVERRUN_MASK) {
409 ISP_ERR("ISP_INT_OVERRUN_MASK: 0x%x \n", irq_status);
410 irq_status &= ~(ISP_INT_OVERRUN_MASK);
411 #if 0
412 //Incomplete frame error handling
413 if(ioread32((ROT_DMA0_BASE + 0x18)) >> 31)
414 {
415 ISP_LOG("Speed up ROTDMA0!!\n");
416 mt65xx_reg_sync_writel(0 , (ROT_DMA0_BASE + 0x300));
417 }
418 else if(ioread32((ROT_DMA1_BASE + 0x18)) >> 31)
419 {
420 ISP_LOG("Speed up ROTDMA1!!\n");
421 mt65xx_reg_sync_writel(0 , (ROT_DMA1_BASE + 0x300));
422 }
423 else if(ioread32((ROT_DMA2_BASE + 0x18)) >> 31)
424 {
425 ISP_LOG("Speed up ROTDMA2!!\n");
426 mt65xx_reg_sync_writel(0 , (ROT_DMA2_BASE + 0x300));
427 }
428 ISP_LOG("speed up ROTDMA done \n");
429 // ensure the view finder is disabe
430 ISP_CLR_BIT(ISP_VFCON, 6);
431 // do hw reset
432 //ISP_WR32(ISP_RESET, 1);
433 mt65xx_reg_sync_writel(0x10000,ISP_RESET);
434 //ISP_SET_BIT(ISP_RESET, 16); //SW reset
435 //ISP_SET_BIT(ISP_RESET, 0); //HW reset
436 // delay at least 100us for reset the ISp (HW suggest)
437 udelay(120);
438 //ISP_WR32(ISP_RESET, 0);
439 mt65xx_reg_sync_writel(0,ISP_RESET);
440 //ISP_CLR_BIT(ISP_RESET, 16); //SW reset
441 //ISP_CLR_BIT(ISP_RESET, 0); //HW reset
442 ISP_SET_BIT(ISP_VFCON, 6);
443 irq_status = 0;
444 ISP_LOG("ISP reset done\n");
445 #endif
446 }
447 //
448 wake_up_interruptible(&isp_wait_queue);
449 //
450 if (irq_status & ISP_INT_VSYNC) {
451 if (dbgMask & ISP_DBG_WORKQUEUE) {
452 ISP_LOG("[mt_isp_irq] schedule_work \n");
453 }
454 schedule_work(&isp_work_queue);
455 irq_status &= ~(ISP_INT_VSYNC);
456 }
457 // If ISP exp int is done, wake up tasklet to write register if it is buffered
458 if ((atomic_read(&writing_reg)) && (irq_status & ISP_INT_EXP_DONE)) {
459 if (dbgMask & ISP_DBG_TASKLET) {
460 ISP_LOG("[mt_isp_irq] tasklet_schedule \n");
461 }
462 tasklet_schedule(&tasklet_write_reg);
463 irq_status &= ~(ISP_INT_EXP_DONE);
464 }
465
466 return IRQ_HANDLED;
467 }
468 #endif
469 /*******************************************************************************
470 *
471 ********************************************************************************/
472 static long mt_isp_ioctl(struct file *file,
473 unsigned int cmd,
474 unsigned long arg)
475 {
476 int ret = 0;
477 //
478 if( pcmd_buf == NULL ||
479 pread_buf == NULL)
480 {
481 ISP_ERR("buf is null\n");
482 return -EFAULT;
483 }
484 if (_IOC_DIR(cmd) != _IOC_NONE) {
485 // IO write
486 if (_IOC_DIR(cmd) & _IOC_WRITE) {
487 if (copy_from_user(pcmd_buf, (void *) arg, _IOC_SIZE(cmd)) != 0) {
488 ISP_ERR("copy_from_user failed \n");
489 return -EFAULT;
490 }
491 }
492 }
493 //
494 switch (cmd) {
495 case MT_ISP_IOC_T_RESET:
496 ISP_LOG("[MT_ISP_IOC_T_RESET] \n");
497 mt_isp_reset();
498 break;
499 case MT_ISP_IOC_G_READ_REG:
500 ret = mt_isp_read_reg((mt_isp_reg_io_t *) pcmd_buf);
501 break;
502 case MT_ISP_IOC_S_WRITE_REG:
503 ret = mt_isp_write_reg((mt_isp_reg_io_t *) pcmd_buf);
504 break;
505 case MT_ISP_IOC_T_HOLD_REG:
506 ret = mt_isp_hold_reg(*(u32 *) pcmd_buf);
507 break;
508 //case MT_ISP_IOC_T_RUN:
509 // break;
510 case MT_ISP_IOC_T_WAIT_IRQ:
511 ret = mt_isp_wait_irq(*(u32 *) pcmd_buf);
512 break;
513 case MT_ISP_IOC_T_DUMP_REG:
514 ret = mt_isp_dump_reg();
515 break;
516 case MT_ISP_IOC_T_DBG_FLAG:
517 ISP_LOG("[MT_ISP_IOC_T_DBG_FLAG]: 0x%x \n", *(u32 *) pcmd_buf);
518 dbgMask = *(u32 *) pcmd_buf;
519 break;
520 default:
521 ISP_ERR("[mt_isp_ioctl] unknown cmd \n");
522 ret = -EPERM;
523 break;
524 }
525 //
526 if (_IOC_READ & _IOC_DIR(cmd)) {
527 if (copy_to_user((void __user *) arg, pcmd_buf , _IOC_SIZE(cmd)) != 0) {
528 ISP_ERR("copy_to_user failed \n");
529 return -EFAULT;
530 }
531 }
532
533 return ret;
534 }
535
536 /*******************************************************************************
537 *
538 ********************************************************************************/
539 static int mt_isp_open(struct inode *inode, struct file *file)
540 {
541 int ret = 0;
542
543 ISP_LOG("[mt_isp_open] \n");
544 //
545 spin_lock_irq(&isp_lock);
546 if (pcmd_buf) {
547 // Buffer has been allocated
548 ISP_ERR(" open more than once \n");
549 goto mt_isp_open_exit;
550 }
551 // Allocate buffer for cmd/read/write buffer
552 if (pcmd_buf != NULL) {
553 ISP_ERR("pcmd_buf is not null \n");
554 }
555 if (pread_buf != NULL) {
556 ISP_ERR("pread_buf is not null \n");
557 }
558 if (pwrite_buf != NULL) {
559 ISP_ERR("pread_buf is not null \n");
560 }
561 pcmd_buf = (u8 *) kmalloc(buf_size, GFP_KERNEL);
562 if (pcmd_buf == NULL) {
563 ISP_ERR("kmalloc failed \n ");
564 ret = -ENOMEM;
565 goto mt_isp_open_exit;
566 }
567 pread_buf = (u8 *) kmalloc(buf_size, GFP_KERNEL);
568 if (pread_buf == NULL) {
569 ISP_ERR("kmalloc failed \n ");
570 ret = -ENOMEM;
571 goto mt_isp_open_exit;
572 }
573 pwrite_buf = (u8 *) kmalloc(buf_size, GFP_KERNEL);
574 if (pwrite_buf == NULL) {
575 ISP_ERR("kmalloc failed \n ");
576 ret = -ENOMEM;
577 goto mt_isp_open_exit;
578 }
579 //
580 atomic_set(&hold_reg, 0);
581 atomic_set(&writing_reg, 0);
582 hold_count = 0;
583 irq_status = 0;
584 //
585 init_waitqueue_head(&isp_wait_queue);
586 //
587 INIT_WORK(&isp_work_queue, mt_isp_work_queue);
588 // Enable clock
589 mt_isp_clk_ctrl(1);
590
591 mt_isp_open_exit:
592 if (ret < 0) {
593 if (pcmd_buf) {
594 kfree(pcmd_buf);
595 pcmd_buf = NULL;
596 }
597 if (pread_buf) {
598 kfree(pread_buf);
599 pread_buf = NULL;
600 }
601 if (pwrite_buf) {
602 kfree(pwrite_buf);
603 pwrite_buf = NULL;
604 }
605 }
606
607 spin_unlock_irq(&isp_lock);
608
609 return ret;
610 }
611
612 /*******************************************************************************
613 *
614 ********************************************************************************/
615 static int mt_isp_release(struct inode *inode, struct file *file)
616 {
617 ISP_LOG("[mt_isp_release] \n");
618
619 //
620 mt_isp_clk_ctrl(0);
621 //
622 if (pcmd_buf) {
623 kfree(pcmd_buf);
624 pcmd_buf = NULL;
625 }
626 if (pread_buf) {
627 kfree(pread_buf);
628 pread_buf = NULL;
629 }
630 if (pwrite_buf) {
631 kfree(pwrite_buf);
632 pwrite_buf = NULL;
633 }
634
635 return 0;
636 }
637
638 /*******************************************************************************
639 *
640 ********************************************************************************/
641 static int mt_isp_mmap(struct file *file, struct vm_area_struct *vma)
642 {
643 // ISP_LOG("[mt_isp_mmap] \n");
644
645 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
646 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
647 vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
648 return -EAGAIN;
649 }
650
651 return 0;
652 }
653
654 /*******************************************************************************
655 *
656 ********************************************************************************/
657 static dev_t dev_isp;
658 static struct cdev *pcdev_isp = NULL;
659 static struct class *pclass_isp = NULL;
660 static const struct file_operations mt_isp_fops = {
661 .owner = THIS_MODULE,
662 .open = mt_isp_open,
663 .release = mt_isp_release,
664 //.flush = mt_isp_flush,
665 .mmap = mt_isp_mmap,
666 .unlocked_ioctl = mt_isp_ioctl
667 //seanlin 111223 fix conpilier error .ioctl = mt_isp_ioctl
668 };
669 static int isp_irq_num;
670
671 /*******************************************************************************
672 *
673 ********************************************************************************/
674 inline static void mt_isp_unregister_char_driver(void)
675 {
676 // ISP_LOG("[mt_isp_unregister_char_driver] \n");
677
678 //Release char driver
679 if (pcdev_isp != NULL) {
680 cdev_del(pcdev_isp);
681 pcdev_isp = NULL;
682 }
683 //
684 unregister_chrdev_region(dev_isp, 1);
685 }
686
687 /*******************************************************************************
688 *
689 ********************************************************************************/
690 inline static int mt_isp_register_char_driver(void)
691 {
692 int ret = 0;
693
694 ISP_LOG("[mt_isp_register_char_driver] \n");
695 //
696 if ( (ret = alloc_chrdev_region(&dev_isp, 0, 1, ISP_DEV_NAME)) < 0 ) {
697 ISP_ERR("alloc_chrdev_region failed, %d \n", ret);
698 ISP_LOG("[alloc_chrdev_region failed] \n");
699 return ret;
700 }
701 //Allocate driver
702 pcdev_isp = cdev_alloc();
703 if (pcdev_isp == NULL) {
704 ISP_ERR("cdev_alloc failed\n");
705 ISP_LOG("[cdev_alloc failed] \n");
706 ret = -ENOMEM;
707 goto mt_isp_register_char_driver_exit;
708 }
709 //Attatch file operation.
710 cdev_init(pcdev_isp, &mt_isp_fops);
711 //
712 pcdev_isp->owner = THIS_MODULE;
713 //Add to system
714 if ( (ret = cdev_add(pcdev_isp, dev_isp, 1)) < 0) {
715 ISP_ERR("Attatch file operation failed, %d \n", ret);
716 goto mt_isp_register_char_driver_exit;
717 }
718
719 ISP_LOG("[mt_isp_register_char_driver]OKOK \n");
720
721 mt_isp_register_char_driver_exit:
722 //
723 if (ret < 0) {
724 mt_isp_unregister_char_driver();
725 }
726
727 return ret;
728 }
729
730 /*******************************************************************************
731 *
732 ********************************************************************************/
733 static int mt_isp_probe(struct platform_device *pdev)
734 {
735 int ret = 0;
736 struct resource *pres = NULL;
737 int i;
738
739 ISP_LOG("[mt_isp_probe] enter \n");
740 // Check platform_device parameters
741 if (pdev == NULL) {
742 dev_err(&pdev->dev, "pdev is NULL \n");
743 return -ENXIO;
744 }
745 // Register char driver
746 if ( (ret = mt_isp_register_char_driver()) ) {
747 dev_err(&pdev->dev, "register char failed \n");
748 return ret;
749 }
750 // Mapping CAM_REGISTERS
751 for (i = 0; i < 2; i++) {
752 pres = platform_get_resource(pdev, IORESOURCE_MEM, i);
753 if (pres == NULL) {
754 dev_err(&pdev->dev, "platform_get_resource failed \n");
755 ret = -ENOMEM;
756 goto mt_isp_probe_exit;
757 }
758 pres = request_mem_region(pres->start, pres->end - pres->start + 1, pdev->name);
759 if (pres == NULL) {
760 dev_err(&pdev->dev, "request_mem_region failed \n");
761 ret = -ENOMEM;
762 goto mt_isp_probe_exit;
763 }
764 }
765 // Request CAM_ISP IRQ
766 #if 0 // FIXME
767 isp_irq_num = platform_get_irq(pdev, 0);
768 ISP_LOG("IRQ Num = %d \n", isp_irq_num);
769 if ( (ret = request_irq(isp_irq_num, mt_isp_irq, 0, pdev->name, NULL)) ) {
770 dev_err(&pdev->dev, "request IRQ failed\n");
771 goto mt_isp_probe_exit;
772 }
773 mt6575_irq_set_sens(MT6575_CAM_IRQ_LINE,MT65xx_LEVEL_SENSITIVE);
774 #endif
775 // Someone has enable isp irq ??
776 // enable_irq(isp_irq_num);
777 //
778 // Create class register
779 pclass_isp = class_create(THIS_MODULE, "ispdrv");
780 if (IS_ERR(pclass_isp)) {
781 ret = PTR_ERR(pclass_isp);
782 ISP_ERR("Unable to create class, err = %d\n", ret);
783 return ret;
784 }
785 // FIXME: error handling
786 device_create(pclass_isp, NULL, dev_isp, NULL, ISP_DEV_NAME);
787 // Initialize critical section
788 spin_lock_init(&isp_lock);
789
790 mt_isp_probe_exit:
791 //
792 if (ret < 0) {
793 mt_isp_unregister_char_driver();
794 }
795 //
796 ISP_LOG("[mt_isp_probe] exit \n");
797 //
798 return ret;
799 }
800
801 /*******************************************************************************
802 * Called when the device is being detached from the driver
803 ********************************************************************************/
804 static int mt_isp_remove(struct platform_device *pdev)
805 {
806 struct resource *pres;
807 int i;
808 int irq_num;
809
810 ISP_LOG("[mt_isp_remove] \n");
811 // unregister char driver.
812 mt_isp_unregister_char_driver();
813 // unmaping ISP CAM_REGISTER registers
814 for (i = 0; i < 2; i++) {
815 pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
816 release_mem_region(pres->start, (pres->end - pres->start + 1));
817 }
818 // Release IRQ
819 disable_irq(isp_irq_num);
820 irq_num = platform_get_irq(pdev, 0);
821 free_irq(irq_num , NULL);
822 //
823 device_destroy(pclass_isp, dev_isp);
824 //
825 class_destroy(pclass_isp);
826 pclass_isp = NULL;
827
828 return 0;
829 }
830
831 /*******************************************************************************
832 *
833 ********************************************************************************/
834 static int mt_isp_suspend(struct platform_device *pdev, pm_message_t mesg)
835 {
836 return 0;
837 }
838
839 /*******************************************************************************
840 *
841 ********************************************************************************/
842 static int mt_isp_resume(struct platform_device *pdev)
843 {
844 return 0;
845 }
846
847 /*******************************************************************************
848 *
849 ********************************************************************************/
850 static struct platform_driver isp_driver = {
851 .probe = mt_isp_probe,
852 .remove = mt_isp_remove,
853 .suspend = mt_isp_suspend,
854 .resume = mt_isp_resume,
855 .driver = {
856 .name = "mt-isp",
857 .owner = THIS_MODULE,
858 }
859 };
860
861 /*******************************************************************************
862 *
863 ********************************************************************************/
864 static int
865 mt_isp_dump_reg_to_proc(
866 char *page, char **start, off_t off, int count, int *eof, void *data
867 )
868 {
869 char *p = page;
870 int len = 0;
871 u32 u4Index = 0 ;
872
873 ISP_LOG("[mt_isp_dump_reg_to_proc] \n");
874 //
875
876 p += sprintf(p, "\n\r MT6589 ISP Register \n\r");
877 p += sprintf(p,"======General Setting ====\n\r");
878 for (u4Index=0x4000; u4Index < 0x4010; u4Index += 4) {
879 p += sprintf(p,"+0x%0x 0x%0x\n\r", u4Index, ISP_RD32(ISP_BASE + u4Index));
880 }
881 p += sprintf(p,"======STATUS Setting ====\n\r");
882 for (u4Index = 0x4020; u4Index <= 0x4024; u4Index += 4) {
883 p += sprintf(p,"+0x%0x 0x%0x\n\r", u4Index, ISP_RD32(ISP_BASE + u4Index));
884 }
885 //
886 for (u4Index = 0x000043BC; u4Index <= 0x000043BC; u4Index +=4) {
887 p += sprintf(p, "CAM_IMGO_ERR_STAT\n+0x%0x 0x%0x\n\r", u4Index, ISP_RD32(ISP_BASE + u4Index));
888 }
889 //
890 for (u4Index = 0x0000439C; u4Index <= 0x0000439C; u4Index +=4) {
891 p += sprintf(p, "CAM_IMGI_ERR_STAT\n+0x%0x 0x%0x\n\r", u4Index, ISP_RD32(ISP_BASE + u4Index));
892 }
893 //
894 for (u4Index = 0x00004164; u4Index <= 0x00004164; u4Index +=4) {
895 p += sprintf(p, "CTL_DBG_PORT\n+0x%0x 0x%0x\n\r", u4Index, ISP_RD32(ISP_BASE + u4Index));
896 }
897
898 *start = page + off;
899
900 len = p - page;
901 if (len > off) {
902 len -= off;
903 }
904 else {
905 len = 0;
906 }
907
908 return len < count ? len : count;
909 }
910
911 /*******************************************************************************
912 *
913 ********************************************************************************/
914 static int mt_isp_reg_debug(
915 struct file *file, const char *buffer, unsigned long count, void *data
916 )
917 {
918 char regBuf[64];
919 u32 u4CopyBufSize = (count < (sizeof(regBuf) - 1)) ? (count) : (sizeof(regBuf) - 1);
920 u32 u4Addr = 0;
921 u32 u4Data = 0;
922
923 if (copy_from_user(regBuf, buffer, u4CopyBufSize))
924 return -EFAULT;
925
926 if (sscanf(regBuf, "%x %x", &u4Addr, &u4Data) == 2) {
927 iowrite32(u4Data, ISP_BASE + u4Addr);
928 ISP_LOG("write addr = 0x%08x, data = 0x%08x\n", u4Addr, ioread32(ISP_BASE + u4Addr));
929 }
930 else if (sscanf(regBuf, "%x", &u4Addr) == 1) {
931 ISP_LOG("read addr = 0x%08x, data = 0x%08x\n", u4Addr, ioread32(ISP_BASE + u4Addr));
932 }
933
934 return count;
935 }
936
937 /*******************************************************************************
938 *
939 ********************************************************************************/
940 static int __init mt_isp_init(void)
941 {
942 int ret = 0;
943 struct proc_dir_entry *prEntry;
944
945 ISP_LOG("[mt_isp_init] \n");
946 //
947 if ((ret = platform_driver_register(&isp_driver)) < 0) {
948 ISP_ERR("platform_driver_register fail \n");
949 return ret;
950 }
951 //
952 prEntry = create_proc_entry("driver/isp_reg", 0, NULL);
953 if (prEntry) {
954 prEntry->read_proc = mt_isp_dump_reg_to_proc;
955 prEntry->write_proc = mt_isp_reg_debug;
956 ISP_ERR("add /proc/driver/isp_reg entry OK \n");
957 }
958 else {
959 ISP_ERR("add /proc/driver/isp_reg entry fail \n");
960 }
961
962 return ret;
963 }
964
965 /*******************************************************************************
966 *
967 ********************************************************************************/
968 static void __exit mt_isp_exit(void)
969 {
970 ISP_LOG("[mt_isp_exit] \n");
971
972 platform_driver_unregister(&isp_driver);
973 }
974
975 /*******************************************************************************
976 *
977 ********************************************************************************/
978 module_init(mt_isp_init);
979 module_exit(mt_isp_exit);
980 MODULE_DESCRIPTION("MT6589 ISP driver");
981 MODULE_AUTHOR("ME3");
982 MODULE_LICENSE("GPL");
983