mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
drivers/net/irda: remove unused drivers
Change-Id: Ide8b500d07779a7f78df6cd37626b951390594f8 Signed-off-by: Tao Huang <huangtao@rock-chips.com>
This commit is contained in:
@@ -1,762 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/***************************************************************************
|
||||
*
|
||||
* File: bu92725guw.c
|
||||
*
|
||||
* Description: functions of operating with bu92725guw board.
|
||||
*
|
||||
* Created: 2007/9
|
||||
*
|
||||
* Rev 1.1
|
||||
*
|
||||
*
|
||||
* Confidential ROHM CO.,LTD.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include "rk29_ir.h"
|
||||
|
||||
#if 0
|
||||
#define RK29IR_DBG(x...) printk(x)
|
||||
#else
|
||||
#define RK29IR_DBG(x...)
|
||||
#endif
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Data
|
||||
----------------------------------------------------------------------------*/
|
||||
/* record current setting
|
||||
*/
|
||||
static u32 curTrans_mode; /* SIR, MIR, FIR */
|
||||
static u32 curTrans_speed; /* 2.4kbps, 9.6kbps,..., 4Mbps */
|
||||
static u32 curTrans_way; /* idle, send, receive, mir-receive, mir-send, fir-receive, fir-send, auto-multi-receive, multi-receive, multi-send */
|
||||
static u16 curFIT; /* FIT2,1,0 in PWR/FIT register */
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Function Proto
|
||||
----------------------------------------------------------------------------*/
|
||||
static void internal_set(u8 modeChg);
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
global Function Implement
|
||||
----------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Synopsis: board initialize
|
||||
*
|
||||
* Paras: none
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void irda_hw_init(struct rk29_irda *si)
|
||||
{
|
||||
//smc0_init(&si->irda_base_addr);
|
||||
|
||||
//printk("%s [%d]\n",__FUNCTION__,__LINE__);
|
||||
}
|
||||
void irda_hw_deinit(struct rk29_irda *si)
|
||||
{
|
||||
// smc0_init(&si->irda_base_addr);
|
||||
}
|
||||
|
||||
int irda_hw_startup(void)
|
||||
{
|
||||
volatile u16 val;
|
||||
//int i=0;
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
//IER (disable all)
|
||||
BU92725GUW_WRITE_REG(REG_IER_ADDR, 0x0000);
|
||||
|
||||
//MCR (use IrDA Controller func, 9.6kbps, SIR)
|
||||
BU92725GUW_WRITE_REG(REG_MCR_ADDR, REG_MCR_9600 | REG_MCR_SIR);
|
||||
|
||||
//PWR/FIT (default)
|
||||
BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, REG_PWR_FIT_MPW_3 | REG_PWR_FIT_FPW_2 | REG_PWR_FIT_FIT_0);
|
||||
|
||||
//TRCR (idle, clr fifo, IrDA power on, mode select enable)
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_FCLR | REG_TRCR_MS_EN);
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
while (val & REG_TRCR_MS_EN) {
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
}
|
||||
|
||||
//FTLV
|
||||
BU92725GUW_WRITE_REG(REG_FTLV_ADDR, 0x0000);
|
||||
|
||||
// for(i=0; i<REG_WREC_ADDR;i=(i+2))//%REG_WREC_ADDR) //
|
||||
// printk("reg %d = 0x%x\n",i,BU92725GUW_READ_REG(i));
|
||||
|
||||
curTrans_mode = BU92725GUW_SIR;
|
||||
curTrans_speed = 9600;
|
||||
curTrans_way = BU92725GUW_IDLE;
|
||||
curFIT = REG_PWR_FIT_FIT_0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irda_hw_shutdown(void)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
//IER (diable all)
|
||||
BU92725GUW_WRITE_REG(REG_IER_ADDR, 0x0000);
|
||||
|
||||
//MCR (use IrDA Controller func, 9.6kbps, SIR)
|
||||
BU92725GUW_WRITE_REG(REG_MCR_ADDR, REG_MCR_9600 | REG_MCR_SIR);
|
||||
|
||||
//PWR/FIT (default)
|
||||
BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, REG_PWR_FIT_MPW_3 | REG_PWR_FIT_FPW_2 | REG_PWR_FIT_FIT_0);
|
||||
|
||||
//TRCR (idle, clr fifo, IrDA , rx, tx power down)
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_FCLR | REG_TRCR_IRPD |REG_TRCR_TXPWD | REG_TRCR_RXPWD);
|
||||
|
||||
//FTLV
|
||||
BU92725GUW_WRITE_REG(REG_FTLV_ADDR, 0x0000);
|
||||
|
||||
curTrans_mode = BU92725GUW_SIR;
|
||||
curTrans_speed = 9600;
|
||||
curTrans_way = BU92725GUW_IDLE;
|
||||
curFIT = REG_PWR_FIT_FIT_0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: set data transfer speed
|
||||
*
|
||||
* Paras: speed - speed value will be set; value is from enum eTrans_Speed
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
int irda_hw_set_speed(u32 speed)
|
||||
{
|
||||
u32 mode;
|
||||
u8 modeChg = 0;
|
||||
|
||||
/* do nothing if speed is same as current */
|
||||
RK29IR_DBG("line %d: enter %s, speed=%d\n", __LINE__, __FUNCTION__, speed);
|
||||
|
||||
if (speed == curTrans_speed)
|
||||
return 0;
|
||||
|
||||
/* mode */
|
||||
switch (speed) {
|
||||
case 2400:
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
mode = BU92725GUW_SIR;
|
||||
break;
|
||||
case 576000:
|
||||
case 1152000:
|
||||
mode = BU92725GUW_MIR;
|
||||
break;
|
||||
case 4000000:
|
||||
mode = BU92725GUW_FIR;
|
||||
break;
|
||||
default:
|
||||
return -1; //invalid
|
||||
}
|
||||
|
||||
/* speed */
|
||||
curTrans_speed = speed;
|
||||
|
||||
/* change trans way if needed */
|
||||
switch (curTrans_way) {
|
||||
case BU92725GUW_IDLE:
|
||||
break;
|
||||
case BU92725GUW_REV:
|
||||
if (mode == BU92725GUW_MIR)
|
||||
curTrans_way = BU92725GUW_MIR_REV;
|
||||
else if (mode == BU92725GUW_FIR)
|
||||
curTrans_way = BU92725GUW_AUTO_MULTI_REV;
|
||||
//curTrans_way = BU92725GUW_MULTI_REV;
|
||||
//curTrans_way = BU92725GUW_FIR_REV;
|
||||
break;
|
||||
case BU92725GUW_SEND:
|
||||
if (mode == BU92725GUW_MIR)
|
||||
curTrans_way = BU92725GUW_MIR_SEND;
|
||||
else if (mode == BU92725GUW_FIR)
|
||||
curTrans_way = BU92725GUW_MULTI_SEND;
|
||||
//curTrans_way = BU92725GUW_FIR_SEND;
|
||||
break;
|
||||
case BU92725GUW_MIR_REV:
|
||||
if (mode == BU92725GUW_SIR)
|
||||
curTrans_way = BU92725GUW_REV;
|
||||
else if (mode == BU92725GUW_FIR)
|
||||
curTrans_way = BU92725GUW_AUTO_MULTI_REV;
|
||||
//curTrans_way = BU92725GUW_MULTI_REV;
|
||||
//curTrans_way = BU92725GUW_FIR_REV;
|
||||
break;
|
||||
case BU92725GUW_MIR_SEND:
|
||||
if (mode == BU92725GUW_SIR)
|
||||
curTrans_way = BU92725GUW_SEND;
|
||||
else if (mode == BU92725GUW_FIR)
|
||||
curTrans_way = BU92725GUW_MULTI_SEND;
|
||||
//curTrans_way = BU92725GUW_FIR_SEND;
|
||||
break;
|
||||
case BU92725GUW_FIR_REV:
|
||||
case BU92725GUW_AUTO_MULTI_REV:
|
||||
case BU92725GUW_MULTI_REV:
|
||||
if (mode == BU92725GUW_SIR)
|
||||
curTrans_way = BU92725GUW_REV;
|
||||
else if (mode == BU92725GUW_MIR)
|
||||
curTrans_way = BU92725GUW_MIR_REV;
|
||||
break;
|
||||
case BU92725GUW_FIR_SEND:
|
||||
case BU92725GUW_MULTI_SEND:
|
||||
if (mode == BU92725GUW_SIR)
|
||||
curTrans_way = BU92725GUW_SEND;
|
||||
else if (mode == BU92725GUW_MIR)
|
||||
curTrans_way = BU92725GUW_MIR_SEND;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode != curTrans_mode) {
|
||||
if ((mode == BU92725GUW_FIR) || (curTrans_mode == BU92725GUW_FIR))
|
||||
modeChg = 1; /* need set TRCR5:MS_EN */
|
||||
}
|
||||
|
||||
curTrans_mode = mode;
|
||||
|
||||
/* set bu92725guw registers */
|
||||
//internal_set(modeChg);
|
||||
internal_set(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irda_hw_tx_enable_irq(enum eTrans_Mode mode)
|
||||
{
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/* hardware-specific code
|
||||
*/
|
||||
if (mode == BU92725GUW_SIR)
|
||||
BU92725GUW_set_trans_way(BU92725GUW_SEND);
|
||||
else if (mode == BU92725GUW_MIR)
|
||||
BU92725GUW_set_trans_way(BU92725GUW_MIR_SEND);
|
||||
else
|
||||
BU92725GUW_set_trans_way(BU92725GUW_MULTI_SEND);
|
||||
//BU92725GUW_set_trans_way(BU92725GUW_FIR_SEND);
|
||||
//BU92725GUW_clr_fifo();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irda_hw_tx_enable(int len)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
BU92725GUW_WRITE_REG(REG_FTLV_ADDR, len);
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_TX_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irda_hw_get_irqsrc(void)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
return BU92725GUW_READ_REG(REG_EIR_ADDR);
|
||||
}
|
||||
|
||||
int irda_hw_get_data16(char* data8)
|
||||
{
|
||||
u16 data16 = 0;
|
||||
int len = 0;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
len = BU92725GUW_READ_REG(REG_FLV_ADDR);
|
||||
if(len > 0)
|
||||
{
|
||||
/* read data from RXD */
|
||||
data16 = BU92725GUW_READ_REG(REG_RXD_ADDR);
|
||||
data8[0] = (u8)data16;
|
||||
data8[1] = (u8)(data16 >> 8);
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void irda_hw_set_moderx(void)
|
||||
{
|
||||
// frData.ucFlags &= ~(FRMF_TX_ACTIVE);
|
||||
// frData.ucFlags |= FRMF_RX_ACTIVE;
|
||||
|
||||
//int i=0;
|
||||
/* hardware-specific code
|
||||
*/
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
//BU92725GUW_clr_fifo();
|
||||
|
||||
if (curTrans_mode == BU92725GUW_SIR)
|
||||
BU92725GUW_set_trans_way(BU92725GUW_REV);
|
||||
else if (curTrans_mode == BU92725GUW_MIR)
|
||||
BU92725GUW_set_trans_way(BU92725GUW_MIR_REV);
|
||||
else
|
||||
BU92725GUW_set_trans_way(BU92725GUW_AUTO_MULTI_REV);
|
||||
//BU92725GUW_set_trans_way(BU92725GUW_MULTI_REV);
|
||||
//BU92725GUW_set_trans_way(BU92725GUW_FIR_REV);
|
||||
}
|
||||
|
||||
int irda_hw_get_mode(void)
|
||||
{
|
||||
return curTrans_way;
|
||||
#if 0
|
||||
u16 val = 0;
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
RK29IR_DBG("line %d: enter %s, REG_TRCR_ADDR = 0x%x\n", __LINE__, __FUNCTION__, val);
|
||||
|
||||
return (val& (REG_TRCR_TX_EN | REG_TRCR_RX_EN));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: set data transfer way
|
||||
*
|
||||
* Paras: way - transfer way will be set; value is from enum eThrans_Way
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void BU92725GUW_set_trans_way(u32 way)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
if (way == curTrans_way)
|
||||
return;
|
||||
|
||||
curTrans_way = way;
|
||||
|
||||
/* set bu92725guw registers */
|
||||
/* [Modify] AIC 2011/09/27
|
||||
*
|
||||
* internal_set(1);
|
||||
*/
|
||||
internal_set(0);
|
||||
/* [Modify] AIC 2011/09/27 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: clear fifo
|
||||
*
|
||||
* Paras: none
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void BU92725GUW_clr_fifo(void)
|
||||
{
|
||||
volatile u16 val;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/* set TRCR4:FCLR */
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
val &= 0xff8f;
|
||||
val |= REG_TRCR_FCLR;
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, val);
|
||||
|
||||
/* wait op complete */
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
while (val & REG_TRCR_FCLR)
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: read frame data from fifo
|
||||
*
|
||||
* Paras: buf - point to buffer for storing frame data
|
||||
*
|
||||
* Return: number of data got from fifo (in byte)
|
||||
*/
|
||||
u16 BU92725GUW_get_data(u8 *buf)
|
||||
{
|
||||
volatile u16 data;
|
||||
u16 len, count, i;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (curTrans_way == BU92725GUW_MULTI_REV) {
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_FLV_CP|REG_TRCR_RX_CON|REG_TRCR_RX_EN);
|
||||
}
|
||||
|
||||
/* get data count from FLV or FLVII */
|
||||
if ((curTrans_way == BU92725GUW_REV) || (curTrans_way == BU92725GUW_MIR_REV)
|
||||
|| (curTrans_way == BU92725GUW_FIR_REV))
|
||||
len = BU92725GUW_READ_REG(REG_FLV_ADDR);
|
||||
else
|
||||
len = BU92725GUW_READ_REG(REG_FLVII_ADDR);
|
||||
|
||||
count = (len % 2)? (len / 2 + 1) : (len / 2);
|
||||
|
||||
/* read data from RXD */
|
||||
for (i=0; i<count; i++) {
|
||||
data = BU92725GUW_READ_REG(REG_RXD_ADDR);
|
||||
buf[i * 2] = (u8)data;
|
||||
buf[i * 2 + 1] = (u8)(data >> 8);
|
||||
}
|
||||
|
||||
/* restart receive mode under SIR */
|
||||
if ((curTrans_way == BU92725GUW_REV) || (curTrans_way == BU92725GUW_MIR_REV)
|
||||
|| (curTrans_way == BU92725GUW_FIR_REV)){
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, 0x0000);
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_RX_EN);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: write data from buffer1 and buffer2 into fifo
|
||||
*
|
||||
* Paras: buf1 - point to buffer 1
|
||||
* len1 - length of data to write into fifo from buffer 1
|
||||
* buf2 - point to buffer 2
|
||||
* len2 - length of data to write into fifo from buffer 2
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void BU92725GUW_send_data(u8 *buf1, u16 len1, u8 *buf2, u16 len2)
|
||||
{/* buf2,len2 will be used by framer under MIR/FIR mode */
|
||||
u16 data, len, pos;
|
||||
u8 *ptr;
|
||||
|
||||
len = len1 + len2;
|
||||
pos = 0;
|
||||
ptr = (u8 *)(&data);
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
/* set FTLV */
|
||||
BU92725GUW_WRITE_REG(REG_FTLV_ADDR, len);
|
||||
|
||||
/* set TRCR:TX_EN under normal send mode */
|
||||
if ((curTrans_way == BU92725GUW_SEND) || (curTrans_way == BU92725GUW_MIR_SEND)
|
||||
|| (curTrans_way == BU92725GUW_FIR_SEND)) {
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_TX_EN);
|
||||
}
|
||||
|
||||
|
||||
/* set TXD */
|
||||
while (pos < len) {
|
||||
|
||||
*ptr++ = (pos < len1)? buf1[pos] : buf2[pos-len1];
|
||||
|
||||
pos++;
|
||||
|
||||
if (pos < len) {
|
||||
*ptr-- = (pos < len1)? buf1[pos] : buf2[pos-len1];
|
||||
} else
|
||||
*ptr-- = 0x00;
|
||||
|
||||
pos++;
|
||||
|
||||
BU92725GUW_WRITE_REG(REG_TXD_ADDR, data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: set frame sending interval under multi-window send mode
|
||||
*
|
||||
* Paras: us - interval time value to set
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void BU92725GUW_set_frame_interval(u32 us)
|
||||
{
|
||||
volatile u16 val;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/* set PWR/FIT */
|
||||
|
||||
val = BU92725GUW_READ_REG(REG_PWR_FIT_ADDR);
|
||||
//val &= 0xf8ff;
|
||||
val &= 0xf0ff;
|
||||
|
||||
if (us <= 100)
|
||||
val |= REG_PWR_FIT_FIT_0;
|
||||
else if (us <= 200)
|
||||
val |= REG_PWR_FIT_FIT_1;
|
||||
else if (us <= 300)
|
||||
val |= REG_PWR_FIT_FIT_2;
|
||||
else if (us <= 400)
|
||||
val |= REG_PWR_FIT_FIT_3;
|
||||
else if (us <= 500)
|
||||
val |= REG_PWR_FIT_FIT_4;
|
||||
else if (us <= 600)
|
||||
val |= REG_PWR_FIT_FIT_5;
|
||||
else if (us <= 800)
|
||||
val |= REG_PWR_FIT_FIT_6;
|
||||
else if (us <= 1000)
|
||||
val |= REG_PWR_FIT_FIT_7;
|
||||
else if (us <= 1200)
|
||||
val |= REG_PWR_FIT_FIT_8;
|
||||
else if (us <= 1400)
|
||||
val |= REG_PWR_FIT_FIT_9;
|
||||
else if (us <= 1600)
|
||||
val |= REG_PWR_FIT_FIT_A;
|
||||
else if (us <= 1800)
|
||||
val |= REG_PWR_FIT_FIT_B;
|
||||
else if (us <= 2000)
|
||||
val |= REG_PWR_FIT_FIT_C;
|
||||
else if (us <= 2200)
|
||||
val |= REG_PWR_FIT_FIT_D;
|
||||
else if (us <= 2400)
|
||||
val |= REG_PWR_FIT_FIT_E;
|
||||
else
|
||||
val |= REG_PWR_FIT_FIT_F;
|
||||
|
||||
BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, val);
|
||||
|
||||
//curFIT = val & 0x0700;
|
||||
curFIT = val & 0x0F00;
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: return current transfer mode (SIR/MIR/FIR)
|
||||
*
|
||||
* Paras: none
|
||||
*
|
||||
* Return: current transfer mode
|
||||
*/
|
||||
u32 BU92725GUW_get_trans_mode(void)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
return curTrans_mode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: add a IrDA pulse following frame
|
||||
*
|
||||
* Paras: none
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void BU92725GUW_add_pulse(void)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/* valid only under M/FIR send mode */
|
||||
if (curTrans_way != BU92725GUW_MULTI_SEND)
|
||||
return;
|
||||
|
||||
/* set TRCR3:IR_PLS */
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_IR_PLS | REG_TRCR_TX_CON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synopsis: soft reset bu92725guw board; will be called after some error happened
|
||||
*
|
||||
* Paras: none
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void BU92725GUW_reset(void)
|
||||
{
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/* set bu925725guw registers */
|
||||
internal_set(1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
local Function Implement
|
||||
----------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Synopsis: set bu92725guw internal registers
|
||||
*
|
||||
* Paras: modeChg - need set TRCR5:MS_EN or not
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
static void internal_set(u8 modeChg)
|
||||
{
|
||||
volatile u16 val;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/* disable INT */
|
||||
BU92725GUW_WRITE_REG(REG_IER_ADDR, 0x0000);
|
||||
val = BU92725GUW_READ_REG(REG_EIR_ADDR);
|
||||
|
||||
/* MCR */
|
||||
val = 0;
|
||||
switch (curTrans_mode) {
|
||||
case BU92725GUW_SIR: //00
|
||||
val |= REG_MCR_SIR;
|
||||
break;
|
||||
case BU92725GUW_MIR: //01
|
||||
val |= REG_MCR_MIR;
|
||||
break;
|
||||
case BU92725GUW_FIR: //10
|
||||
val |= REG_MCR_FIR;
|
||||
break;
|
||||
}
|
||||
switch (curTrans_speed) {
|
||||
case 2400: //000
|
||||
val |= REG_MCR_2400;
|
||||
break;
|
||||
case 9600: //010
|
||||
val |= REG_MCR_9600;
|
||||
break;
|
||||
case 19200: //011
|
||||
val |= REG_MCR_19200;
|
||||
break;
|
||||
case 38400: //100
|
||||
val |= REG_MCR_38400;
|
||||
break;
|
||||
case 57600: //101
|
||||
val |= REG_MCR_57600;
|
||||
break;
|
||||
case 115200: //110
|
||||
val |= REG_MCR_115200;
|
||||
break;
|
||||
case 576000: //001
|
||||
val |= REG_MCR_576K;
|
||||
break;
|
||||
case 1152000: //010
|
||||
val |= REG_MCR_1152K;
|
||||
break;
|
||||
case 4000000: //010
|
||||
val |= REG_MCR_4M;
|
||||
break;
|
||||
}
|
||||
BU92725GUW_WRITE_REG(REG_MCR_ADDR, val);
|
||||
RK29IR_DBG("REG_MCR_ADDR: 0x%x\n", val);
|
||||
|
||||
/* PWR / FIT */
|
||||
switch (curTrans_mode) {
|
||||
case BU92725GUW_SIR:
|
||||
val = 0x0000;
|
||||
break;
|
||||
case BU92725GUW_MIR:
|
||||
val = REG_PWR_FIT_MPW_3 | curFIT;
|
||||
break;
|
||||
case BU92725GUW_FIR:
|
||||
val = REG_PWR_FIT_FPW_2 | curFIT;
|
||||
break;
|
||||
}
|
||||
BU92725GUW_WRITE_REG(REG_PWR_FIT_ADDR, val);
|
||||
RK29IR_DBG("REG_PWR_FIT_ADDR: 0x%x\n", val);
|
||||
|
||||
/* TRCR:MS_EN */
|
||||
if (modeChg) {
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, REG_TRCR_MS_EN);
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
while (val & REG_TRCR_MS_EN) {
|
||||
val = BU92725GUW_READ_REG(REG_TRCR_ADDR);
|
||||
}
|
||||
}
|
||||
|
||||
/* TRCR */
|
||||
switch (curTrans_way) {
|
||||
case BU92725GUW_IDLE:
|
||||
val = 0x0000;
|
||||
break;
|
||||
case BU92725GUW_REV:
|
||||
case BU92725GUW_MIR_REV:
|
||||
case BU92725GUW_FIR_REV:
|
||||
val = REG_TRCR_RX_EN;
|
||||
break;
|
||||
case BU92725GUW_AUTO_MULTI_REV:
|
||||
val = REG_TRCR_RX_EN | REG_TRCR_AUTO_FLV_CP;
|
||||
break;
|
||||
case BU92725GUW_MULTI_REV:
|
||||
val = REG_TRCR_RX_EN | REG_TRCR_RX_CON;//FIR
|
||||
break;
|
||||
case BU92725GUW_SEND:
|
||||
case BU92725GUW_MIR_SEND:
|
||||
case BU92725GUW_FIR_SEND:
|
||||
val = 0x0000;
|
||||
break;
|
||||
case BU92725GUW_MULTI_SEND:
|
||||
val = REG_TRCR_TX_CON;
|
||||
break;
|
||||
}
|
||||
BU92725GUW_WRITE_REG(REG_TRCR_ADDR, val);
|
||||
RK29IR_DBG("REG_TRCR_ADDR: 0x%x\n", val);
|
||||
|
||||
/* IER */
|
||||
switch (curTrans_way) {
|
||||
case BU92725GUW_IDLE:
|
||||
val = 0x0000;
|
||||
break;
|
||||
|
||||
case BU92725GUW_REV: /* SIR use */
|
||||
val = REG_INT_EOFRX | REG_INT_TO | REG_INT_OE | REG_INT_FE; //IER1, 2, 5, 7
|
||||
break;
|
||||
|
||||
case BU92725GUW_MIR_REV: /* MIR use */
|
||||
val = REG_INT_STFRX | REG_INT_TO | REG_INT_OE | REG_INT_EOF
|
||||
| REG_INT_AC | REG_INT_DECE; //IER1,2, 5, 6, 7
|
||||
break;
|
||||
|
||||
case BU92725GUW_FIR_REV: /* FIR use */
|
||||
val = REG_INT_STFRX | REG_INT_TO | REG_INT_CRC | REG_INT_OE | REG_INT_EOF \
|
||||
| REG_INT_AC | REG_INT_DECE; //IER1,2, 4, 5, 6, 7
|
||||
break;
|
||||
|
||||
case BU92725GUW_MULTI_REV: /* not used */
|
||||
val = REG_INT_STFRX | REG_INT_TO | REG_INT_CRC | REG_INT_OE | REG_INT_EOF | REG_INT_AC | REG_INT_DECE \
|
||||
| REG_INT_RDOE | REG_INT_DEX | REG_INT_RDUE; //IER1,2, 4, 5, 6, 7, 8, 9, 10
|
||||
break;
|
||||
|
||||
case BU92725GUW_AUTO_MULTI_REV: /* M/FIR use */
|
||||
val = REG_INT_TO | REG_INT_CRC | REG_INT_OE | REG_INT_EOF | REG_INT_AC | REG_INT_DECE\
|
||||
| REG_INT_RDOE | REG_INT_DEX | REG_INT_RDE; //IER2, 4, 5, 6, 7, 8, 9, 12
|
||||
break;
|
||||
|
||||
case BU92725GUW_SEND: /* SIR use */
|
||||
val = REG_INT_TXE; //IER3
|
||||
break;
|
||||
|
||||
case BU92725GUW_MIR_SEND:
|
||||
case BU92725GUW_FIR_SEND:
|
||||
val = REG_INT_TXE | REG_INT_TO; //IER2, 3
|
||||
break;
|
||||
|
||||
case BU92725GUW_MULTI_SEND: /* M/FIR use */
|
||||
val = REG_INT_TO | REG_INT_TXE | REG_INT_WRE; //IER2, 3, 11
|
||||
break;
|
||||
}
|
||||
BU92725GUW_WRITE_REG(REG_IER_ADDR, val);
|
||||
RK29IR_DBG("REG_IER_ADDR: 0x%x\n", val);
|
||||
}
|
||||
|
||||
void BU92725GUW_dump_register(void)
|
||||
{
|
||||
printk("bu92725 register value:\n");
|
||||
printk("MCR: 0x%x\n", BU92725GUW_READ_REG(REG_MCR_ADDR));
|
||||
printk("FIT: 0x%x\n", BU92725GUW_READ_REG(REG_PWR_FIT_ADDR));
|
||||
printk("TRCR: 0x%x\n", BU92725GUW_READ_REG(REG_TRCR_ADDR));
|
||||
printk("IER: 0x%x\n", BU92725GUW_READ_REG(REG_IER_ADDR));
|
||||
}
|
||||
|
||||
/* [Add] AIC 2011/09/29 */
|
||||
int BU92725GUW_get_length_in_fifo_buffer(void)
|
||||
{
|
||||
return( (int)BU92725GUW_READ_REG(REG_FLV_ADDR) );
|
||||
}
|
||||
/* [Add-end] AIC 2011/09/29 */
|
||||
@@ -1,235 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/***************************************************************************
|
||||
*
|
||||
* File: bu92725guw.h
|
||||
*
|
||||
* Description: This file contains configuration constants for the
|
||||
* bu92725guw board.
|
||||
*
|
||||
* Created: 2007/9
|
||||
*
|
||||
* Rev 1.1
|
||||
*
|
||||
*
|
||||
* Confidential ROHM CO.,LTD.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef __BU92725GUW_H
|
||||
#define __BU92725GUW_H
|
||||
|
||||
#include "mach/rk29_smc.h"
|
||||
|
||||
|
||||
/* irda registers addr must be 2*ori_register when use smc control*/
|
||||
#define REG_TXD_ADDR 0
|
||||
#define REG_RXD_ADDR 0
|
||||
#define REG_IER_ADDR 2
|
||||
#define REG_EIR_ADDR 4
|
||||
#define REG_MCR_ADDR 6
|
||||
#define REG_PWR_FIT_ADDR 8
|
||||
#define REG_TRCR_ADDR 10
|
||||
#define REG_FTLV_ADDR 12
|
||||
#define REG_FLV_ADDR 14
|
||||
#define REG_FLVII_ADDR 16
|
||||
#define REG_FLVIII_ADDR 18
|
||||
#define REG_FLVIV_ADDR 20
|
||||
#define REG_TRCRII_ADDR 22
|
||||
#define REG_TXEC_ADDR 24
|
||||
#define REG_WREC_ADDR 26
|
||||
|
||||
/*
|
||||
*register bits definition (registers are all 16 bits)
|
||||
*/
|
||||
//interrupt reg (IER and EIR)
|
||||
#define REG_INT_DRX (0x0001 << 0)
|
||||
#define REG_INT_EOFRX (0x0001 << 1)
|
||||
#define REG_INT_STFRX (0x0001 << 1)
|
||||
#define REG_INT_TO (0x0001 << 2)
|
||||
#define REG_INT_TXE (0x0001 << 3)
|
||||
#define REG_INT_CRC (0x0001 << 4)
|
||||
#define REG_INT_OE (0x0001 << 5)
|
||||
#define REG_INT_EOF (0x0001 << 6)
|
||||
#define REG_INT_FE (0x0001 << 7)
|
||||
#define REG_INT_AC (0x0001 << 7)
|
||||
#define REG_INT_DECE (0x0001 << 7)
|
||||
#define REG_INT_RDOE (0x0001 << 8)
|
||||
#define REG_INT_DEX (0x0001 << 9)
|
||||
#define REG_INT_RDUE (0x0001 << 10)
|
||||
#define REG_INT_WRE (0x0001 << 11)
|
||||
#define REG_INT_RDE (0x0001 << 12)
|
||||
|
||||
//MCR
|
||||
#define REG_MCR_CTLA 0x1000
|
||||
#define REG_MCR_RC_MODE 0x0800
|
||||
#define REG_MCR_RC_EN 0x0400
|
||||
#define REG_MCR_2400 (0x0000 << 5)
|
||||
#define REG_MCR_9600 (0x0002 << 5) //default
|
||||
#define REG_MCR_19200 (0x0003 << 5)
|
||||
#define REG_MCR_38400 (0x0004 << 5)
|
||||
#define REG_MCR_57600 (0x0005 << 5)
|
||||
#define REG_MCR_115200 (0x0006 << 5)
|
||||
#define REG_MCR_576K (0x0001 << 5)
|
||||
#define REG_MCR_1152K (0x0002 << 5)
|
||||
#define REG_MCR_4M (0x0002 << 5)
|
||||
#define REG_MCR_SIR 0x0000 //default
|
||||
#define REG_MCR_MIR 0x0001
|
||||
#define REG_MCR_FIR 0x0002
|
||||
|
||||
|
||||
/* flag event bit
|
||||
*/
|
||||
#define FRM_EVT_RX_EOFRX REG_INT_EOFRX //IER1
|
||||
#define FRM_EVT_RX_RDE REG_INT_RDE //IER12
|
||||
#define FRM_EVT_TX_TXE REG_INT_TXE //IER3
|
||||
#define FRM_EVT_TX_WRE REG_INT_WRE //IER11
|
||||
#define FRM_EVT_EXIT_NOW 0x00010000
|
||||
|
||||
|
||||
enum eTrans_Mode {
|
||||
BU92725GUW_SIR = 0,
|
||||
BU92725GUW_MIR,
|
||||
BU92725GUW_FIR,
|
||||
};
|
||||
enum eTrans_Speed {
|
||||
BU92725GUW_2400 = 0,
|
||||
BU92725GUW_9600,
|
||||
BU92725GUW_19200,
|
||||
BU92725GUW_38400,
|
||||
BU92725GUW_57600,
|
||||
BU92725GUW_115200,
|
||||
BU92725GUW_576K,
|
||||
BU92725GUW_1152K,
|
||||
BU92725GUW_4M,
|
||||
};
|
||||
|
||||
//PWR/FIT
|
||||
#define REG_PWR_FIT_SPW 0x0001
|
||||
#define REG_PWR_FIT_MPW_0 (0x0000 << 1)
|
||||
#define REG_PWR_FIT_MPW_1 (0x0001 << 1)
|
||||
#define REG_PWR_FIT_MPW_2 (0x0002 << 1)
|
||||
#define REG_PWR_FIT_MPW_3 (0x0003 << 1) //default
|
||||
#define REG_PWR_FIT_MPW_4 (0x0004 << 1)
|
||||
#define REG_PWR_FIT_MPW_5 (0x0005 << 1)
|
||||
#define REG_PWR_FIT_MPW_6 (0x0006 << 1)
|
||||
#define REG_PWR_FIT_MPW_7 (0x0007 << 1)
|
||||
#define REG_PWR_FIT_MPW_8 (0x0008 << 1)
|
||||
#define REG_PWR_FIT_MPW_9 (0x0009 << 1)
|
||||
#define REG_PWR_FIT_MPW_10 (0x000A << 1)
|
||||
#define REG_PWR_FIT_MPW_11 (0x000B << 1)
|
||||
#define REG_PWR_FIT_MPW_12 (0x000C << 1)
|
||||
#define REG_PWR_FIT_MPW_13 (0x000D << 1)
|
||||
#define REG_PWR_FIT_MPW_14 (0x000E << 1)
|
||||
#define REG_PWR_FIT_MPW_15 (0x000F << 1)
|
||||
#define REG_PWR_FIT_FPW_0 (0x0000 << 5)
|
||||
#define REG_PWR_FIT_FPW_1 (0x0001 << 5)
|
||||
#define REG_PWR_FIT_FPW_2 (0x0002 << 5) //default
|
||||
#define REG_PWR_FIT_FPW_3 (0x0003 << 5)
|
||||
#define REG_PWR_FIT_FIT_0 (0x0000 << 8) //default
|
||||
#define REG_PWR_FIT_FIT_1 (0x0001 << 8)
|
||||
#define REG_PWR_FIT_FIT_2 (0x0002 << 8)
|
||||
#define REG_PWR_FIT_FIT_3 (0x0003 << 8)
|
||||
#define REG_PWR_FIT_FIT_4 (0x0004 << 8)
|
||||
#define REG_PWR_FIT_FIT_5 (0x0005 << 8)
|
||||
#define REG_PWR_FIT_FIT_6 (0x0006 << 8)
|
||||
#define REG_PWR_FIT_FIT_7 (0x0007 << 8)
|
||||
#define REG_PWR_FIT_FIT_8 (0x0008 << 8) //default
|
||||
#define REG_PWR_FIT_FIT_9 (0x0009 << 8)
|
||||
#define REG_PWR_FIT_FIT_A (0x000A << 8)
|
||||
#define REG_PWR_FIT_FIT_B (0x000B << 8)
|
||||
#define REG_PWR_FIT_FIT_C (0x000C << 8)
|
||||
#define REG_PWR_FIT_FIT_D (0x000D << 8)
|
||||
#define REG_PWR_FIT_FIT_E (0x000E << 8)
|
||||
#define REG_PWR_FIT_FIT_F (0x000F << 8)
|
||||
|
||||
//TRCR
|
||||
#define REG_TRCR_TX_EN 0x0001
|
||||
#define REG_TRCR_RX_EN (0x0001 << 1)
|
||||
#define REG_TRCR_S_EOT (0x0001 << 2)
|
||||
#define REG_TRCR_IR_PLS (0x0001 << 3)
|
||||
#define REG_TRCR_FCLR (0x0001 << 4)
|
||||
#define REG_TRCR_MS_EN (0x0001 << 5)
|
||||
#define REG_TRCR_IRPD (0x0001 << 6)
|
||||
#define REG_TRCR_M_STA (0x0001 << 7)
|
||||
#define REG_TRCR_RXPWD (0x0001 << 8)
|
||||
#define REG_TRCR_TXPWD (0x0001 << 9)
|
||||
#define REG_TRCR_ONE_BIT_R (0x0001 << 10)
|
||||
#define REG_TRCR_AUTO_FLV_CP (0x0001 << 11)
|
||||
#define REG_TRCR_RX_CON (0x0001 << 12)
|
||||
#define REG_TRCR_FLV_CP (0x0001 << 13)
|
||||
#define REG_TRCR_TX_CON (0x0001 << 14)
|
||||
#define REG_TRCR_TX_NUM (0x0001 << 15)
|
||||
|
||||
enum eThrans_Way {
|
||||
BU92725GUW_IDLE = 0,
|
||||
BU92725GUW_REV, /* SIR use */
|
||||
BU92725GUW_SEND, /* SIR use */
|
||||
BU92725GUW_MIR_REV, /* MIR use */
|
||||
BU92725GUW_MIR_SEND, /* MIR use */
|
||||
BU92725GUW_FIR_REV, /* FIR use */
|
||||
BU92725GUW_FIR_SEND, /* FIR use */
|
||||
BU92725GUW_AUTO_MULTI_REV, /* M/FIR use */
|
||||
BU92725GUW_MULTI_REV, /* not used */
|
||||
BU92725GUW_MULTI_SEND, /* M/FIR use */
|
||||
};
|
||||
|
||||
|
||||
#define BU92725GUW_FIFO_SIZE (2560 * 2)
|
||||
|
||||
#define BU92725GUW_MAX_FRM_INTERVAL 1000 /* 1000us */
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Functions used by framer
|
||||
----------------------------------------------------------------------------*/
|
||||
#define BU92725GUW_READ_REG(regAddr) smc0_read(regAddr)
|
||||
#define BU92725GUW_WRITE_REG(regAddr, data) smc0_write(regAddr, data)
|
||||
|
||||
|
||||
/* board initialize */
|
||||
extern void BU92725GUW_init(void);
|
||||
|
||||
/* board deinit */
|
||||
extern void BU92725GUW_deinit(void);
|
||||
|
||||
/* set data transfer speed */
|
||||
extern void BU92725GUW_set_trans_speed(u32 speed);
|
||||
|
||||
/* set frame transfer way */
|
||||
extern void BU92725GUW_set_trans_way(u32 way);
|
||||
|
||||
/* flush fifo */
|
||||
extern void BU92725GUW_clr_fifo(void);
|
||||
|
||||
/* set frame sending interval */
|
||||
extern void BU92725GUW_set_frame_interval(u32 us);
|
||||
|
||||
/* insert IrDA pulse follow frame sending */
|
||||
extern void BU92725GUW_add_pulse(void);
|
||||
|
||||
/* soft reset when some error happened */
|
||||
extern void BU92725GUW_reset(void);
|
||||
|
||||
/* return transfer mode */
|
||||
extern u32 BU92725GUW_get_trans_mode(void);
|
||||
|
||||
/* get frame data from fifo */
|
||||
extern u16 BU92725GUW_get_data(u8 *buf);
|
||||
|
||||
/* send frame data into fifo */
|
||||
extern void BU92725GUW_send_data(u8 *buf1, u16 len1, u8 *buf2, u16 len2);
|
||||
|
||||
/*dump register*/
|
||||
extern void BU92725GUW_dump_register(void);
|
||||
|
||||
int irda_hw_tx_enable_irq(enum eTrans_Mode mode);
|
||||
int irda_hw_get_mode(void);
|
||||
void irda_hw_set_moderx(void);
|
||||
int irda_hw_get_irqsrc(void);
|
||||
int irda_hw_shutdown(void);
|
||||
int irda_hw_startup(void);
|
||||
int irda_hw_set_speed(u32 speed);
|
||||
|
||||
/* [Add] AIC 2011/09/29 */
|
||||
int BU92725GUW_get_length_in_fifo_buffer(void);
|
||||
/* [Add-end] AIC 2011/09/29 */
|
||||
|
||||
#endif /*__BU92725GUW_H*/
|
||||
@@ -1,866 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2011 liuyixing <lyx@rock-chips.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
*note: serial driver for IrDA(SIR and FIR) device
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <mach/board.h>
|
||||
#include <linux/irq.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "bu92725guw.h"
|
||||
#include "ir_serial.h"
|
||||
|
||||
|
||||
#define MAX_FRAME_NUM 20
|
||||
struct rev_frame_length {
|
||||
unsigned long frame_length[MAX_FRAME_NUM];
|
||||
int iRead;
|
||||
int iWrite;
|
||||
int iCount;
|
||||
};
|
||||
|
||||
#define frame_read_empty(f) ((f)->iCount == 0)
|
||||
#define frame_write_full(f) ((f)->iCount == MAX_FRAME_NUM)
|
||||
#define frame_length_buf_clear(f) ((f)->iCount = (f)->iWrite = (f)->iRead = 0)
|
||||
|
||||
struct bu92747_port {
|
||||
struct device *dev;
|
||||
struct irda_info *pdata;
|
||||
struct uart_port port;
|
||||
|
||||
/*for FIR fream read*/
|
||||
struct rev_frame_length rev_frames;
|
||||
//unsigned long last_frame_length;
|
||||
unsigned long cur_frame_length;
|
||||
//wait_queue_head_t data_ready_wq;
|
||||
//atomic_t data_ready;
|
||||
spinlock_t data_lock;
|
||||
|
||||
int tx_empty; /* last TX empty bit */
|
||||
|
||||
spinlock_t conf_lock; /* shared data */
|
||||
int baud; /* current baud rate */
|
||||
|
||||
int rx_enabled; /* if we should rx chars */
|
||||
|
||||
int irq_pin;
|
||||
int irq; /* irq assigned to the bu92747 */
|
||||
|
||||
int minor; /* minor number */
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct work;
|
||||
/* set to 1 to make the workhandler exit as soon as possible */
|
||||
int force_end_work;
|
||||
|
||||
int open_flag;
|
||||
/* need to know we are suspending to avoid deadlock on workqueue */
|
||||
int suspending;
|
||||
|
||||
};
|
||||
|
||||
#define MAX_BU92747 1
|
||||
#define BU92747_MAJOR 204
|
||||
#define BU92747_MINOR 209
|
||||
|
||||
static struct bu92747_port *bu92747s[MAX_BU92747]; /* the chips */
|
||||
static DEFINE_MUTEX(bu92747s_lock); /* race on probe */
|
||||
#define IS_FIR(s) ((s)->baud >= 4000000)
|
||||
static int max_rate = 4000000;
|
||||
static u8 g_receive_buf[BU92725GUW_FIFO_SIZE];
|
||||
|
||||
#if 0
|
||||
#define IRDA_DBG_FUNC(x...) printk(x)
|
||||
#else
|
||||
#define IRDA_DBG_FUNC(x...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define IRDA_DBG_RECV(x...) printk(x)
|
||||
#else
|
||||
#define IRDA_DBG_RECV(x...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define IRDA_DBG_SENT(x...) printk(x)
|
||||
#else
|
||||
#define IRDA_DBG_SENT(x...)
|
||||
#endif
|
||||
|
||||
/* race on startup&shutdown, mutex lock with CIR driver */
|
||||
static DEFINE_MUTEX(irda_cir_lock);
|
||||
int bu92747_try_lock(void)
|
||||
{
|
||||
if (mutex_trylock(&irda_cir_lock))
|
||||
return 1; //ready
|
||||
else
|
||||
return 0; //busy
|
||||
}
|
||||
|
||||
void bu92747_unlock(void)
|
||||
{
|
||||
return mutex_unlock(&irda_cir_lock);
|
||||
}
|
||||
|
||||
static int add_frame_length(struct rev_frame_length *f, unsigned long length)
|
||||
{
|
||||
if (frame_write_full(f))
|
||||
return -1;
|
||||
|
||||
f->frame_length[f->iWrite] = length;
|
||||
f->iCount++;
|
||||
f->iWrite = (f->iWrite+1) % MAX_FRAME_NUM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_frame_length(struct rev_frame_length *f, unsigned long *length)
|
||||
{
|
||||
if (frame_read_empty(f))
|
||||
return -1;
|
||||
|
||||
*length = f->frame_length[f->iRead];
|
||||
f->iCount--;
|
||||
f->iRead = (f->iRead+1) % MAX_FRAME_NUM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu92747_irda_do_rx(struct bu92747_port *s)
|
||||
{
|
||||
//int i;
|
||||
//unsigned int ch, flag;
|
||||
int len;
|
||||
struct tty_struct *tty = s->port.state->port.tty;
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (s->rx_enabled == 0) {
|
||||
BU92725GUW_clr_fifo();
|
||||
BU92725GUW_reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = BU92725GUW_get_data(g_receive_buf);
|
||||
#if 0
|
||||
flag = TTY_NORMAL;
|
||||
//printk("receive data:\n");
|
||||
for (i=0;i<len;i++) {
|
||||
ch = g_receive_buf[i];
|
||||
uart_insert_char(&s->port, 0, 0, ch, flag);
|
||||
s->port.icount.rx++;
|
||||
//printk("%d ", ch);
|
||||
}
|
||||
//printk("\n");
|
||||
#else
|
||||
if (len > 0) {
|
||||
IRDA_DBG_RECV("line %d, enter %s, receive %d data........\n", __LINE__, __func__, len);
|
||||
tty_insert_flip_string(tty, g_receive_buf, len);
|
||||
s->port.icount.rx += len;
|
||||
}
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
static int bu92747_irda_do_tx(struct bu92747_port *s)
|
||||
{
|
||||
//int i;
|
||||
struct circ_buf *xmit = &s->port.state->xmit;
|
||||
int len = uart_circ_chars_pending(xmit);
|
||||
int len1, len2;
|
||||
IRDA_DBG_SENT("line %d, enter %s, sending %d data\n", __LINE__, __FUNCTION__, len);
|
||||
|
||||
if (IS_FIR(s)) {
|
||||
irda_hw_tx_enable_irq(BU92725GUW_FIR);
|
||||
}
|
||||
else {
|
||||
irda_hw_tx_enable_irq(BU92725GUW_SIR);
|
||||
}
|
||||
|
||||
if (len>0) {
|
||||
s->tx_empty = 0;
|
||||
}
|
||||
|
||||
/* [Modify] AIC 2011/09/27
|
||||
* BU92725GUW_send_data(xmit->buf+xmit->tail, len, NULL, 0);
|
||||
*/
|
||||
if ( (xmit->tail + len) > UART_XMIT_SIZE ) {
|
||||
len1 = UART_XMIT_SIZE - xmit->tail;
|
||||
len2 = len - len1;
|
||||
BU92725GUW_send_data(xmit->buf+xmit->tail, len1, xmit->buf, len2);
|
||||
} else {
|
||||
BU92725GUW_send_data(xmit->buf+xmit->tail, len, NULL, 0);
|
||||
}
|
||||
/* [Modify-end] AIC 2011/09/27 */
|
||||
s->port.icount.tx += len;
|
||||
xmit->tail = (xmit->tail + len) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&s->port);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void bu92747_irda_dowork(struct bu92747_port *s)
|
||||
{
|
||||
if (!s->force_end_work && !work_pending(&s->work) &&
|
||||
!freezing(current) && !s->suspending)
|
||||
queue_work(s->workqueue, &s->work);
|
||||
}
|
||||
|
||||
static void bu92747_irda_work(struct work_struct *w)
|
||||
{
|
||||
struct bu92747_port *s = container_of(w, struct bu92747_port, work);
|
||||
struct circ_buf *xmit = &s->port.state->xmit;
|
||||
|
||||
IRDA_DBG_SENT("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (!s->force_end_work && !freezing(current)) {
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
|
||||
if (s->tx_empty)
|
||||
bu92747_irda_do_tx(s);
|
||||
else
|
||||
bu92747_irda_dowork(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t bu92747_irda_irq(int irqno, void *dev_id)
|
||||
{
|
||||
struct bu92747_port *s = dev_id;
|
||||
u32 irq_src = 0;
|
||||
unsigned long len;
|
||||
struct rev_frame_length *f = &(s->rev_frames);
|
||||
|
||||
irq_src = irda_hw_get_irqsrc();
|
||||
IRDA_DBG_RECV("[%s][%d], 0x%x\n",__FUNCTION__,__LINE__, irq_src);
|
||||
|
||||
/* error */
|
||||
if (irq_src & (REG_INT_CRC | REG_INT_OE | REG_INT_FE
|
||||
| REG_INT_AC | REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX)) {
|
||||
printk("[%s][%d]: do err, REG_EIR = 0x%x\n", __FUNCTION__, __LINE__, irq_src);
|
||||
BU92725GUW_clr_fifo();
|
||||
BU92725GUW_reset();
|
||||
if ((BU92725GUW_SEND==irda_hw_get_mode())
|
||||
|| (BU92725GUW_MULTI_SEND==irda_hw_get_mode())) {
|
||||
s->tx_empty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_src & (REG_INT_DRX | FRM_EVT_RX_EOFRX | FRM_EVT_RX_RDE)) {
|
||||
//fixing CA001 (IrSimple mode sending) failing issue
|
||||
/* modified to process a frame ending processing first, when RDE_EI and EOF_EI are happen at the same time.
|
||||
* Before the modification, disconnect packet was processed as the previous packet,
|
||||
* not as a disconnect packet. The packets were combined.
|
||||
*/
|
||||
if ((irq_src & REG_INT_EOF) && (s->port.state->port.tty != NULL)) {
|
||||
tty_flip_buffer_push(s->port.state->port.tty);
|
||||
if (IS_FIR(s)) {
|
||||
spin_lock(&s->data_lock);
|
||||
if (add_frame_length(f, s->cur_frame_length) == 0) {
|
||||
s->cur_frame_length = 0;
|
||||
}
|
||||
else {
|
||||
printk("func %s,line %d: FIR frame length buf full......\n", __FUNCTION__, __LINE__);
|
||||
}
|
||||
spin_unlock(&s->data_lock);
|
||||
}
|
||||
}
|
||||
//~
|
||||
|
||||
len = bu92747_irda_do_rx(s);
|
||||
if (!IS_FIR(s))
|
||||
tty_flip_buffer_push(s->port.state->port.tty);
|
||||
else {
|
||||
spin_lock(&s->data_lock);
|
||||
s->cur_frame_length += len;
|
||||
spin_unlock(&s->data_lock);
|
||||
}
|
||||
}
|
||||
|
||||
if ((irq_src & REG_INT_EOF) && (s->port.state->port.tty != NULL)) {
|
||||
spin_lock(&s->data_lock); // [Modify] AIC 2011/09/30
|
||||
tty_flip_buffer_push(s->port.state->port.tty);
|
||||
if (IS_FIR(s)) {
|
||||
/* [Modify] AIC 2011/09/30
|
||||
* spin_lock(&s->data_lock);
|
||||
*/
|
||||
if (add_frame_length(f, s->cur_frame_length) == 0) {
|
||||
s->cur_frame_length = 0;
|
||||
}
|
||||
else {
|
||||
printk("func %s,line %d: FIR frame length buf full......\n", __FUNCTION__, __LINE__);
|
||||
}
|
||||
/* [Modify] AIC 2011/09/30
|
||||
* spin_unlock(&s->data_lock);
|
||||
*/
|
||||
}
|
||||
spin_unlock(&s->data_lock); // [Modify] AIC 2011/09/30
|
||||
}
|
||||
|
||||
/* [Modify] AIC 2011/09/27
|
||||
*
|
||||
* if (irq_src & (FRM_EVT_TX_TXE | FRM_EVT_TX_WRE)) {
|
||||
* s->tx_empty = 1;
|
||||
* irda_hw_set_moderx();
|
||||
* }
|
||||
*/
|
||||
/* [Modify] AIC 2011/09/29
|
||||
*
|
||||
* if (irq_src & (FRM_EVT_TX_TXE | FRM_EVT_TX_WRE)) {
|
||||
* s->tx_empty = 1;
|
||||
* if ( irq_src & FRM_EVT_TX_TXE ) {
|
||||
* irda_hw_set_moderx();
|
||||
* }
|
||||
*/
|
||||
if ( (irq_src & (FRM_EVT_TX_TXE | FRM_EVT_TX_WRE)) &&
|
||||
(BU92725GUW_get_length_in_fifo_buffer() == 0) ) {
|
||||
s->tx_empty = 1;
|
||||
|
||||
if ( irq_src & FRM_EVT_TX_TXE ) {
|
||||
irda_hw_set_moderx();
|
||||
}
|
||||
}
|
||||
/* [Modify-end] AIC 2011/09/29 */
|
||||
#if 0
|
||||
/* error */
|
||||
if (irq_src & REG_INT_TO) {
|
||||
printk("[%s][%d]: do timeout err\n", __FUNCTION__, __LINE__);
|
||||
BU92725GUW_clr_fifo();
|
||||
BU92725GUW_reset();
|
||||
if ((BU92725GUW_SEND==irda_hw_get_mode())
|
||||
|| (BU92725GUW_MULTI_SEND==irda_hw_get_mode())) {
|
||||
s->tx_empty = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static void bu92747_irda_stop_tx(struct uart_port *port)
|
||||
{
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
static void bu92747_irda_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
//wait for start cmd
|
||||
if (IS_FIR(s))
|
||||
return ;
|
||||
|
||||
bu92747_irda_dowork(s);
|
||||
}
|
||||
|
||||
static void bu92747_irda_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
s->rx_enabled = 0;
|
||||
}
|
||||
|
||||
static unsigned int bu92747_irda_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
/* may not be truly up-to-date */
|
||||
return s->tx_empty;
|
||||
}
|
||||
|
||||
static const char *bu92747_irda_type(struct uart_port *port)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
return s->port.type == PORT_IRDA ? "BU92747" : NULL;
|
||||
}
|
||||
|
||||
static void bu92747_irda_release_port(struct uart_port *port)
|
||||
{
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
static void bu92747_irda_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (flags & UART_CONFIG_TYPE)
|
||||
s->port.type = PORT_IRDA;
|
||||
}
|
||||
|
||||
static int bu92747_irda_verify_port(struct uart_port *port,
|
||||
struct serial_struct *ser)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (ser->type == PORT_UNKNOWN || ser->type == PORT_IRDA)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bu92747_irda_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
struct rev_frame_length *f = &(s->rev_frames);
|
||||
|
||||
printk("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (s->suspending)
|
||||
return;
|
||||
|
||||
s->open_flag = 0;
|
||||
s->force_end_work = 1;
|
||||
|
||||
if (s->workqueue) {
|
||||
flush_workqueue(s->workqueue);
|
||||
destroy_workqueue(s->workqueue);
|
||||
s->workqueue = NULL;
|
||||
}
|
||||
|
||||
spin_lock(&s->data_lock);
|
||||
frame_length_buf_clear(f);
|
||||
s->cur_frame_length = 0;
|
||||
spin_unlock(&s->data_lock);
|
||||
|
||||
if (s->irq)
|
||||
free_irq(s->irq, s);
|
||||
|
||||
irda_hw_shutdown();
|
||||
if (s->pdata->irda_pwr_ctl)
|
||||
s->pdata->irda_pwr_ctl(0);
|
||||
|
||||
bu92747_unlock();
|
||||
}
|
||||
|
||||
static int bu92747_irda_startup(struct uart_port *port)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
char b[32];
|
||||
struct rev_frame_length *f = &(s->rev_frames);
|
||||
|
||||
printk("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
s->rx_enabled = 1;
|
||||
|
||||
if (s->suspending)
|
||||
return 0;
|
||||
|
||||
if (!bu92747_try_lock()) {
|
||||
printk("func %s, cannot get bu92747 lock, bu92747 in using\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
s->baud = 9600;
|
||||
|
||||
spin_lock(&s->data_lock);
|
||||
frame_length_buf_clear(f);
|
||||
s->cur_frame_length = 0;
|
||||
spin_unlock(&s->data_lock);
|
||||
|
||||
s->tx_empty = 1;
|
||||
s->force_end_work = 0;
|
||||
|
||||
sprintf(b, "bu92747_irda-%d", s->minor);
|
||||
s->workqueue = create_rt_workqueue(b);
|
||||
if (!s->workqueue) {
|
||||
dev_warn(s->dev, "cannot create workqueue\n");
|
||||
bu92747_unlock();
|
||||
return -EBUSY;
|
||||
}
|
||||
INIT_WORK(&s->work, bu92747_irda_work);
|
||||
|
||||
if (request_irq(s->irq, bu92747_irda_irq,
|
||||
IRQF_TRIGGER_LOW, "bu92747_irda", s) < 0) {
|
||||
dev_warn(s->dev, "cannot allocate irq %d\n", s->irq);
|
||||
s->irq = 0;
|
||||
destroy_workqueue(s->workqueue);
|
||||
s->workqueue = NULL;
|
||||
bu92747_unlock();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
disable_irq(s->irq);
|
||||
|
||||
if (s->pdata->irda_pwr_ctl)
|
||||
s->pdata->irda_pwr_ctl(1);
|
||||
|
||||
irda_hw_startup();
|
||||
irda_hw_set_moderx();
|
||||
|
||||
enable_irq(s->irq);
|
||||
|
||||
s->open_flag = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu92747_irda_request_port(struct uart_port *port)
|
||||
{
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bu92747_irda_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
static unsigned int bu92747_irda_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
return TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void bu92747_irda_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
static void
|
||||
bu92747_irda_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
int baud = 0;
|
||||
unsigned cflag;
|
||||
struct tty_struct *tty = s->port.state->port.tty;
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
cflag = termios->c_cflag;
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, max_rate);
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
case 4000000:
|
||||
if (s->baud!=baud) {
|
||||
IRDA_DBG_RECV("func %s:irda set baudrate %d........\n", __FUNCTION__, baud);
|
||||
irda_hw_set_speed(baud);
|
||||
s->baud = baud;
|
||||
s->tx_empty = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
}
|
||||
|
||||
static int bu92747_get_frame_length(struct bu92747_port *s)
|
||||
{
|
||||
struct rev_frame_length *f = &(s->rev_frames);
|
||||
unsigned long len = 0;
|
||||
|
||||
spin_lock(&s->data_lock);
|
||||
if (get_frame_length(f, &len) != 0) {
|
||||
IRDA_DBG_RECV("func %s, line %d: FIR data not ready......\n", __FUNCTION__, __LINE__);
|
||||
len = 0;
|
||||
}
|
||||
spin_unlock(&s->data_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int bu92747_irda_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct bu92747_port *s = container_of(port,
|
||||
struct bu92747_port,
|
||||
port);
|
||||
void __user *argp = (void __user *)arg;
|
||||
unsigned long len = 0;
|
||||
int ret = 0;
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
|
||||
switch (cmd) {
|
||||
case TTYIR_GETLENGTH:
|
||||
len = bu92747_get_frame_length(s);
|
||||
if (len >= 0) {
|
||||
if (copy_to_user(argp, &len, sizeof(len)))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
else
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
|
||||
case TTYIR_STARTSEND:
|
||||
bu92747_irda_dowork(s);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct uart_ops bu92747_irda_ops = {
|
||||
.tx_empty = bu92747_irda_tx_empty,
|
||||
.set_mctrl = bu92747_irda_set_mctrl,
|
||||
.get_mctrl = bu92747_irda_get_mctrl,
|
||||
.stop_tx = bu92747_irda_stop_tx,
|
||||
.start_tx = bu92747_irda_start_tx,
|
||||
.stop_rx = bu92747_irda_stop_rx,
|
||||
//.enable_ms = bu92747_irda_enable_ms,
|
||||
.break_ctl = bu92747_irda_break_ctl,
|
||||
.startup = bu92747_irda_startup,
|
||||
.shutdown = bu92747_irda_shutdown,
|
||||
.set_termios = bu92747_irda_set_termios,
|
||||
.type = bu92747_irda_type,
|
||||
.release_port = bu92747_irda_release_port,
|
||||
.request_port = bu92747_irda_request_port,
|
||||
.config_port = bu92747_irda_config_port,
|
||||
.verify_port = bu92747_irda_verify_port,
|
||||
.ioctl = bu92747_irda_ioctl,
|
||||
};
|
||||
|
||||
static struct uart_driver bu92747_irda_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "ttyIr",
|
||||
.dev_name = "ttyIr",
|
||||
.major = BU92747_MAJOR,
|
||||
.minor = BU92747_MINOR,
|
||||
.nr = MAX_BU92747,
|
||||
};
|
||||
|
||||
static int uart_driver_registered;
|
||||
static int __devinit bu92747_irda_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i, retval;
|
||||
struct irda_info *platdata = pdev->dev.platform_data;
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
if (!platdata) {
|
||||
dev_warn(&pdev->dev, "no platform data info\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mutex_lock(&bu92747s_lock);
|
||||
|
||||
if (!uart_driver_registered) {
|
||||
uart_driver_registered = 1;
|
||||
retval = uart_register_driver(&bu92747_irda_uart_driver);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "Couldn't register bu92747 uart driver\n");
|
||||
mutex_unlock(&bu92747s_lock);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_BU92747; i++)
|
||||
if (!bu92747s[i])
|
||||
break;
|
||||
if (i == MAX_BU92747) {
|
||||
dev_warn(&pdev->dev, "too many bu92747 chips\n");
|
||||
mutex_unlock(&bu92747s_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bu92747s[i] = kzalloc(sizeof(struct bu92747_port), GFP_KERNEL);
|
||||
if (!bu92747s[i]) {
|
||||
dev_warn(&pdev->dev,
|
||||
"kmalloc for bu92747 structure %d failed!\n", i);
|
||||
mutex_unlock(&bu92747s_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
bu92747s[i]->dev = &pdev->dev;
|
||||
bu92747s[i]->irq_pin = platdata->intr_pin;
|
||||
bu92747s[i]->irq = gpio_to_irq(platdata->intr_pin);
|
||||
if (platdata->iomux_init)
|
||||
platdata->iomux_init();
|
||||
bu92747s[i]->pdata = platdata;
|
||||
spin_lock_init(&bu92747s[i]->conf_lock);
|
||||
dev_set_drvdata(&pdev->dev, bu92747s[i]);
|
||||
bu92747s[i]->minor = i;
|
||||
dev_dbg(&pdev->dev, "%s: adding port %d\n", __func__, i);
|
||||
bu92747s[i]->port.irq = bu92747s[i]->irq;
|
||||
bu92747s[i]->port.fifosize = BU92725GUW_FIFO_SIZE;
|
||||
bu92747s[i]->port.ops = &bu92747_irda_ops;
|
||||
bu92747s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
bu92747s[i]->port.line = i;
|
||||
bu92747s[i]->port.type = PORT_IRDA;
|
||||
bu92747s[i]->port.dev = &pdev->dev;
|
||||
retval = uart_add_one_port(&bu92747_irda_uart_driver, &bu92747s[i]->port);
|
||||
if (retval < 0)
|
||||
dev_warn(&pdev->dev,
|
||||
"uart_add_one_port failed for line %d with error %d\n",
|
||||
i, retval);
|
||||
bu92747s[i]->open_flag = 0;
|
||||
bu92747s[i]->suspending = 0;
|
||||
/* set shutdown mode to save power. Will be woken-up on open */
|
||||
if (bu92747s[i]->pdata->irda_pwr_ctl)
|
||||
bu92747s[i]->pdata->irda_pwr_ctl(0);
|
||||
|
||||
spin_lock_init(&(bu92747s[i]->data_lock));
|
||||
|
||||
mutex_unlock(&bu92747s_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit bu92747_irda_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bu92747_port *s = dev_get_drvdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
IRDA_DBG_FUNC("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
mutex_lock(&bu92747s_lock);
|
||||
|
||||
/* find out the index for the chip we are removing */
|
||||
for (i = 0; i < MAX_BU92747; i++)
|
||||
if (bu92747s[i] == s)
|
||||
break;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s: removing port %d\n", __func__, i);
|
||||
uart_remove_one_port(&bu92747_irda_uart_driver, &bu92747s[i]->port);
|
||||
kfree(bu92747s[i]);
|
||||
bu92747s[i] = NULL;
|
||||
|
||||
/* check if this is the last chip we have */
|
||||
for (i = 0; i < MAX_BU92747; i++)
|
||||
if (bu92747s[i]) {
|
||||
mutex_unlock(&bu92747s_lock);
|
||||
return 0;
|
||||
}
|
||||
pr_debug("removing bu92747 driver\n");
|
||||
uart_unregister_driver(&bu92747_irda_uart_driver);
|
||||
|
||||
mutex_unlock(&bu92747s_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bu92747_irda_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct bu92747_port *s = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (s->open_flag) {
|
||||
printk("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
disable_irq(s->irq);
|
||||
cancel_work_sync(&s->work);
|
||||
s->suspending = 1;
|
||||
uart_suspend_port(&bu92747_irda_uart_driver, &s->port);
|
||||
|
||||
irda_hw_shutdown();
|
||||
if (s->pdata->irda_pwr_ctl)
|
||||
s->pdata->irda_pwr_ctl(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu92747_irda_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct bu92747_port *s = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (s->open_flag) {
|
||||
printk("line %d, enter %s \n", __LINE__, __FUNCTION__);
|
||||
if (s->pdata->irda_pwr_ctl)
|
||||
s->pdata->irda_pwr_ctl(1);
|
||||
|
||||
irda_hw_startup();
|
||||
irda_hw_set_speed(s->baud);
|
||||
irda_hw_set_moderx();
|
||||
|
||||
uart_resume_port(&bu92747_irda_uart_driver, &s->port);
|
||||
s->suspending = 0;
|
||||
|
||||
if (!s->tx_empty)
|
||||
s->tx_empty = 1;
|
||||
enable_irq(s->irq);
|
||||
if (s->workqueue && !IS_FIR(s))
|
||||
bu92747_irda_dowork(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define bu92747_irda_suspend NULL
|
||||
#define bu92747_irda_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver bu92747_irda_driver = {
|
||||
.driver = {
|
||||
.name = "bu92747_irda",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = bu92747_irda_probe,
|
||||
.remove = bu92747_irda_remove,
|
||||
.suspend = bu92747_irda_suspend,
|
||||
.resume = bu92747_irda_resume,
|
||||
};
|
||||
|
||||
static int __init bu92747_irda_init(void)
|
||||
{
|
||||
if (platform_driver_register(&bu92747_irda_driver) != 0) {
|
||||
printk("Could not register irda driver\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit bu92747_irda_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bu92747_irda_driver);
|
||||
}
|
||||
|
||||
module_init(bu92747_irda_init);
|
||||
module_exit(bu92747_irda_exit);
|
||||
MODULE_DESCRIPTION("BU92747 irda driver");
|
||||
MODULE_AUTHOR("liuyixing <lyx@rock-chips.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _IR_SERIAL_H_
|
||||
#define _IR_SERIAL_H_
|
||||
|
||||
#include "bu92725guw.h"
|
||||
|
||||
/*
|
||||
* define IOCTL macro
|
||||
*/
|
||||
/* magic number */
|
||||
#define TTYIR_IOC_TYPE 0x56
|
||||
|
||||
/* TTYIR_STARTSEND */
|
||||
/* function: start to send a frame in FIR mode */
|
||||
/* parameter: no parameter */
|
||||
/* return: no return code */
|
||||
#define TTYIR_STARTSEND _IO(TTYIR_IOC_TYPE, 0)
|
||||
|
||||
/* TTYIR_GETLENGTH */
|
||||
/* function: get the length of DATA field in the current frame */
|
||||
/* paramter: no paramter */
|
||||
/* return: the length of DATA field (unit:byte) */
|
||||
#define TTYIR_GETLENGTH _IOR(TTYIR_IOC_TYPE, 1, unsigned long)
|
||||
|
||||
#endif
|
||||
@@ -1,783 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the BSD Licence, GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/wakelock.h>
|
||||
|
||||
#include <mach/iomux.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/board.h>
|
||||
#include <mach/rk29_iomap.h>
|
||||
#include <mach/pmu.h>
|
||||
#include <mach/rk29-dma-pl330.h>
|
||||
|
||||
#include "rk29_ir.h"
|
||||
|
||||
#if 0
|
||||
#define RK29IR_DBG(x...) printk(x)
|
||||
#else
|
||||
#define RK29IR_DBG(x...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define RK29IR_DATA_DBG(x...) printk(x)
|
||||
#else
|
||||
#define RK29IR_DATA_DBG(x...)
|
||||
#endif
|
||||
|
||||
#define IRDA_NAME "rk_irda"
|
||||
|
||||
struct irda_driver {
|
||||
struct irda_info *pin_info;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
#define IS_FIR(si) ((si)->speed >= 4000000)
|
||||
static int max_rate = 4000000;
|
||||
#define IRDA_FRAME_SIZE_LIMIT BU92725GUW_FIFO_SIZE
|
||||
|
||||
#define RK29_MAX_RXLEN 2047
|
||||
|
||||
static void rk29_irda_fir_test(struct work_struct *work);
|
||||
static DECLARE_DELAYED_WORK(dwork, rk29_irda_fir_test);
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and map the receive buffer, unless it is already allocated.
|
||||
*/
|
||||
static int rk29_irda_rx_alloc(struct rk29_irda *si)
|
||||
{
|
||||
if (si->rxskb)
|
||||
return 0;
|
||||
|
||||
si->rxskb = alloc_skb(RK29_MAX_RXLEN + 1, GFP_ATOMIC);
|
||||
|
||||
if (!si->rxskb) {
|
||||
printk(KERN_ERR "rk29_ir: out of memory for RX SKB\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
si->rxskb->len = 0;
|
||||
|
||||
/*
|
||||
* Align any IP headers that may be contained
|
||||
* within the frame.
|
||||
*/
|
||||
skb_reserve(si->rxskb, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the IrDA communications speed.
|
||||
*/
|
||||
static int rk29_irda_set_speed(struct rk29_irda *si, int speed)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
printk("[%s][%d], speed=%d\n",__FUNCTION__,__LINE__,speed);
|
||||
|
||||
switch (speed) {
|
||||
case 9600: case 19200: case 38400:
|
||||
case 57600: case 115200:
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
irda_hw_set_speed(speed);
|
||||
|
||||
si->speed = speed;
|
||||
|
||||
local_irq_restore(flags);
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case 4000000:
|
||||
local_irq_save(flags);
|
||||
|
||||
si->speed = speed;
|
||||
|
||||
irda_hw_set_speed(speed);
|
||||
//irda_hw_set_speed(1152000);//MIR
|
||||
rk29_irda_rx_alloc(si);
|
||||
|
||||
local_irq_restore(flags);
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rk29_irda_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)dev_id;
|
||||
struct rk29_irda *si = netdev_priv(dev);
|
||||
u8 data[2048]={0,0};
|
||||
int tmp_len=0;
|
||||
int i=0;
|
||||
u32 irq_src = 0;
|
||||
u32 irda_setptn = 0;
|
||||
|
||||
irq_src = irda_hw_get_irqsrc();
|
||||
|
||||
printk("[%s][%d], 0x%x\n",__FUNCTION__,__LINE__, irq_src);
|
||||
|
||||
//disable_irq(dev->irq);
|
||||
|
||||
/* EIR 1, 3, 11, 12
|
||||
irda_setptn |= irq_src & (REG_INT_EOFRX | REG_INT_TXE | REG_INT_WRE | REG_INT_RDE\
|
||||
| REG_INT_CRC | REG_INT_OE | REG_INT_FE | REG_INT_AC\
|
||||
| REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX) ;*/
|
||||
irda_setptn = irq_src;
|
||||
|
||||
/* error */
|
||||
if (irq_src & (REG_INT_TO| REG_INT_CRC | REG_INT_OE | REG_INT_FE
|
||||
| REG_INT_AC | REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX)) {
|
||||
RK29IR_DBG("[%s][%d]: do err\n",__FUNCTION__,__LINE__);
|
||||
//BU92725GUW_dump_register();
|
||||
BU92725GUW_clr_fifo();
|
||||
BU92725GUW_reset();
|
||||
}
|
||||
|
||||
if (IS_FIR(si)) //FIR
|
||||
{
|
||||
RK29IR_DBG("[%s][%d]: FIR\n",__FUNCTION__,__LINE__);
|
||||
if(irda_hw_get_mode() == BU92725GUW_AUTO_MULTI_REV) {//rx
|
||||
struct sk_buff *skb = si->rxskb;
|
||||
RK29IR_DBG("[%s][%d]: rx\n",__FUNCTION__,__LINE__);
|
||||
if (irda_setptn & (REG_INT_FE | REG_INT_OE | REG_INT_CRC | REG_INT_DECE)) {
|
||||
if (irda_setptn & REG_INT_FE) {
|
||||
printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");
|
||||
dev->stats.rx_frame_errors++;
|
||||
} else {
|
||||
printk(KERN_DEBUG "pxa_ir: fir receive abort\n");
|
||||
dev->stats.rx_errors++;
|
||||
}
|
||||
}
|
||||
if (irda_setptn & (FRM_EVT_RX_EOFRX | FRM_EVT_RX_RDE)) {
|
||||
tmp_len = BU92725GUW_get_data(skb->data+skb->len);
|
||||
skb->len += tmp_len;
|
||||
}
|
||||
if (irda_setptn & REG_INT_EOF) {
|
||||
RK29IR_DBG("[%s][%d]: report data:\n",__FUNCTION__,__LINE__);
|
||||
si->rxskb = NULL;
|
||||
RK29IR_DATA_DBG("[%s][%d]: fir report data:\n",__FUNCTION__,__LINE__);
|
||||
for (i=0;i<skb->len;i++) {
|
||||
RK29IR_DATA_DBG("0x%2x ", skb->data[i]);
|
||||
}
|
||||
RK29IR_DATA_DBG("\n");
|
||||
|
||||
skb_put(skb, skb->len);
|
||||
|
||||
/* Feed it to IrLAP */
|
||||
skb->dev = dev;
|
||||
skb_reset_mac_header(skb);
|
||||
skb->protocol = htons(ETH_P_IRDA);
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += skb->len;
|
||||
|
||||
/*
|
||||
* Before we pass the buffer up, allocate a new one.
|
||||
*/
|
||||
rk29_irda_rx_alloc(si);
|
||||
|
||||
netif_rx(skb);
|
||||
}
|
||||
}
|
||||
else if (irda_hw_get_mode() == BU92725GUW_MULTI_SEND) {//tx
|
||||
struct sk_buff *skb = si->txskb;
|
||||
si->txskb = NULL;
|
||||
RK29IR_DBG("[%s][%d]: tx\n",__FUNCTION__,__LINE__);
|
||||
if (irda_setptn & (FRM_EVT_TX_TXE | FRM_EVT_TX_WRE)) {
|
||||
/*
|
||||
* Do we need to change speed? Note that we're lazy
|
||||
* here - we don't free the old rxskb. We don't need
|
||||
* to allocate a buffer either.
|
||||
*/
|
||||
if (si->newspeed) {
|
||||
rk29_irda_set_speed(si, si->newspeed);
|
||||
si->newspeed = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Account and free the packet.
|
||||
*/
|
||||
if (skb) {
|
||||
dev->stats.tx_packets ++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the TX queue is available for sending
|
||||
* (for retries). TX has priority over RX at all times.
|
||||
*/
|
||||
netif_wake_queue(dev);
|
||||
|
||||
irda_hw_set_moderx();
|
||||
}
|
||||
}
|
||||
}
|
||||
else //SIR
|
||||
{
|
||||
RK29IR_DBG("[%d][%s], sir\n", __LINE__, __FUNCTION__);
|
||||
if(irda_hw_get_mode() == BU92725GUW_REV) //rx
|
||||
{
|
||||
RK29IR_DBG("[%d][%s], receive data:\n", __LINE__, __FUNCTION__);
|
||||
if(irda_setptn & (REG_INT_OE | REG_INT_FE ))
|
||||
{
|
||||
dev->stats.rx_errors++;
|
||||
if (irda_setptn & REG_INT_FE)
|
||||
dev->stats.rx_frame_errors++;
|
||||
if (irda_setptn & REG_INT_OE)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
}
|
||||
if((irda_setptn & ( FRM_EVT_RX_EOFRX| REG_INT_EOF /*|FRM_EVT_RX_RDE*/)))
|
||||
{
|
||||
tmp_len = BU92725GUW_get_data(data);
|
||||
RK29IR_DATA_DBG("[%d][%s], sir receive data:\n", __LINE__, __FUNCTION__);
|
||||
for(i=0;i<=tmp_len;i++)
|
||||
{
|
||||
RK29IR_DATA_DBG("0x%2x ",data[i]);
|
||||
async_unwrap_char(dev, &dev->stats, &si->rx_buff, data[i]);
|
||||
}
|
||||
RK29IR_DATA_DBG("\n");
|
||||
//BU92725GUW_clr_fifo();
|
||||
}
|
||||
}
|
||||
else if(irda_hw_get_mode() == BU92725GUW_SEND) //tx
|
||||
{
|
||||
RK29IR_DBG("[%d][%s], transmit data\n", __LINE__, __FUNCTION__);
|
||||
if((irda_setptn & FRM_EVT_TX_TXE) && (si->tx_buff.len)) {
|
||||
RK29IR_DATA_DBG("[%d][%s], sir transmit data:\n", __LINE__, __FUNCTION__);
|
||||
for (i=0;i<si->tx_buff.len;i++) {
|
||||
RK29IR_DATA_DBG("0x%2x ", *(si->tx_buff.data)++);
|
||||
}
|
||||
RK29IR_DATA_DBG("\n");
|
||||
|
||||
BU92725GUW_send_data(si->tx_buff.data, si->tx_buff.len, NULL, 0);
|
||||
si->tx_buff.len = 0;
|
||||
}
|
||||
else if (si->tx_buff.len == 0) {
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head;
|
||||
|
||||
/*
|
||||
* Ok, we've finished transmitting. Now enable
|
||||
* the receiver. Sometimes we get a receive IRQ
|
||||
* immediately after a transmit...
|
||||
*/
|
||||
if (si->newspeed) {
|
||||
rk29_irda_set_speed(si, si->newspeed);
|
||||
si->newspeed = 0;
|
||||
}
|
||||
|
||||
irda_hw_set_moderx();
|
||||
|
||||
/* I'm hungry! */
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
//enable_irq(dev->irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rk29_irda_start(struct net_device *dev)
|
||||
{
|
||||
struct rk29_irda *si = netdev_priv(dev);
|
||||
int err = 0;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
si->speed = 9600;
|
||||
|
||||
/*
|
||||
* irda module power up
|
||||
*/
|
||||
if (si->pdata->irda_pwr_ctl)
|
||||
si->pdata->irda_pwr_ctl(1);
|
||||
si->power = 1;
|
||||
|
||||
err = request_irq(dev->irq, rk29_irda_irq, IRQ_TYPE_LEVEL_LOW, dev->name, dev);//
|
||||
if (err) {
|
||||
printk("line %d: %s request_irq failed\n", __LINE__, __func__);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* The interrupt must remain disabled for now.
|
||||
*/
|
||||
disable_irq(dev->irq);
|
||||
|
||||
/*
|
||||
* Setup the smc port for the specified speed.
|
||||
*/
|
||||
err = irda_hw_startup();
|
||||
if (err) {
|
||||
printk("line %d: %s irda_hw_startup err\n", __LINE__, __func__);
|
||||
goto err_startup;
|
||||
}
|
||||
irda_hw_set_moderx();
|
||||
|
||||
/*
|
||||
* Open a new IrLAP layer instance.
|
||||
*/
|
||||
si->irlap = irlap_open(dev, &si->qos, "rk29");
|
||||
err = -ENOMEM;
|
||||
if (!si->irlap) {
|
||||
printk("line %d: %s irlap_open err\n", __LINE__, __func__);
|
||||
goto err_irlap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now enable the interrupt and start the queue
|
||||
*/
|
||||
si->open = 1;
|
||||
enable_irq(dev->irq);
|
||||
netif_start_queue(dev);
|
||||
|
||||
printk("rk29_ir: irda driver opened\n");
|
||||
|
||||
//test
|
||||
//rk29_irda_set_speed(si, 4000000);
|
||||
//schedule_delayed_work(&dwork, msecs_to_jiffies(5000));
|
||||
|
||||
return 0;
|
||||
|
||||
err_irlap:
|
||||
si->open = 0;
|
||||
irda_hw_shutdown();
|
||||
if (si->pdata->irda_pwr_ctl)
|
||||
si->pdata->irda_pwr_ctl(0);
|
||||
err_startup:
|
||||
free_irq(dev->irq, dev);
|
||||
err_irq:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rk29_irda_stop(struct net_device *dev)
|
||||
{
|
||||
struct rk29_irda *si = netdev_priv(dev);
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
disable_irq(dev->irq);
|
||||
irda_hw_shutdown();
|
||||
|
||||
/*
|
||||
* If we have been doing DMA receive, make sure we
|
||||
* tidy that up cleanly.
|
||||
*/
|
||||
if (si->rxskb) {
|
||||
dev_kfree_skb(si->rxskb);
|
||||
si->rxskb = NULL;
|
||||
}
|
||||
|
||||
/* Stop IrLAP */
|
||||
if (si->irlap) {
|
||||
irlap_close(si->irlap);
|
||||
si->irlap = NULL;
|
||||
}
|
||||
|
||||
netif_stop_queue(dev);
|
||||
si->open = 0;
|
||||
|
||||
/*
|
||||
* Free resources
|
||||
*/
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
//irda module power down
|
||||
if (si->pdata->irda_pwr_ctl)
|
||||
si->pdata->irda_pwr_ctl(0);
|
||||
|
||||
si->power = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct rk29_irda *si = netdev_priv(dev);
|
||||
int speed = irda_get_next_speed(skb);
|
||||
int i;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
/*
|
||||
* Does this packet contain a request to change the interface
|
||||
* speed? If so, remember it until we complete the transmission
|
||||
* of this frame.
|
||||
*/
|
||||
if (speed != si->speed && speed != -1)
|
||||
si->newspeed = speed;
|
||||
|
||||
/*
|
||||
* If this is an empty frame, we can bypass a lot.
|
||||
*/
|
||||
if (skb->len == 0) {
|
||||
if (si->newspeed) {
|
||||
si->newspeed = 0;
|
||||
rk29_irda_set_speed(si, speed);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
if (!IS_FIR(si)) {
|
||||
si->tx_buff.data = si->tx_buff.head;
|
||||
si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize);
|
||||
|
||||
/* Disable STUART interrupts and switch to transmit mode. */
|
||||
/* enable STUART and transmit interrupts */
|
||||
irda_hw_tx_enable_irq(BU92725GUW_SIR);
|
||||
|
||||
RK29IR_DATA_DBG("[%d][%s], sir transmit data:\n", __LINE__, __FUNCTION__);
|
||||
for (i=0;i<si->tx_buff.len;i++) {
|
||||
RK29IR_DATA_DBG("0x%2x ", *(si->tx_buff.data)++);
|
||||
}
|
||||
RK29IR_DATA_DBG("\n");
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
dev->trans_start = jiffies;
|
||||
BU92725GUW_send_data(si->tx_buff.data, si->tx_buff.len, NULL, 0);
|
||||
si->tx_buff.len = 0;
|
||||
}
|
||||
else {
|
||||
unsigned long mtt = irda_get_mtt(skb);
|
||||
si->txskb = skb;
|
||||
|
||||
irda_hw_tx_enable_irq(BU92725GUW_FIR);
|
||||
|
||||
RK29IR_DATA_DBG("[%d][%s], fir transmit data:\n", __LINE__, __FUNCTION__);
|
||||
for (i=0;i<skb->len;i++) {
|
||||
RK29IR_DATA_DBG("0x%2x ", skb->data[i]);
|
||||
}
|
||||
RK29IR_DATA_DBG("\n");
|
||||
|
||||
dev->trans_start = jiffies;
|
||||
BU92725GUW_send_data(skb->data, skb->len, NULL, 0);
|
||||
}
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
rk29_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
|
||||
{
|
||||
struct if_irda_req *rq = (struct if_irda_req *)ifreq;
|
||||
struct rk29_irda *si = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCSBANDWIDTH:
|
||||
if (capable(CAP_NET_ADMIN)) {
|
||||
/*
|
||||
* We are unable to set the speed if the
|
||||
* device is not running.
|
||||
*/
|
||||
if (si->open) {
|
||||
ret = rk29_irda_set_speed(si, rq->ifr_baudrate );
|
||||
} else {
|
||||
printk("rk29_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCSMEDIABUSY:
|
||||
ret = -EPERM;
|
||||
if (capable(CAP_NET_ADMIN)) {
|
||||
irda_device_set_media_busy(dev, TRUE);
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCGRECEIVING:
|
||||
rq->ifr_receiving = IS_FIR(si) ? 0
|
||||
: si->rx_buff.state != OUTSIDE_FRAME;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct net_device_ops rk29_irda_netdev_ops = {
|
||||
.ndo_open = rk29_irda_start,
|
||||
.ndo_stop = rk29_irda_stop,
|
||||
.ndo_start_xmit = rk29_irda_hard_xmit,
|
||||
.ndo_do_ioctl = rk29_irda_ioctl,
|
||||
};
|
||||
|
||||
|
||||
static int rk29_irda_init_iobuf(iobuff_t *io, int size)
|
||||
{
|
||||
io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
|
||||
if (io->head != NULL) {
|
||||
io->truesize = size;
|
||||
io->in_frame = FALSE;
|
||||
io->state = OUTSIDE_FRAME;
|
||||
io->data = io->head;
|
||||
}
|
||||
return io->head ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static void rk29_irda_fir_test(struct work_struct *work)
|
||||
{
|
||||
char send_data[4] = {1,0,1,0};
|
||||
irda_hw_tx_enable_irq(BU92725GUW_FIR);
|
||||
|
||||
BU92725GUW_send_data(send_data, 4, NULL, 0);
|
||||
|
||||
schedule_delayed_work(&dwork, msecs_to_jiffies(5000));
|
||||
return ;
|
||||
}
|
||||
|
||||
static int rk29_irda_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct irda_info *mach_info = NULL;
|
||||
struct net_device *dev;
|
||||
struct rk29_irda *si;
|
||||
unsigned int baudrate_mask;
|
||||
int err = -ENOMEM;
|
||||
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
mach_info = pdev->dev.platform_data;
|
||||
|
||||
if (mach_info)
|
||||
mach_info->iomux_init();
|
||||
|
||||
dev = alloc_irdadev(sizeof(struct rk29_irda));
|
||||
if (!dev) {
|
||||
printk("line %d: rk29_ir malloc failed\n", __LINE__);
|
||||
goto err_mem_1;
|
||||
}
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
si = netdev_priv(dev);
|
||||
si->dev = &pdev->dev;
|
||||
si->pdata = pdev->dev.platform_data;
|
||||
|
||||
/*
|
||||
* Initialise the HP-SIR buffers
|
||||
*/
|
||||
err = rk29_irda_init_iobuf(&si->rx_buff, 14384);
|
||||
if (err) {
|
||||
printk("line %d: rk29_ir malloc failed\n", __LINE__);
|
||||
goto err_mem_2;
|
||||
}
|
||||
err = rk29_irda_init_iobuf(&si->tx_buff, 4000);
|
||||
if (err) {
|
||||
printk("line %d: rk29_ir malloc failed\n", __LINE__);
|
||||
goto err_mem_3;
|
||||
}
|
||||
dev->netdev_ops = &rk29_irda_netdev_ops;
|
||||
dev->irq = gpio_to_irq(mach_info->intr_pin);
|
||||
|
||||
irda_init_max_qos_capabilies(&si->qos);
|
||||
|
||||
/*
|
||||
* We support original IRDA up to 115k2. (we don't currently
|
||||
* support 4Mbps). Min Turn Time set to 1ms or greater.
|
||||
*/
|
||||
baudrate_mask = IR_9600;
|
||||
|
||||
switch (max_rate) {
|
||||
case 4000000: baudrate_mask |= IR_4000000 << 8;
|
||||
case 115200: baudrate_mask |= IR_115200;
|
||||
case 57600: baudrate_mask |= IR_57600;
|
||||
case 38400: baudrate_mask |= IR_38400;
|
||||
case 19200: baudrate_mask |= IR_19200;
|
||||
}
|
||||
|
||||
si->qos.baud_rate.bits &= baudrate_mask;
|
||||
si->qos.min_turn_time.bits = 7;
|
||||
|
||||
irda_qos_bits_to_value(&si->qos);
|
||||
|
||||
/*
|
||||
* Initially enable HP-SIR modulation, and ensure that the port
|
||||
* is disabled.
|
||||
*/
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
printk("line %d: rk29_ir register_netdev failed\n", __LINE__);
|
||||
goto err_register;
|
||||
}
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
//test
|
||||
//wake_lock_init(&w_lock, WAKE_LOCK_SUSPEND, "rk29_cir");
|
||||
//wake_lock(&w_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
kfree(si->tx_buff.head);
|
||||
err_mem_3:
|
||||
kfree(si->rx_buff.head);
|
||||
err_mem_2:
|
||||
free_netdev(dev);
|
||||
err_mem_1:
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static int rk29_irda_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);
|
||||
|
||||
if (dev) {
|
||||
struct rk29_irda *si = netdev_priv(dev);
|
||||
unregister_netdev(dev);
|
||||
kfree(si->tx_buff.head);
|
||||
kfree(si->rx_buff.head);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* Suspend the IrDA interface.
|
||||
*/
|
||||
static int rk29_irda_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
struct rk29_irda *si;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
si = netdev_priv(dev);
|
||||
if (si->open) {
|
||||
/*
|
||||
* Stop the transmit queue
|
||||
*/
|
||||
netif_device_detach(dev);
|
||||
disable_irq(dev->irq);
|
||||
irda_hw_shutdown();
|
||||
if (si->pdata->irda_pwr_ctl)
|
||||
si->pdata->irda_pwr_ctl(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resume the IrDA interface.
|
||||
*/
|
||||
static int rk29_irda_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
struct rk29_irda *si;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
si = netdev_priv(dev);
|
||||
if (si->open) {
|
||||
|
||||
if (si->pdata->irda_pwr_ctl)
|
||||
si->pdata->irda_pwr_ctl(1);
|
||||
|
||||
/*
|
||||
* If we missed a speed change, initialise at the new speed
|
||||
* directly. It is debatable whether this is actually
|
||||
* required, but in the interests of continuing from where
|
||||
* we left off it is desireable. The converse argument is
|
||||
* that we should re-negotiate at 9600 baud again.
|
||||
*/
|
||||
if (si->newspeed) {
|
||||
si->speed = si->newspeed;
|
||||
si->newspeed = 0;
|
||||
}
|
||||
|
||||
irda_hw_startup();
|
||||
enable_irq(dev->irq);
|
||||
|
||||
/*
|
||||
* This automatically wakes up the queue
|
||||
*/
|
||||
netif_device_attach(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define rk29_irda_suspend NULL
|
||||
#define rk29_irda_resume NULL
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_driver irda_driver = {
|
||||
.driver = {
|
||||
.name = IRDA_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rk29_irda_probe,
|
||||
.remove = rk29_irda_remove,
|
||||
.suspend = rk29_irda_suspend,
|
||||
.resume = rk29_irda_resume,
|
||||
};
|
||||
|
||||
static int __init irda_init(void)
|
||||
{
|
||||
if (platform_driver_register(&irda_driver) != 0) {
|
||||
printk("Could not register irda driver\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit irda_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&irda_driver);
|
||||
}
|
||||
|
||||
module_init(irda_init);
|
||||
module_exit(irda_exit);
|
||||
MODULE_AUTHOR(" zyw@rock-chips.com");
|
||||
MODULE_DESCRIPTION("Driver for irda device");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __DRIVERS_NET_IRDA_RK29_IR_H
|
||||
#define __DRIVERS_NET_IRDA_RK29_IR_H
|
||||
|
||||
#include "bu92725guw.h"
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irmod.h>
|
||||
#include <net/irda/wrapper.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
struct rk29_irda {
|
||||
unsigned char* irda_base_addr;
|
||||
unsigned char power;
|
||||
unsigned char open;
|
||||
|
||||
int speed;
|
||||
int newspeed;
|
||||
|
||||
struct sk_buff *txskb;
|
||||
struct sk_buff *rxskb;
|
||||
|
||||
unsigned char *dma_rx_buff;
|
||||
unsigned char *dma_tx_buff;
|
||||
u32 dma_rx_buff_phy;
|
||||
u32 dma_tx_buff_phy;
|
||||
unsigned int dma_tx_buff_len;
|
||||
int txdma;
|
||||
int rxdma;
|
||||
|
||||
|
||||
struct device *dev;
|
||||
struct irda_info *pdata;
|
||||
struct irlap_cb *irlap;
|
||||
struct qos_info qos;
|
||||
|
||||
iobuff_t tx_buff;
|
||||
iobuff_t rx_buff;
|
||||
};
|
||||
|
||||
#endif //__DRIVERS_NET_IRDA_RK29_IR_H
|
||||
Reference in New Issue
Block a user