import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / cirq / mt8127 / mt_cirq.c
1 #include <linux/kernel.h>
2 #include <linux/device.h>
3 #include <linux/platform_device.h>
4 #include <linux/module.h>
5 #include <linux/interrupt.h>
6 #include <mach/mt_cirq.h>
7 #include <mach/mt_reg_base.h>
8 #include <asm/system.h>
9 #include <linux/module.h>
10 #include <linux/uaccess.h>
11 #include <linux/slab.h>
12 #include <linux/cpu.h>
13 #include <linux/smp.h>
14 #include <linux/types.h>
15 #include <mach/mt_sleep.h>
16 #include "mach/sync_write.h"
17 #include "mach/irqs.h"
18 #include <asm/mach/irq.h>
19
20 #include <linux/version.h>
21 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
22 #include <asm/hardware/gic.h>
23 #else
24 #include <linux/irqchip/arm-gic.h>
25 #endif
26
27
28 #define INT_POL_CTL0 (MCUSYS_CFGREG_BASE + 0x100)
29
30 int mt_cirq_test(void);
31 void mt_cirq_dump_reg(void);
32 #define CIRQ_DEBUG 0
33 #define CIRQ_LOG_LEVEL KERN_DEBUG
34 #define LDVT
35
36 #if(CIRQ_DEBUG == 1)
37 #ifdef CTP
38 #define dbgmsg dbg_print
39 #else
40 #define dbgmsg printk
41 #define print_func() do { \
42 printk("in %s\n",__func__); \
43 } while(0)
44 #endif
45 #else
46 #define dbgmsg(...)
47 #define print_func() do { }while(0)
48 #endif
49
50
51 #define cirq_num_validate(x) do{\
52 if (x > (MT_NR_CIRQ) || x < 0){\
53 dbgmsg(CIRQ_LOG_LEVEL "Error in %s [CIRQ] wrong cirq, num %d is larger then 155 or less then 0\n",__func__,x); \
54 return -1; \
55 }\
56 }while(0)
57
58
59 struct mt_cirq_driver{
60 struct device_driver driver;
61 const struct platform_device_id *id_table;
62 };
63
64 static struct mt_cirq_driver mt_cirq_drv = {
65 .driver = {
66 .name = "cirq",
67 .bus = &platform_bus_type,
68 .owner = THIS_MODULE,
69 },
70 .id_table= NULL,
71 };
72
73 /* 1: this cirq is masked
74 * 0: this cirq is umasked
75 * -1:cirq num is out of range
76 * */
77 static unsigned int mt_cirq_get_mask(unsigned int cirq_num)
78 {
79 unsigned int base;
80 unsigned int bit = 1 << (cirq_num % 32);
81 volatile unsigned int val;
82 print_func();
83 cirq_num_validate(cirq_num);
84 base = (cirq_num / 32) * 4 + CIRQ_MASK0;
85 val = readl(IOMEM(base));
86 if (val & bit)
87 return 1;
88 else
89 return 0;
90 }
91
92 void mt_cirq_mask_all(void)
93 {
94 int i;
95
96 for(i = 0; i < 5; i++)
97 mt65xx_reg_sync_writel(0xFFFFFFFF, CIRQ_MASK_SET0 + i * 4);
98 }
99
100 void mt_cirq_unmask_all(void)
101 {
102 int i;
103
104 for(i = 0; i < 5; i++)
105 mt65xx_reg_sync_writel(0xFFFFFFFF, CIRQ_MASK_CLR0 + i * 4);
106 }
107
108 void mt_cirq_ack_all(void)
109 {
110 int i;
111
112 for(i = 0; i < 5; i++)
113 mt65xx_reg_sync_writel(0xFFFFFFFF, CIRQ_ACK0 + i * 4);
114 }
115
116 /*
117 * 0: mask success
118 * -1:cirq num is out of range
119 * */
120 static int mt_cirq_mask(unsigned int cirq_num)
121 {
122 unsigned int base;
123 unsigned int bit = 1 << (cirq_num % 32);
124 print_func();
125
126 cirq_num_validate(cirq_num);
127 base = (cirq_num / 32) * 4 + CIRQ_ACK0;
128 mt65xx_reg_sync_writel(bit, base);
129
130 base = (cirq_num / 32) * 4 + CIRQ_MASK_SET0;
131 mt65xx_reg_sync_writel(bit, base);
132
133 dbgmsg(CIRQ_LOG_LEVEL "[CIRQ] mask addr:%x = %x, after set:0x%x\n", base, bit,readl(IOMEM((cirq_num / 32) * 4 + CIRQ_MASK0)));
134 return 0;
135
136 }
137
138 /*
139 * 0: umask success
140 * -1:cirq num is out of range
141 * */
142 static int mt_cirq_unmask(unsigned int cirq_num)
143 {
144 unsigned int base;
145 unsigned int bit = 1 << (cirq_num % 32);
146
147 print_func();
148
149 cirq_num_validate(cirq_num);
150 base = (cirq_num / 32) * 4 + CIRQ_ACK0;
151 mt65xx_reg_sync_writel(bit, base);
152 dbgmsg(CIRQ_LOG_LEVEL "[CIRQ] ack :%x, bit: %x\n", base, bit);
153
154 base = (cirq_num / 32) * 4 + CIRQ_MASK_CLR0;
155 mt65xx_reg_sync_writel(bit, base);
156
157 dbgmsg(CIRQ_LOG_LEVEL "[CIRQ] unmask addr:%x = %x, after set:0x%x\n", base, bit,readl(IOMEM((cirq_num / 32) * 4 + CIRQ_MASK0)));
158 return 0;
159
160 }
161
162 /*
163 * 0: set pol success
164 * -1:cirq num is out of range
165 * */
166 static int mt_cirq_set_pol(unsigned int cirq_num, unsigned int pol)
167 {
168 unsigned int base;
169 unsigned int bit = 1 << (cirq_num % 32);
170
171 print_func();
172
173 cirq_num_validate(cirq_num);
174 if (pol == MT_CIRQ_POL_NEG) {
175 base = (cirq_num / 32) * 4 + CIRQ_POL_CLR0;
176 } else if (pol == MT_CIRQ_POL_POS){
177 base = (cirq_num / 32) * 4 + CIRQ_POL_SET0;
178 } else {
179 dbgmsg(KERN_CRIT"%s invalid polarity value\n", __func__);
180 return -1 ;
181 }
182 mt65xx_reg_sync_writel(bit, base);
183 dbgmsg(CIRQ_LOG_LEVEL "[CIRQ] set pol:%d :%x, bit: %x, after set:0x%x\n",pol, base, bit,readl(IOMEM((cirq_num / 32) * 4 + CIRQ_POL0)));
184 return 0;
185
186 }
187
188 /*
189 * 0: set sens success
190 * -1:cirq num is out of range
191 * */
192 static int mt_cirq_set_sens(unsigned int cirq_num, unsigned int sens)
193 {
194 unsigned int base;
195 unsigned int bit = 1 << (cirq_num % 32);
196
197 print_func();
198 cirq_num_validate(cirq_num);
199 if (sens == MT_EDGE_SENSITIVE) {
200 base = (cirq_num / 32) * 4 + CIRQ_SENS_CLR0;
201 } else if (sens == MT_LEVEL_SENSITIVE) {
202 base = (cirq_num / 32) * 4 + CIRQ_SENS_SET0;
203 } else {
204 dbgmsg(KERN_CRIT"%s invalid sensitivity value\n", __func__);
205 return -1;
206 }
207 mt65xx_reg_sync_writel(bit, base);
208 dbgmsg(CIRQ_LOG_LEVEL "[CIRQ] %s,sens:%d :%x, bit: %x, after set:0x%x\n", __func__,sens, base, bit,readl(IOMEM((cirq_num / 32) * 4 + CIRQ_SENS0)));
209 return 0;
210 }
211
212 /* 1: this cirq is MT_LEVEL_SENSITIVE
213 * 0: this cirq is MT_EDGE_SENSITIVE
214 * -1:cirq num is out of range
215 * */
216 static unsigned int mt_cirq_get_sens(unsigned int cirq_num)
217 {
218
219 unsigned int base;
220 unsigned int bit = 1 << (cirq_num % 32);
221 volatile unsigned int val;
222 print_func();
223 cirq_num_validate(cirq_num);
224 base = (cirq_num / 32) * 4 + CIRQ_SENS0;
225 val = readl(IOMEM(base));
226 if (val & bit)
227 {
228 return MT_LEVEL_SENSITIVE;
229 }
230 else
231 {
232 return MT_EDGE_SENSITIVE;
233 }
234
235 }
236
237 /* 1: this cirq is MT_CIRQ_POL_POS
238 * 0: this cirq is MT_CIRQ_POL_NEG
239 * -1:cirq num is out of range
240 * */
241 static unsigned int mt_cirq_get_pol(unsigned int cirq_num)
242 {
243 unsigned int base;
244 unsigned int bit = 1 << (cirq_num % 32);
245 volatile unsigned int val;
246 print_func();
247 cirq_num_validate(cirq_num);
248 base = (cirq_num / 32) * 4 + CIRQ_POL0;
249 val = readl(IOMEM(base));
250 if (val & bit)
251 {
252 return MT_CIRQ_POL_POS;
253 }
254 else
255 {
256 return MT_CIRQ_POL_NEG;
257 }
258 }
259 #if 0
260 /*
261 * 0: ack success
262 * -1:cirq num is out of range
263 * */
264 static unsigned int mt_cirq_ack(unsigned int cirq_num)
265 {
266 unsigned int base;
267 unsigned int bit = 1 << (cirq_num % 32);
268 print_func();
269
270 cirq_num_validate(cirq_num);
271 base = (cirq_num / 32) * 4 + CIRQ_ACK0;
272 mt65xx_reg_sync_writel(bit, base);
273
274
275 dbgmsg(CIRQ_LOG_LEVEL "[CIRQ] ack addr:%x = %x\n", base, bit);
276
277 return 0;
278 }
279 #endif
280 #if 0
281 /*
282 * 0: get sta success
283 * -1:cirq num is out of range
284 * */
285 unsigned int mt_cirq_read_status(unsigned int cirq_num)
286 {
287 unsigned int sta;
288 unsigned int base;
289 unsigned int bit = 1 << (cirq_num % 32);
290 volatile unsigned int val;
291 print_func();
292 cirq_num_validate(cirq_num);
293
294 base = (cirq_num / 32) * 4 + CIRQ_STA0;
295 val = readl(IOMEM(base));
296 sta = (val & bit);
297 return sta;
298
299 }
300 #endif
301 void mt_cirq_enable(void){
302 unsigned int base=CIRQ_CON;
303 volatile unsigned int val;
304 val = readl(IOMEM(CIRQ_CON));
305 val |= (0x3); //enable edge only mode
306 mt65xx_reg_sync_writel(val,base);
307 }
308 void mt_cirq_disable(void){
309 unsigned int base=CIRQ_CON;
310 volatile unsigned int val;
311 val = readl(IOMEM(CIRQ_CON));
312 val &= (~0x1);
313 mt65xx_reg_sync_writel(val,base);
314 }
315 void mt_cirq_flush(void){
316
317 unsigned int irq;
318 volatile unsigned int val;
319 print_func();
320
321 /*make edge interrupt shows in the STA*/
322 mt_cirq_unmask_all();
323 for (irq = 64; irq < (NR_MT_IRQ_LINE); irq+=32)
324 {
325 val = readl(IOMEM(((irq-64) / 32) * 4 + CIRQ_STA0));
326 //printk("irq:%d,pending bit:%x\n",irq,val);
327
328 mt65xx_reg_sync_writel(val,(GIC_DIST_BASE + GIC_DIST_PENDING_SET + irq / 32 * 4));
329 dsb();
330 //printk("irq:%d,pending bit:%x,%x\n",irq,val,readl(GIC_DIST_BASE + GIC_DIST_PENDING_SET + irq / 32 * 4));
331 }
332 mt_cirq_mask_all();
333 dsb();
334 }
335 static void mt_cirq_clone_pol(void)
336 {
337 unsigned int irq,irq_offset;
338 volatile unsigned int value;
339 volatile unsigned int value_cirq;
340 int ix;
341 print_func();
342 for (irq = 64; irq < (NR_MT_IRQ_LINE); irq+=32)
343 {
344 value = readl(IOMEM(INT_POL_CTL0 + ((irq-GIC_PRIVATE_SIGNALS) / 32 * 4)));
345 irq_offset = (irq-64) / 32;
346 dbgmsg(CIRQ_LOG_LEVEL "irq:%d,gic_pol_address:0x%8x,gic_pol_value:0x%08x\n",irq,INT_POL_CTL0 + ((irq-GIC_PRIVATE_SIGNALS) / 32 * 4),value);
347 for (ix = 0; ix < 32; ix++)
348 {
349 if (value & (0x1)) //high trigger
350 mt_cirq_set_pol(irq+ix-64,MT_CIRQ_POL_NEG);
351 else//low trigger
352 mt_cirq_set_pol(irq+ix-64,MT_CIRQ_POL_POS);
353
354 value >>= 1;
355 }
356 value_cirq = readl(IOMEM(CIRQ_POL0 + irq_offset*4));
357 dbgmsg(CIRQ_LOG_LEVEL "irq:%d,cirq_value:0x%08x\n",irq,value_cirq);
358 }
359 }
360
361 static void mt_cirq_clone_sens(void)
362 {
363 unsigned int irq,irq_offset;
364 volatile unsigned int value;
365 volatile unsigned int value_cirq;
366 int ix;
367 print_func();
368 for (irq = 64; irq < (NR_MT_IRQ_LINE); irq+=16)
369 {
370 value = readl(IOMEM(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4));
371 dbgmsg(CIRQ_LOG_LEVEL "irq:%d,sens:%08x,value:0x%08x\n",irq,GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4,value);
372 irq_offset = (irq-64) / 32;
373 for (ix = 0; ix < 16; ix++)
374 {
375 if (value & (0x2)) //edge trigger
376 mt_cirq_set_sens(irq-64+ix,MT_EDGE_SENSITIVE);
377 else//level trigger
378 mt_cirq_set_sens(irq-64+ix,MT_LEVEL_SENSITIVE);
379 value >>= 2;
380 }
381 value_cirq = readl(IOMEM(CIRQ_SENS0 + irq_offset*4));
382 dbgmsg(CIRQ_LOG_LEVEL "irq:%d,cirq_value:0x%08x\n",irq,value_cirq);
383 }
384 }
385
386 static void mt_cirq_clone_mask(void)
387 {
388 unsigned int irq,irq_offset;
389 volatile unsigned int value;
390 volatile unsigned int value_cirq;
391 int ix;
392 print_func();
393 for (irq = 64; irq < (NR_MT_IRQ_LINE); irq+=32)
394 {
395 value = readl(IOMEM(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + irq / 32 * 4));
396 dbgmsg(CIRQ_LOG_LEVEL "irq:%d,mask:%08x,value:0x%08x\n",irq,(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + irq / 32 * 4) ,value);
397 irq_offset = (irq-64) / 32;
398 for (ix = 0; ix < 32; ix++)
399 {
400 if (value & (0x1)) //enable
401 mt_cirq_unmask(irq+ix-64);
402 else//disable
403 mt_cirq_mask(irq+ix-64);
404
405 value >>= 1;
406 }
407 value_cirq = readl(IOMEM(CIRQ_MASK0 + irq_offset*4));
408 dbgmsg(CIRQ_LOG_LEVEL "irq:%d,cirq_value:0x%08x\n",irq,value_cirq);
409 }
410 }
411 void mt_cirq_clone_gic(void)
412 {
413 mt_cirq_clone_pol();
414 mt_cirq_clone_sens();
415 mt_cirq_clone_mask();
416 }
417
418
419 #if defined(LDVT)
420 /*
421 * cirq_dvt_show: To show usage.
422 */
423 static ssize_t cirq_dvt_show(struct device_driver *driver, char *buf)
424 {
425 return snprintf(buf, PAGE_SIZE, "CIRQ dvt test\n");
426 }
427
428 /*
429 * mci_dvt_store: To select mci test case.
430 */
431 static ssize_t cirq_dvt_store(struct device_driver *driver, const char *buf,
432 size_t count)
433 {
434 char *p = (char *)buf;
435 unsigned int num;
436
437 num = simple_strtoul(p, &p, 10);
438 switch(num){
439 case 1:
440 mt_cirq_clone_gic();
441 mt_cirq_dump_reg();
442 break;
443 case 2:
444 mt_cirq_test();
445 break;
446 case 3:
447 mt_cirq_disable();
448 break;
449 default:
450 break;
451 }
452
453 return count;
454 }
455 DRIVER_ATTR(cirq_dvt, 0664, cirq_dvt_show, cirq_dvt_store);
456 #endif //!LDVT
457
458 /*
459 * CIRQ interrupt service routine.
460 */
461 static irqreturn_t cirq_irq_handler(int irq, void *dev_id)
462 {
463 printk("CIRQ_Handler\n");
464 mt_cirq_ack_all();
465 return IRQ_HANDLED;
466 }
467
468 /*
469 * always return 0
470 * */
471 static int __init mt_cirq_init(void){
472 int ret;
473 printk("CIRQ init...\n");
474 if (request_irq(MT_CIRQ_IRQ_ID, cirq_irq_handler, IRQF_TRIGGER_LOW, "CIRQ", NULL)) {
475 printk(KERN_ERR"CIRQ IRQ LINE NOT AVAILABLE!!\n");
476 }else
477 {
478 printk("CIRQ handler init success.");
479 }
480 ret = driver_register(&mt_cirq_drv.driver);
481 #ifdef LDVT
482 ret = driver_create_file(&mt_cirq_drv.driver, &driver_attr_cirq_dvt);
483 #endif
484 if (ret == 0)
485 printk("CIRQ init done...\n");
486 return 0;
487
488 }
489
490 #if defined(LDVT)
491 #define __CHECK_IRQ_TYPE
492 #if defined(__CHECK_IRQ_TYPE)
493 #define X_DEFINE_IRQ(__name, __num, __polarity, __sensitivity) \
494 { .num = __num, .polarity = __polarity, .sensitivity = __sensitivity, },
495 #define L 0
496 #define H 1
497 #define EDGE MT_EDGE_SENSITIVE
498 #define LEVEL MT_LEVEL_SENSITIVE
499 struct __check_irq_type
500 {
501 int num;
502 int polarity;
503 int sensitivity;
504 };
505 struct __check_irq_type __check_irq_type[] =
506 {
507 #include <mach/x_define_irq.h>
508 { .num = -1, },
509 };
510 #undef X_DEFINE_IRQ
511 #undef L
512 #undef H
513 #undef EDGE
514 #undef LEVEL
515 #endif
516
517 void mt_cirq_dump_reg(void)
518 {
519 int cirq_num;
520 int pol,sens,mask;
521 int irq_iter;
522
523 printk("IRQ:\tPOL\tSENS\tMASK\n");
524 for (cirq_num = 0; cirq_num < MT_NR_CIRQ; cirq_num++)
525 {
526 pol = mt_cirq_get_pol(cirq_num);
527 sens = mt_cirq_get_sens(cirq_num);
528 mask = mt_cirq_get_mask(cirq_num);
529 #if defined(__CHECK_IRQ_TYPE)
530 //only check unmask irq
531 if (0 == mask){
532 irq_iter = 0;
533 while (__check_irq_type[irq_iter].num >= 0) {
534 if (__check_irq_type[irq_iter].num == (cirq_num+64)){
535 if(__check_irq_type[irq_iter].sensitivity != sens){
536 printk("[CIRQ] Error sens in irq:%d\n",cirq_num+64);
537 }
538 if(__check_irq_type[irq_iter].polarity != (pol)){
539 printk("[CIRQ] Error polarity in irq:%d\n",cirq_num+64);
540 }
541 break;
542 }
543 irq_iter++;
544 }
545 }
546 #endif
547 printk("IRQ:%d\t%d\t%d\t%d\n",cirq_num+64,pol,sens,mask);
548
549 }
550 }
551 int mt_cirq_test(void)
552 {
553 int cirq_num = 100;
554 mt_cirq_enable();
555
556 /*test polarity*/
557 mt_cirq_set_pol(cirq_num,MT_CIRQ_POL_NEG);
558 if ( MT_CIRQ_POL_NEG != mt_cirq_get_pol(cirq_num))
559 printk("mt_cirq_set_pol test failed!!\n");
560 mt_cirq_set_pol(cirq_num,MT_CIRQ_POL_POS);
561 if ( MT_CIRQ_POL_POS != mt_cirq_get_pol(cirq_num))
562 printk("mt_cirq_set_pol test failed!!\n");
563
564 /*test sensitivity*/
565 mt_cirq_set_sens(cirq_num,MT_EDGE_SENSITIVE);
566 if ( MT_EDGE_SENSITIVE != mt_cirq_get_sens(cirq_num))
567 printk("mt_cirq_set_sens test failed!!\n");
568 mt_cirq_set_sens(cirq_num,MT_LEVEL_SENSITIVE);
569 if ( MT_LEVEL_SENSITIVE != mt_cirq_get_sens(cirq_num))
570 printk("mt_cirq_set_sens test failed!!\n");
571
572 /*test mask*/
573 mt_cirq_mask(cirq_num);
574 if ( 1 != mt_cirq_get_mask(cirq_num))
575 printk("mt_cirq_mask test failed!!\n");
576 mt_cirq_unmask(cirq_num);
577 mt_cirq_set_sens(cirq_num,MT_LEVEL_SENSITIVE);
578 if ( 0 != mt_cirq_get_mask(cirq_num))
579 printk("mt_cirq_unmask test failed!!\n");
580
581
582 mt_cirq_clone_gic();
583 mt_cirq_dump_reg();
584
585 return 0;
586 }
587 #endif //!LDVT
588 arch_initcall(mt_cirq_init);
589 EXPORT_SYMBOL(mt_cirq_enable);
590 EXPORT_SYMBOL(mt_cirq_disable);
591 EXPORT_SYMBOL(mt_cirq_clone_gic);
592 EXPORT_SYMBOL(mt_cirq_flush);
593