#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "drv_devices.h" #include "drv_uartb.h" #define IRQ_UARTB 54 struct kfifo uartb_fifo; DEFINE_SPINLOCK(uart_write_lock); static void __set_baudrate_low(unsigned int baudrate) { unsigned int dl; dl = baudrate * 64 / 375; *(volatile unsigned int *) 0xbe0d0114 = dl; clear_bit(15,(volatile void __iomem *)0xbe00002c); } static void __set_baudrate_high(unsigned int baudrate) { #if defined(CONFIG_CHIP_8503) if (baudrate == 230400) *(unsigned char *)0xbe00018e = 0xff; else if (baudrate == 460800) *(unsigned char *)0xbe00018e = 0xbf; else if (baudrate == 921600) *(unsigned char *)0xbe00018e = 0x9f; #elif defined(CONFIG_CHIP_8506) if (baudrate == 230400) return; else if (baudrate == 460800) *(unsigned char *)0xbe00018e = 0xfa; else if (baudrate == 921600) *(unsigned char *)0xbe00018e = 0xbc; #elif defined(CONFIG_CHIP_6710) if (baudrate == 230400) return; else if (baudrate == 460800) *(unsigned char *)0xbe00018e = 0xe1; else if (baudrate == 921600) *(unsigned char *)0xbe00018e = 0xb0; #elif defined(CONFIG_CHIP_8501) if (baudrate == 230400) return; else if (baudrate == 460800) *(unsigned char *)0xbe00018e = 0xd5; else if (baudrate == 921600) *(unsigned char *)0xbe00018e = 0xb5; #elif defined(CONFIG_CHIP_533) || defined(CONFIG_CHIP_512L) if (baudrate == 230400) return; else if (baudrate == 460800) *(unsigned char *)0xbe00018e = 0xe2; else if (baudrate == 921600) *(unsigned char *)0xbe00018e = 0xb1; #endif set_bit(15,(volatile void __iomem *)0xbe00002c); } static void uartb_set_baudrate(unsigned int baudrate) { unsigned long flags; spin_lock_irqsave(&uart_write_lock, flags); switch (baudrate) { case 9600: case 14400: case 19200: case 38400: case 57600: case 115200: __set_baudrate_low(baudrate); break; case 230400: case 460800: case 921600: __set_baudrate_high(baudrate); break; } spin_unlock_irqrestore(&uart_write_lock, flags); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,8) long uartb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) #else static ssize_t uartb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) #endif { switch (cmd) { case UARTB_SET_BAUDRATE: uartb_set_baudrate(arg); break; } return 0; } static ssize_t uartb_write(struct file *filp, const char __user *uBuff, size_t count, loff_t *f_pos) { unsigned char *kBuff; unsigned int off_irq_flag=0; off_irq_flag = (unsigned int)count & 0x8000; count &= 0x7fff; if((kBuff=(unsigned char *)kmalloc(count, GFP_KERNEL))==NULL) { printk(KERN_EMERG"audiorx_write: no enough memory to do !!!\n"); return count; } if(copy_from_user(kBuff, uBuff, count)) { printk(KERN_EMERG"audiorx_write: copy_from_user error !!!\n"); } else { unsigned int i; unsigned long flags; if (off_irq_flag) spin_lock_irqsave(&uart_write_lock, flags); for (i = 0; i < count; i++) { while(! ((*(volatile unsigned int *)0xbe0d0110)&0x00006000)); writeb(kBuff[i], (volatile unsigned char *)0xbe0d0104); } if (off_irq_flag) spin_unlock_irqrestore(&uart_write_lock, flags); //AI_write(kBuff, count); } kfree(kBuff); return count; } static ssize_t uartb_read(struct file *filp, char __user *uBuff, size_t count, loff_t *f_pos) { size_t i,ret; size_t max_count; unsigned char tmp_buf[512]; memset(tmp_buf,0x0,sizeof(tmp_buf)); max_count = (count < 512)? count: 512; //printk("<0> max_count = %d\n",max_count); for (i = 0; i < max_count; i++) { if (kfifo_is_empty(&uartb_fifo) != 0) { //printk("<0>kfifo_is_empty\n"); break; } ret = kfifo_out(&uartb_fifo, &tmp_buf[i], sizeof(unsigned char)); //printk("<0>c=%c\n",tmp_buf[i]); if (ret != sizeof(unsigned char)) return -EINVAL; } if (copy_to_user(uBuff, tmp_buf, count)) { printk("<0> copy_to_user error!\n"); i = -EFAULT; } return i; } static int uartb_open(struct inode *i, struct file *f) { printk("<0>file open\n"); kfifo_reset(&uartb_fifo); #if defined(CONFIG_XHDMICPIN_TO_UARTB) //UARTB output from XHDMIC_SDA & XHDMIC_SCL set_bit(2, (volatile void __iomem *)0xbe000010); #elif defined(CONFIG_KEY1_I2S_SCK_TO_UARTB) //KEY1 as UARTB_RX clear_bit(20, (volatile void __iomem *) 0xbe0f0600); set_bit(21, (volatile void __iomem *)0xbe0f0600); //I2C_SCK as UARTB_TX clear_bit(2, (volatile void __iomem *) 0xbe0f0600); clear_bit(3, (volatile void __iomem *) 0xbe0f0600); set_bit(15, (volatile void __iomem *) 0xbe00012c); clear_bit(8, (volatile void __iomem *) 0xbe00013c);//R_I2S_OEJ clear_bit(26, (volatile void __iomem *) 0xbe00013c); #else //LVB_TXN4 as UARTB_RX set_bit(14, (volatile void __iomem *) 0xbe00012c); #if (CONFIG_CHIPID == 0x533) set_bit(9, (volatile void __iomem *) 0xbe0000ec); #else clear_bit(9, (volatile void __iomem *) 0xbe00025c); clear_bit(17, (volatile void __iomem *) 0xbe00025c); #endif //LVA_TXN4 as UARTB_TX set_bit(14, (volatile void __iomem *) 0xbe00012c); #if (CONFIG_CHIPID == 0x533) clear_bit(4, (volatile void __iomem *) 0xbe0000ec); #else clear_bit(4, (volatile void __iomem *) 0xbe00025c); clear_bit(17, (volatile void __iomem *) 0xbe00025c); #endif #endif return 0; } static int uartb_close(struct inode *i, struct file *f) { printk("<0>uartb_close\n"); #ifdef CONFIG_XHDMICPIN_TO_UARTB clear_bit(2, (volatile void __iomem *) 0xbe000010); #elif defined(CONFIG_KEY1_I2S_SCK_TO_UARTB) clear_bit(21, (volatile void __iomem *)0xbe0f0600); set_bit(8, (volatile void __iomem *) 0xbe00013c); clear_bit(15, (volatile void __iomem *) 0xbe00012c); #else clear_bit(14, (volatile void __iomem *) 0xbe00012c); #if (CONFIG_CHIPID == 0x533) clear_bit(9, (volatile void __iomem *) 0xbe0000ec); #else set_bit(9, (volatile void __iomem *) 0xbe00025c); set_bit(4, (volatile void __iomem *) 0xbe00025c); #endif #endif return 0; } static irqreturn_t uartb_ISR( int irq, void* dev_id ) { int i; unsigned int rec_fifo, indicator; unsigned char c; //printk("<0> irq=%d\n",irq); if (kfifo_is_full(&uartb_fifo)) { printk("<0> [UARTB] kfifo is full!!\n"); *(volatile unsigned int *) 0xbe0d0110 = *(volatile unsigned int *) 0xbe0d0110; //w1c return IRQ_HANDLED; } rec_fifo = *(volatile unsigned int *) 0xbe0d0100; /* plz read 000, then 00c , hw limit, Gaia*/ indicator = (*(volatile unsigned int *) 0xbe0d010c) & 0xf; for(i=0; indicator!=0; i++){ indicator = indicator >>1; c = rec_fifo >> (i*8); if (kfifo_is_full(&uartb_fifo) == 0) kfifo_in(&uartb_fifo, &c, sizeof(unsigned char)); else break; } //printk("<0> len = %d\n",kfifo_len(&uartb_fifo)); *(volatile unsigned int *) 0xbe0d0110 = *(volatile unsigned int *) 0xbe0d0110; //w1c return IRQ_HANDLED; } static void uartb_dispatch(void) { do_IRQ(IRQ_UARTB); } static struct file_operations uartb_fops = { owner : THIS_MODULE, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,8)) unlocked_ioctl : uartb_ioctl, #else ioctl : uartb_ioctl, #endif open : uartb_open, release : uartb_close, write : uartb_write, read : uartb_read, }; /* static struct file_operations uartb_fops = { .ioctl = uartb_ioctl, .write = uartb_write, .open = uartb_open, .release = uartb_close, .owner = THIS_MODULE, }; */ struct cdev *cdev_uartb; int uartb_init(void) { int ret,err; dev_t devno = MKDEV(UARTB_MAJOR, 0); err=register_chrdev_region(devno, 1, "uartb"); if(err) { return -EIO; } cdev_uartb = cdev_alloc(); cdev_uartb->owner = THIS_MODULE; cdev_uartb->ops = &uartb_fops; err=cdev_add(cdev_uartb, devno, 1); if(err) { return -EIO; } set_vi_handler(IRQ_UARTB, uartb_dispatch); ret = request_irq(IRQ_UARTB, &uartb_ISR, IRQF_DISABLED, "uartb", NULL); *(volatile unsigned short *) 0xbe0d0114 = 0x666;//baud rate:115200,0x00000666:9600 *(volatile unsigned int *) 0xbe0d0128 = 0; *(volatile unsigned int *) 0xbe0d0108 = 0x00200307; *(volatile unsigned int *) 0xbe0d0110 = *(volatile unsigned int *) 0xbe0d0110; while (*(volatile unsigned char *)0xbe0d010c) ret = (int) *(volatile unsigned int *)0xbe0d0100; ret = kfifo_alloc(&uartb_fifo, PAGE_SIZE, GFP_KERNEL); if (ret < 0) printk("<0>[UARTB] kfifo alloc error!"); return ret; } #ifdef CONFIG_SUPPORT_UARTB module_init(uartb_init); #endif //MODULE_LICENSE("Dual BSD/GPL");