1 /***************************************************************************
\r
5 * Description: functions of operating with bu92725guw board.
\r
12 * Confidential ROHM CO.,LTD.
\r
14 ****************************************************************************/
\r
16 #include <linux/module.h>
\r
17 #include <linux/delay.h>
\r
18 #include <linux/errno.h>
\r
19 #include <linux/platform_device.h>
\r
20 #include <linux/fs.h>
\r
21 #include <linux/kernel.h>
\r
22 #include <linux/slab.h>
\r
23 #include <linux/mm.h>
\r
24 #include <linux/ioport.h>
\r
25 #include <linux/init.h>
\r
26 #include <linux/sched.h>
\r
27 #include <linux/pci.h>
\r
28 #include <linux/random.h>
\r
29 #include <linux/version.h>
\r
30 #include <linux/mutex.h>
\r
31 #include <linux/videodev2.h>
\r
32 #include <linux/dma-mapping.h>
\r
33 #include <linux/interrupt.h>
\r
34 #include <linux/kthread.h>
\r
35 #include <linux/highmem.h>
\r
36 #include <linux/freezer.h>
\r
38 #include "rk29_ir.h"
\r
41 #define RK29IR_DBG(x...) printk(x)
\r
43 #define RK29IR_DBG(x...)
\r
47 /*---------------------------------------------------------------------------
\r
49 ----------------------------------------------------------------------------*/
\r
50 /* record current setting
\r
52 static u32 curTrans_mode; /* SIR, MIR, FIR */
\r
53 static u32 curTrans_speed; /* 2.4kbps, 9.6kbps,..., 4Mbps */
\r
54 static u32 curTrans_way; /* idle, send, receive, auto-multi-receive, multi-receive, multi-send */
\r
55 static u16 curFIT; /* FIT2,1,0 in PWR/FIT register */
\r
57 /*---------------------------------------------------------------------------
\r
59 ----------------------------------------------------------------------------*/
\r
60 static void internal_set(u8 modeChg);
\r
62 /*---------------------------------------------------------------------------
\r
63 global Function Implement
\r
64 ----------------------------------------------------------------------------*/
\r
66 * Synopsis: board initialize
\r
72 void irda_hw_init(struct rk29_irda *si)
\r
74 //smc0_init(&si->irda_base_addr);
\r
76 //printk("%s [%d]\n",__FUNCTION__,__LINE__);
\r
78 void irda_hw_deinit(struct rk29_irda *si)
\r
80 // smc0_init(&si->irda_base_addr);
\r
83 int irda_hw_startup(struct rk29_irda *si)
\r
87 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
90 BU92725GUW_WRITE_REG(REG_IER_ADDR, 0x0000);
\r
92 //MCR (use IrDA Controller func, 9.6kbps, SIR)
\r
93 BU92725GUW_WRITE_REG(REG_MCR_ADDR, REG_MCR_9600 | REG_MCR_SIR);
\r
96 BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, REG_PWR_FIT_MPW_3 | REG_PWR_FIT_FPW_2 | REG_PWR_FIT_FIT_0);
\r
98 //TRCR (idle, clr fifo, IrDA power on, mode select enable)
\r
99 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_FCLR | REG_TRCR_MS_EN);
\r
100 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
101 while (val & REG_TRCR_MS_EN) {
\r
102 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
106 BU92725GUW_WRITE_REG(REG_FTLV_ADDR, 0x0000);
\r
108 // for(i=0; i<REG_WREC_ADDR;i=(i+2))//%REG_WREC_ADDR) //
\r
109 // printk("reg %d = 0x%x\n",i,BU92725GUW_READ_REG(i));
\r
111 curTrans_mode = BU92725GUW_SIR;
\r
112 curTrans_speed = 9600;
\r
113 curTrans_way = BU92725GUW_IDLE;
\r
114 curFIT = REG_PWR_FIT_FIT_0;
\r
118 int irda_hw_shutdown(struct rk29_irda *si)
\r
120 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
123 BU92725GUW_WRITE_REG(REG_IER_ADDR, 0x0000);
\r
125 //MCR (use IrDA Controller func, 9.6kbps, SIR)
\r
126 BU92725GUW_WRITE_REG(REG_MCR_ADDR, REG_MCR_9600 | REG_MCR_SIR);
\r
128 //PWR/FIT (default)
\r
129 BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, REG_PWR_FIT_MPW_3 | REG_PWR_FIT_FPW_2 | REG_PWR_FIT_FIT_0);
\r
131 //TRCR (idle, clr fifo, IrDA power down)
\r
132 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_FCLR | REG_TRCR_IRPD);
\r
135 BU92725GUW_WRITE_REG(REG_FTLV_ADDR, 0x0000);
\r
137 curTrans_mode = BU92725GUW_SIR;
\r
138 curTrans_speed = 9600;
\r
139 curTrans_way = BU92725GUW_IDLE;
\r
140 curFIT = REG_PWR_FIT_FIT_0;
\r
146 * Synopsis: set data transfer speed
\r
148 * Paras: speed - speed value will be set; value is from enum eTrans_Speed
\r
152 int irda_hw_set_speed(u32 speed)
\r
157 /* do nothing if speed is same as current */
\r
158 RK29IR_DBG("line %d: enter %s, speed=%d\n", __LINE__, __FUNCTION__, speed);
\r
160 if (speed == curTrans_speed)
\r
171 mode = BU92725GUW_SIR;
\r
175 mode = BU92725GUW_MIR;
\r
178 mode = BU92725GUW_FIR;
\r
181 return -1; //invalid
\r
185 curTrans_speed = speed;
\r
187 /* change trans way if needed */
\r
188 switch (curTrans_way) {
\r
189 case BU92725GUW_IDLE:
\r
191 case BU92725GUW_REV:
\r
192 if (mode != BU92725GUW_SIR)
\r
193 curTrans_way = BU92725GUW_AUTO_MULTI_REV;
\r
194 //curTrans_way = BU92725GUW_MULTI_REV;
\r
196 case BU92725GUW_SEND:
\r
197 if (mode != BU92725GUW_SIR)
\r
198 curTrans_way = BU92725GUW_MULTI_SEND;
\r
200 case BU92725GUW_AUTO_MULTI_REV:
\r
201 if (mode == BU92725GUW_SIR)
\r
202 curTrans_way = BU92725GUW_REV;
\r
204 case BU92725GUW_MULTI_REV: //not used now
\r
205 if (mode == BU92725GUW_SIR)
\r
206 curTrans_way = BU92725GUW_REV;
\r
208 case BU92725GUW_MULTI_SEND:
\r
209 if (mode == BU92725GUW_SIR)
\r
210 curTrans_way = BU92725GUW_SEND;
\r
214 if (mode != curTrans_mode) {
\r
215 if ((mode == BU92725GUW_FIR) || (curTrans_mode == BU92725GUW_FIR))
\r
216 modeChg = 1; /* need set TRCR5:MS_EN */
\r
219 curTrans_mode = mode;
\r
221 /* set bu92725guw registers */
\r
222 //internal_set(modeChg);
\r
228 int irda_hw_tx_enable_irq(enum eTrans_Mode mode)
\r
231 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
232 /* hardware-specific code
\r
234 if (mode == BU92725GUW_SIR)
\r
235 BU92725GUW_set_trans_way(BU92725GUW_SEND);
\r
237 BU92725GUW_set_trans_way(BU92725GUW_MULTI_SEND);
\r
239 //BU92725GUW_clr_fifo();
\r
244 int irda_hw_tx_enable(int len)
\r
246 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
247 BU92725GUW_WRITE_REG(REG_FTLV_ADDR, len);
\r
248 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_TX_EN);
\r
252 int irda_hw_get_irqsrc(void)
\r
254 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
255 return BU92725GUW_READ_REG(REG_EIR_ADDR);
\r
258 int irda_hw_get_data16(char* data8)
\r
263 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
265 len = BU92725GUW_READ_REG(REG_FLV_ADDR);
\r
268 /* read data from RXD */
\r
269 data16 = BU92725GUW_READ_REG(REG_RXD_ADDR);
\r
270 data8[0] = (u8)data16;
\r
271 data8[1] = (u8)(data16 >> 8);
\r
278 void irda_hw_set_moderx(void)
\r
280 // frData.ucFlags &= ~(FRMF_TX_ACTIVE);
\r
281 // frData.ucFlags |= FRMF_RX_ACTIVE;
\r
284 /* hardware-specific code
\r
286 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
288 //BU92725GUW_clr_fifo();
\r
290 if (curTrans_mode == BU92725GUW_SIR)
\r
291 BU92725GUW_set_trans_way(BU92725GUW_REV);
\r
293 BU92725GUW_set_trans_way(BU92725GUW_AUTO_MULTI_REV);
\r
294 //BU92725GUW_set_trans_way(BU92725GUW_MULTI_REV);
\r
297 int irda_hw_get_mode(void)
\r
299 return curTrans_way;
\r
302 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
303 RK29IR_DBG("line %d: enter %s, REG_TRCR_ADDR = 0x%x\n", __LINE__, __FUNCTION__, val);
\r
305 return (val& (REG_TRCR_TX_EN | REG_TRCR_RX_EN));
\r
309 * Synopsis: set data transfer way
\r
311 * Paras: way - transfer way will be set; value is from enum eThrans_Way
\r
315 void BU92725GUW_set_trans_way(u32 way)
\r
317 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
318 if (way == curTrans_way)
\r
321 curTrans_way = way;
\r
323 /* set bu92725guw registers */
\r
328 * Synopsis: clear fifo
\r
334 void BU92725GUW_clr_fifo(void)
\r
338 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
339 /* set TRCR4:FCLR */
\r
340 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
342 val |= REG_TRCR_FCLR;
\r
343 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, val);
\r
345 /* wait op complete */
\r
346 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
347 while (val & REG_TRCR_FCLR)
\r
348 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
352 * Synopsis: read frame data from fifo
\r
354 * Paras: buf - point to buffer for storing frame data
\r
356 * Return: number of data got from fifo (in byte)
\r
358 u16 BU92725GUW_get_data(u8 *buf)
\r
363 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
365 /* get data count from FLV or FLVII */
\r
366 if (curTrans_way == BU92725GUW_REV)
\r
367 len = BU92725GUW_READ_REG(REG_FLV_ADDR);
\r
369 len = BU92725GUW_READ_REG(REG_FLVII_ADDR);
\r
371 count = (len % 2)? (len / 2 + 1) : (len / 2);
\r
373 /* read data from RXD */
\r
374 for (i=0; i<count; i++) {
\r
375 data = BU92725GUW_READ_REG(REG_RXD_ADDR);
\r
376 buf[i * 2] = (u8)data;
\r
377 buf[i * 2 + 1] = (u8)(data >> 8);
\r
380 /* restart receive mode under SIR */
\r
381 if (curTrans_way == BU92725GUW_REV) {
\r
382 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, 0x0000);
\r
383 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_RX_EN);
\r
390 * Synopsis: write data from buffer1 and buffer2 into fifo
\r
392 * Paras: buf1 - point to buffer 1
\r
393 * len1 - length of data to write into fifo from buffer 1
\r
394 * buf2 - point to buffer 2
\r
395 * len2 - length of data to write into fifo from buffer 2
\r
399 void BU92725GUW_send_data(u8 *buf1, u16 len1, u8 *buf2, u16 len2)
\r
400 {/* buf2,len2 will be used by framer under MIR/FIR mode */
\r
401 u16 data, len, pos;
\r
406 ptr = (u8 *)(&data);
\r
408 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
414 BU92725GUW_WRITE_REG(REG_FTLV_ADDR, len);
\r
416 /* set TRCR:TX_EN under normal send mode */
\r
417 if (curTrans_way == BU92725GUW_SEND) {//SIR
\r
418 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_TX_EN);
\r
423 while (pos < len) {
\r
425 *ptr++ = (pos < len1)? buf1[pos] : buf2[pos-len1];
\r
430 *ptr-- = (pos < len1)? buf1[pos] : buf2[pos-len1];
\r
436 BU92725GUW_WRITE_REG(REG_TXD_ADDR, data);
\r
441 * Synopsis: set frame sending interval under multi-window send mode
\r
443 * Paras: us - interval time value to set
\r
447 void BU92725GUW_set_frame_interval(u32 us)
\r
451 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
454 val = BU92725GUW_READ_REG(REG_PWR_FIT_ADDR);
\r
459 val |= REG_PWR_FIT_FIT_0;
\r
460 else if (us <= 200)
\r
461 val |= REG_PWR_FIT_FIT_1;
\r
462 else if (us <= 300)
\r
463 val |= REG_PWR_FIT_FIT_2;
\r
464 else if (us <= 400)
\r
465 val |= REG_PWR_FIT_FIT_3;
\r
466 else if (us <= 500)
\r
467 val |= REG_PWR_FIT_FIT_4;
\r
468 else if (us <= 600)
\r
469 val |= REG_PWR_FIT_FIT_5;
\r
470 else if (us <= 800)
\r
471 val |= REG_PWR_FIT_FIT_6;
\r
472 else if (us <= 1000)
\r
473 val |= REG_PWR_FIT_FIT_7;
\r
474 else if (us <= 1200)
\r
475 val |= REG_PWR_FIT_FIT_8;
\r
476 else if (us <= 1400)
\r
477 val |= REG_PWR_FIT_FIT_9;
\r
478 else if (us <= 1600)
\r
479 val |= REG_PWR_FIT_FIT_A;
\r
480 else if (us <= 1800)
\r
481 val |= REG_PWR_FIT_FIT_B;
\r
482 else if (us <= 2000)
\r
483 val |= REG_PWR_FIT_FIT_C;
\r
484 else if (us <= 2200)
\r
485 val |= REG_PWR_FIT_FIT_D;
\r
486 else if (us <= 2400)
\r
487 val |= REG_PWR_FIT_FIT_E;
\r
489 val |= REG_PWR_FIT_FIT_F;
\r
491 BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, val);
\r
493 //curFIT = val & 0x0700;
\r
494 curFIT = val & 0x0F00;
\r
498 * Synopsis: return current transfer mode (SIR/MIR/FIR)
\r
502 * Return: current transfer mode
\r
504 u32 BU92725GUW_get_trans_mode(void)
\r
506 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
507 return curTrans_mode;
\r
511 * Synopsis: add a IrDA pulse following frame
\r
517 void BU92725GUW_add_pulse(void)
\r
519 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
520 /* valid only under M/FIR send mode */
\r
521 if (curTrans_way != BU92725GUW_MULTI_SEND)
\r
524 /* set TRCR3:IR_PLS */
\r
525 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_IR_PLS | REG_TRCR_TX_CON);
\r
529 * Synopsis: soft reset bu92725guw board; will be called after some error happened
\r
535 void BU92725GUW_reset(void)
\r
537 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
538 /* set bu925725guw registers */
\r
542 /*---------------------------------------------------------------------------
\r
543 local Function Implement
\r
544 ----------------------------------------------------------------------------*/
\r
546 * Synopsis: set bu92725guw internal registers
\r
548 * Paras: modeChg - need set TRCR5:MS_EN or not
\r
552 static void internal_set(u8 modeChg)
\r
556 RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
\r
558 BU92725GUW_WRITE_REG(REG_IER_ADDR, 0x0000);
\r
559 val = BU92725GUW_READ_REG(REG_EIR_ADDR);
\r
563 switch (curTrans_mode) {
\r
564 case BU92725GUW_SIR: //00
\r
565 val |= REG_MCR_SIR;
\r
567 case BU92725GUW_MIR: //01
\r
568 val |= REG_MCR_MIR;
\r
570 case BU92725GUW_FIR: //10
\r
571 val |= REG_MCR_FIR;
\r
574 switch (curTrans_speed) {
\r
576 val |= REG_MCR_2400;
\r
579 val |= REG_MCR_9600;
\r
582 val |= REG_MCR_19200;
\r
585 val |= REG_MCR_38400;
\r
588 val |= REG_MCR_57600;
\r
591 val |= REG_MCR_115200;
\r
594 val |= REG_MCR_576K;
\r
596 case 1152000: //010
\r
597 val |= REG_MCR_1152K;
\r
599 case 4000000: //010
\r
603 BU92725GUW_WRITE_REG(REG_MCR_ADDR, val);
\r
604 RK29IR_DBG("REG_MCR_ADDR: 0x%x\n", val);
\r
607 switch (curTrans_mode) {
\r
608 case BU92725GUW_SIR:
\r
611 case BU92725GUW_MIR:
\r
612 val = REG_PWR_FIT_MPW_3 | curFIT;
\r
614 case BU92725GUW_FIR:
\r
615 val = REG_PWR_FIT_FPW_2 | curFIT;
\r
618 BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, val);
\r
619 RK29IR_DBG("REG_PWR_FIT_ADDR: 0x%x\n", val);
\r
623 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_MS_EN);
\r
624 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
625 while (val & REG_TRCR_MS_EN) {
\r
626 val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
\r
631 switch (curTrans_way) {
\r
632 case BU92725GUW_IDLE:
\r
635 case BU92725GUW_REV:
\r
636 val = REG_TRCR_RX_EN;
\r
638 case BU92725GUW_SEND:
\r
641 case BU92725GUW_AUTO_MULTI_REV:
\r
642 val = REG_TRCR_RX_EN | REG_TRCR_AUTO_FLV_CP;
\r
644 case BU92725GUW_MULTI_REV: //not used
\r
645 val = REG_TRCR_RX_EN | REG_TRCR_RX_CON;
\r
647 case BU92725GUW_MULTI_SEND:
\r
648 val = REG_TRCR_TX_CON;
\r
651 BU92725GUW_WRITE_REG(REG_TRCR_ADDR, val);
\r
652 RK29IR_DBG("REG_TRCR_ADDR: 0x%x\n", val);
\r
655 switch (curTrans_way) {
\r
656 case BU92725GUW_IDLE:
\r
660 case BU92725GUW_REV: /* SIR use */
\r
661 val = REG_INT_EOFRX | REG_INT_TO | REG_INT_OE | REG_INT_FE; //IER1, 2, 5, 7
\r
664 case BU92725GUW_SEND: /* SIR use */
\r
665 val = REG_INT_TXE; //IER3
\r
668 case BU92725GUW_MULTI_REV: /* not used */
\r
669 val = REG_INT_STFRX | REG_INT_TO | REG_INT_CRC | REG_INT_OE | REG_INT_EOF | REG_INT_AC | REG_INT_DECE |
\r
670 REG_INT_RDOE | REG_INT_DEX | REG_INT_RDUE; //IER1,2, 4, 5, 6, 7, 8, 9, 10
\r
673 case BU92725GUW_AUTO_MULTI_REV: /* M/FIR use */
\r
674 val = REG_INT_TO | REG_INT_CRC | REG_INT_OE | REG_INT_EOF | REG_INT_AC | REG_INT_DECE |
\r
675 REG_INT_RDOE | REG_INT_DEX | REG_INT_RDE; //IER2, 4, 5, 6, 7, 8, 9, 12
\r
678 case BU92725GUW_MULTI_SEND: /* M/FIR use */
\r
679 val = REG_INT_TO | REG_INT_TXE | REG_INT_WRE; //IER2, 3, 11
\r
682 BU92725GUW_WRITE_REG(REG_IER_ADDR, val);
\r
683 RK29IR_DBG("REG_IER_ADDR: 0x%x\n", val);
\r