From: lyx Date: Mon, 4 Jul 2011 03:13:57 +0000 (-0700) Subject: newton:add IRDA driver X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=46913393621dff26a73d1a2551c9629478f511bd;p=firefly-linux-kernel-4.4.55.git newton:add IRDA driver now is just for sir --- diff --git a/arch/arm/configs/rk29_newton_defconfig b/arch/arm/configs/rk29_newton_defconfig old mode 100644 new mode 100755 index eb198a7253c7..b2cc190eed2b --- a/arch/arm/configs/rk29_newton_defconfig +++ b/arch/arm/configs/rk29_newton_defconfig @@ -487,7 +487,47 @@ CONFIG_ANDROID_PARANOID_NETWORK=y # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set -# CONFIG_IRDA is not set +CONFIG_IRDA=y + +# +# IrDA protocols +# +CONFIG_IRLAN=y +CONFIG_IRNET=y +# CONFIG_IRCOMM is not set +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set + +# +# Dongle support +# +# CONFIG_KINGSUN_DONGLE is not set +# CONFIG_KSDAZZLE_DONGLE is not set +# CONFIG_KS959_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_SIGMATEL_FIR is not set +# CONFIG_MCS_FIR is not set +CONFIG_RK_IRDA=y +CONFIG_BU92725GUW=y CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y @@ -1774,6 +1814,7 @@ CONFIG_RK29_IPP=y # # CONFIG_CMMB is not set # CONFIG_TEST_CODE is not set +CONFIG_RK29_SMC=y # # File systems diff --git a/arch/arm/mach-rk29/board-rk29-newton.c b/arch/arm/mach-rk29/board-rk29-newton.c index 190070164d7a..77b164b6f620 100755 --- a/arch/arm/mach-rk29/board-rk29-newton.c +++ b/arch/arm/mach-rk29/board-rk29-newton.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -365,6 +366,140 @@ struct platform_device rk29_device_dma_cpy = { #endif +#if defined(CONFIG_RK_IRDA) || defined(CONFIG_BU92747GUW_CIR) +#define BU92747GUW_RESET_PIN RK29_PIN3_PD4// INVALID_GPIO // +#define BU92747GUW_RESET_MUX_NAME GPIO3D4_HOSTWRN_NAME//NULL // +#define BU92747GUW_RESET_MUX_MODE GPIO3H_GPIO3D4//NULL // + +#define BU92747GUW_PWDN_PIN RK29_PIN3_PD3//RK29_PIN5_PA7 // +#define BU92747GUW_PWDN_MUX_NAME GPIO3D3_HOSTRDN_NAME//GPIO5A7_HSADCDATA2_NAME // +#define BU92747GUW_PWDN_MUX_MODE GPIO3H_GPIO3D3//GPIO5L_GPIO5A7 // + +static int bu92747guw_io_init(void) +{ + int ret; + + //reset pin + if(BU92747GUW_RESET_MUX_NAME != NULL) + { + rk29_mux_api_set(BU92747GUW_RESET_MUX_NAME, BU92747GUW_RESET_MUX_MODE); + } + ret = gpio_request(BU92747GUW_RESET_PIN, NULL); + if(ret != 0) + { + gpio_free(BU92747GUW_RESET_PIN); + printk(">>>>>> BU92747GUW_RESET_PIN gpio_request err \n "); + } + gpio_direction_output(BU92747GUW_RESET_PIN, GPIO_HIGH); + + //power down pin + if(BU92747GUW_PWDN_MUX_NAME != NULL) + { + rk29_mux_api_set(BU92747GUW_PWDN_MUX_NAME, BU92747GUW_PWDN_MUX_MODE); + } + ret = gpio_request(BU92747GUW_PWDN_PIN, NULL); + if(ret != 0) + { + gpio_free(BU92747GUW_PWDN_PIN); + printk(">>>>>> BU92747GUW_PWDN_PIN gpio_request err \n "); + } + + //power down as default + gpio_direction_output(BU92747GUW_PWDN_PIN, GPIO_LOW); + + return 0; +} + + +static int bu92747guw_io_deinit(void) +{ + gpio_free(BU92747GUW_PWDN_PIN); + gpio_free(BU92747GUW_RESET_PIN); + return 0; +} + +//power ctl func is share with irda and remote +static int nPowerOnCount = 0; +static DEFINE_MUTEX(bu92747_power_mutex); + +//1---power on; 0---power off +static int bu92747guw_power_ctl(int enable) +{ + printk("%s \n",__FUNCTION__); + + mutex_lock(&bu92747_power_mutex); + if (enable) { + nPowerOnCount++; + if (nPowerOnCount == 1) {//power on first + //smc0_init(NULL); + gpio_set_value(BU92747GUW_PWDN_PIN, GPIO_HIGH); + gpio_set_value(BU92747GUW_RESET_PIN, GPIO_LOW); + mdelay(5); + gpio_set_value(BU92747GUW_RESET_PIN, GPIO_HIGH); + mdelay(5); + } + } + else { + nPowerOnCount--; + if (nPowerOnCount == 0) {//power down final + //smc0_exit(); + gpio_set_value(BU92747GUW_PWDN_PIN, GPIO_LOW); + } + } + mutex_unlock(&bu92747_power_mutex); + return 0; +} +#endif + +#ifdef CONFIG_RK_IRDA +#define IRDA_IRQ_PIN RK29_PIN5_PB2 +#define IRDA_IRQ_MUX_NAME GPIO5B2_HSADCDATA5_NAME +#define IRDA_IRQ_MUX_MODE GPIO5L_GPIO5B2 + +int irda_iomux_init(void) +{ + int ret = 0; + + //irda irq pin + if(IRDA_IRQ_MUX_NAME != NULL) + { + rk29_mux_api_set(IRDA_IRQ_MUX_NAME, IRDA_IRQ_MUX_MODE); + } + ret = gpio_request(IRDA_IRQ_PIN, NULL); + if(ret != 0) + { + gpio_free(IRDA_IRQ_PIN); + printk(">>>>>> IRDA_IRQ_PIN gpio_request err \n "); + } + gpio_pull_updown(IRDA_IRQ_PIN, GPIO_HIGH); + gpio_direction_input(IRDA_IRQ_PIN); + + return 0; +} + +int irda_iomux_deinit(void) +{ + gpio_free(IRDA_IRQ_PIN); + return 0; +} + +static struct irda_info rk29_irda_info = { + .intr_pin = IRDA_IRQ_PIN, + .iomux_init = irda_iomux_init, + .iomux_deinit = irda_iomux_deinit, + .irda_pwr_ctl = bu92747guw_power_ctl, +}; + +static struct platform_device irda_device = { + .name = "rk_irda", + .id = -1, + .dev = { + .platform_data = &rk29_irda_info, + } +}; +#endif + + static struct android_pmem_platform_data android_pmem_pdata = { .name = "pmem", .start = PMEM_UI_BASE, @@ -1486,6 +1621,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_RK29_NEWTON &rk29_device_newton, #endif +#ifdef CONFIG_RK_IRDA + &irda_device, +#endif }; /***************************************************************************************** @@ -1686,6 +1824,12 @@ static void __init machine_rk29_board_init(void) #endif board_usb_detect_init(RK29_PIN0_PA0); + +#if defined(CONFIG_RK_IRDA) || defined(CONFIG_BU92747GUW_CIR) + smc0_init(NULL); + bu92747guw_io_init(); +#endif + } static void __init machine_rk29_fixup(struct machine_desc *desc, struct tag *tags, diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h index e4b3d924b6ef..8c9eec37c046 100755 --- a/arch/arm/mach-rk29/include/mach/board.h +++ b/arch/arm/mach-rk29/include/mach/board.h @@ -22,6 +22,13 @@ #include #include +struct irda_info{ + u32 intr_pin; + int (*iomux_init)(void); + int (*iomux_deinit)(void); + int (*irda_pwr_ctl)(int en); +}; + struct rk29_button_light_info{ u32 led_on_pin; u32 led_on_level; diff --git a/arch/arm/mach-rk29/include/mach/rk29_smc.h b/arch/arm/mach-rk29/include/mach/rk29_smc.h new file mode 100755 index 000000000000..264057f166ab --- /dev/null +++ b/arch/arm/mach-rk29/include/mach/rk29_smc.h @@ -0,0 +1,11 @@ + +#ifndef __DRIVER_IRDA_SMC_H +#define __DRIVER_IRDA_SMC_H + +extern int smc0_init(u8 **base_addr); +extern void smc0_exit(void); +extern int smc0_write(u32 addr, u32 data); +extern int smc0_read(u32 addr); +extern int smc0_enable(int enable); +#endif + diff --git a/drivers/Kconfig b/drivers/Kconfig index 33a14a76a6b3..32f588c5fc2c 100755 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -126,4 +126,5 @@ source "drivers/cmmb/Kconfig" source "drivers/testcode/Kconfig" +source "drivers/smc/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index d56339157752..8a5da3179476 100755 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -116,5 +116,6 @@ obj-y += platform/ obj-y += ieee802154/ obj-$(CONFIG_CMMB) += cmmb/ obj-$(CONFIG_TEST_CODE) += testcode/ +obj-y += smc/ obj-y += dbg/ diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig old mode 100644 new mode 100755 index f76384221422..1fb4578fd430 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -387,5 +387,19 @@ config MCS_FIR To compile it as a module, choose M here: the module will be called mcs7780. +config RK_IRDA + tristate "rockchip rk29 IrDA" + depends on IRDA && RK29_SMC + help + Say Y or M here if you want to build support for the rk29 + built-in IRDA interface which can support both SIR, MIR and FIR. + +choice + depends on RK_IRDA + prompt "irda module select" +config BU92725GUW + bool "bu92725guw" +endchoice + endmenu diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile old mode 100644 new mode 100755 index d82e1e3bd8c8..8aa32fa6ddb7 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -37,6 +37,8 @@ obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o +obj-$(CONFIG_RK_IRDA) += rk29_ir.o +obj-$(CONFIG_BU92725GUW) += bu92725guw.o # The SIR helper module sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/bu92725guw.c b/drivers/net/irda/bu92725guw.c new file mode 100755 index 000000000000..b1794b3517e2 --- /dev/null +++ b/drivers/net/irda/bu92725guw.c @@ -0,0 +1,687 @@ +/*************************************************************************** + * + * File: bu92725guw.c + * + * Description: functions of operating with bu92725guw board. + * + * Created: 2007/9 + * + * Rev 1.1 + * + * + * Confidential ROHM CO.,LTD. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, 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(struct rk29_irda *si) +{ + 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 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 + BU92725GUW_set_trans_way(BU92725GUW_AUTO_MULTI_REV); + //BU92725GUW_set_trans_way(BU92725GUW_MULTI_REV); +} + +int irda_hw_get_mode(void) +{ + return curTrans_way; + + 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)); +} + +/* + * 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 */ + internal_set(1); +} + +/* + * 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__); + + /* get data count from FLV or FLVII */ + if (curTrans_way == BU92725GUW_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> 8); + } + + /* restart receive mode under SIR */ + if (curTrans_way == BU92725GUW_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) {//SIR + 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: + val = REG_TRCR_RX_EN; + break; + case BU92725GUW_SEND: + val = 0x0000; + break; + case BU92725GUW_AUTO_MULTI_REV: + val = REG_TRCR_RX_EN | REG_TRCR_AUTO_FLV_CP; + break; + case BU92725GUW_MULTI_REV: //not used + val = REG_TRCR_RX_EN | REG_TRCR_RX_CON; + 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_SEND: /* SIR use */ + val = REG_INT_TXE; //IER3 + 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_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); +} + + + diff --git a/drivers/net/irda/bu92725guw.h b/drivers/net/irda/bu92725guw.h new file mode 100755 index 000000000000..cee61bc85ad0 --- /dev/null +++ b/drivers/net/irda/bu92725guw.h @@ -0,0 +1,216 @@ +/*************************************************************************** + * + * 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_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); + + +#endif /*__BU92725GUW_H*/ diff --git a/drivers/net/irda/rk29_ir.c b/drivers/net/irda/rk29_ir.c new file mode 100755 index 000000000000..b7454d896c14 --- /dev/null +++ b/drivers/net/irda/rk29_ir.c @@ -0,0 +1,712 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 = 115200; +#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); + + 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) ; + + /* 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_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 | REG_INT_EOF))) { + tmp_len = BU92725GUW_get_data(skb->data+skb->len); + skb->len += tmp_len; + } + if (irda_setptn & (REG_INT_EOF | FRM_EVT_RX_EOFRX)) { + 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;ilen;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;itx_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(si); + 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(si); +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(si); + + /* + * 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;itx_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;ilen;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] = {0,0,0,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. + */ + irda_hw_init(si); + + 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: + irda_hw_deinit(si); + 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); + irda_hw_deinit(si); + } + + return 0; +} + + +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"); + diff --git a/drivers/net/irda/rk29_ir.h b/drivers/net/irda/rk29_ir.h new file mode 100755 index 000000000000..ba4380fec5b0 --- /dev/null +++ b/drivers/net/irda/rk29_ir.h @@ -0,0 +1,52 @@ +#ifndef __DRIVERS_NET_IRDA_RK29_IR_H +#define __DRIVERS_NET_IRDA_RK29_IR_H + +#include "bu92725guw.h" +#include +#include +#include +#include + +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; +}; +extern void irda_hw_init(struct rk29_irda *si); +extern int irda_hw_get_mode(void); +extern void irda_hw_deinit(struct rk29_irda *si); +extern int irda_hw_startup(struct rk29_irda *si); +extern int irda_hw_shutdown(struct rk29_irda *si); +extern int irda_hw_set_speed(u32 speed); +extern int irda_hw_tx_enable_irq(enum eTrans_Mode mode); +extern int irda_hw_tx_enable(int len); +extern int irda_hw_get_irqsrc(void); +extern int irda_hw_get_data16(char* data8); +extern void irda_hw_set_moderx(void); +extern int irda_hw_get_mode(void); + + +#endif //__DRIVERS_NET_IRDA_RK29_IR_H diff --git a/drivers/smc/Kconfig b/drivers/smc/Kconfig new file mode 100755 index 000000000000..618908d29318 --- /dev/null +++ b/drivers/smc/Kconfig @@ -0,0 +1,9 @@ + +config RK29_SMC + bool "rk29 smc interface" + default y + help + if you want to use smc in rk29, pls enable it + + + diff --git a/drivers/smc/Makefile b/drivers/smc/Makefile new file mode 100755 index 000000000000..5e5258e921c4 --- /dev/null +++ b/drivers/smc/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for the Linux IrDA infrared port device drivers. +# +# 9 Aug 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# + +# FIR drivers +obj-$(CONFIG_USB_IRDA) += irda-usb.o +obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o +obj-$(CONFIG_NSC_FIR) += nsc-ircc.o +obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o +obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o +obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o +obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o +obj-$(CONFIG_ALI_FIR) += ali-ircc.o +obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o +obj-$(CONFIG_VIA_FIR) += via-ircc.o + +obj-$(CONFIG_RK29_SMC) += rk29_smc.o diff --git a/drivers/smc/rk29_smc.c b/drivers/smc/rk29_smc.c new file mode 100755 index 000000000000..7f1339a1bb88 --- /dev/null +++ b/drivers/smc/rk29_smc.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#include +#include +#include +#include +#include + +void __iomem *rank0_vir_base; // virtual basic address of lcdc register +struct clk *smc_clk = NULL; +struct clk *smc_axi_clk = NULL; +void __iomem *reg_vir_base; // virtual basic address of lcdc register + +int smc0_enable(int enable) +{ + if(enable){ + clk_enable(smc_axi_clk); + clk_enable(smc_clk); + __raw_writel(__raw_readl(RK29_GRF_BASE+0xbc) | 0x2000 , (RK29_GRF_BASE+0xbc)); + + __raw_writel((0x801), (reg_vir_base+0x18)); + __raw_writel(0x00400000, (reg_vir_base+0x10)); + __raw_writel((15 | (14<<8) | (15<<4) | (5<<11) ), (reg_vir_base+0x14)); + //__raw_writel((15 | (10<<8) | (15<<4) | (7<<11) ), (reg_vir_base+0x14)); + + __raw_writel(0x00400000, (reg_vir_base+0x10)); + } else { + clk_disable(smc_axi_clk); + clk_disable(smc_clk); + } + return 0; +} + +int smc0_init(u8 **base_addr) +{ + u32 reg_phy_base; // physical basic address of lcdc register + u32 len; // physical map length of lcdc register + struct resource *mem; + + u32 rank0_phy_base; // physical basic address of lcdc register + u32 rank0_len; // physical map length of lcdc register + struct resource *rank0_mem; + + printk(" %s %d \n",__FUNCTION__, __LINE__); + + if(smc_axi_clk == NULL)smc_axi_clk = clk_get(NULL, "aclk_smc"); + if(smc_clk == NULL)smc_clk = clk_get(NULL, "smc"); + + rank0_phy_base = 0x11000000; //0x12000000;// + rank0_len = SZ_4K; + rank0_mem = request_mem_region(rank0_phy_base, rank0_len, "smc_rank0"); + if (rank0_mem == NULL) + { + printk("failed to get rank0 memory region [%d]\n",__LINE__); + } + + rank0_vir_base = ioremap(rank0_phy_base, rank0_len); + if (rank0_vir_base == NULL) + { + printk("ioremap() of rank0 failed\n"); + } + + //*base_addr = rank0_vir_base; + + reg_phy_base = RK29_SMC_PHYS; + len = SZ_16K; + mem = request_mem_region(reg_phy_base, len, "smc reg"); + if (mem == NULL) + { + printk("failed to get memory region [%d]\n",__LINE__); + } + + reg_vir_base = ioremap(reg_phy_base, len); + if (reg_vir_base == NULL) + { + printk("ioremap() of registers failed\n"); + } + + smc0_enable(1); + + rk29_mux_api_set(GPIO0B7_EBCGDOE_SMCOEN_NAME, GPIO0L_SMC_OE_N); + rk29_mux_api_set(GPIO0B6_EBCSDSHR_SMCBLSN1_HOSTINT_NAME, GPIO0L_SMC_BLS_N_1 ); + rk29_mux_api_set(GPIO0B5_EBCVCOM_SMCBLSN0_NAME, GPIO0L_SMC_BLS_N_0 ); + rk29_mux_api_set(GPIO0B4_EBCBORDER1_SMCWEN_NAME, GPIO0L_SMC_WE_N); + + rk29_mux_api_set(GPIO0B3_EBCBORDER0_SMCADDR3_HOSTDATA3_NAME, GPIO0L_SMC_ADDR3); + rk29_mux_api_set(GPIO0B2_EBCSDCE2_SMCADDR2_HOSTDATA2_NAME, GPIO0L_SMC_ADDR2); + rk29_mux_api_set(GPIO0B1_EBCSDCE1_SMCADDR1_HOSTDATA1_NAME, GPIO0L_SMC_ADDR1); + rk29_mux_api_set(GPIO0B0_EBCSDCE0_SMCADDR0_HOSTDATA0_NAME, GPIO0L_SMC_ADDR0); + + rk29_mux_api_set(GPIO1A1_SMCCSN0_NAME, GPIO1L_SMC_CSN0); + // rk29_mux_api_set(GPIO1A1_SMCCSN0_NAME, GPIO1L_GPIO1A1); + + // if(gpio_request(RK29_PIN1_PA1, NULL) != 0) + { + // gpio_free(RK29_PIN1_PA1); + // printk(">>>>>> RK29_PIN1_PA1 gpio_request err \n "); + } + // gpio_direction_output(RK29_PIN1_PA1, GPIO_LOW); + + rk29_mux_api_set(GPIO1A2_SMCCSN1_NAME, GPIO1L_SMC_CSN1); + rk29_mux_api_set(GPIO0D0_EBCSDOE_SMCADVN_NAME, GPIO0H_SMC_ADV_N); + + rk29_mux_api_set(GPIO5C0_EBCSDDO0_SMCDATA0_NAME, GPIO5H_SMC_DATA0); + rk29_mux_api_set(GPIO5C1_EBCSDDO1_SMCDATA1_NAME, GPIO5H_SMC_DATA1); + rk29_mux_api_set(GPIO5C2_EBCSDDO2_SMCDATA2_NAME, GPIO5H_SMC_DATA2); + rk29_mux_api_set(GPIO5C3_EBCSDDO3_SMCDATA3_NAME, GPIO5H_SMC_DATA3); + rk29_mux_api_set(GPIO5C4_EBCSDDO4_SMCDATA4_NAME, GPIO5H_SMC_DATA4); + rk29_mux_api_set(GPIO5C5_EBCSDDO5_SMCDATA5_NAME, GPIO5H_SMC_DATA5); + rk29_mux_api_set(GPIO5C6_EBCSDDO6_SMCDATA6_NAME, GPIO5H_SMC_DATA6); + rk29_mux_api_set(GPIO5C7_EBCSDDO7_SMCDATA7_NAME, GPIO5H_SMC_DATA7); + + rk29_mux_api_set(GPIO0C0_EBCGDSP_SMCDATA8_NAME, GPIO0H_SMC_DATA8); + rk29_mux_api_set(GPIO0C1_EBCGDR1_SMCDATA9_NAME, GPIO0H_SMC_DATA9); + rk29_mux_api_set(GPIO0C2_EBCSDCE0_SMCDATA10_NAME, GPIO0H_SMC_DATA10); + rk29_mux_api_set(GPIO0C3_EBCSDCE1_SMCDATA11_NAME, GPIO0H_SMC_DATA11); + rk29_mux_api_set(GPIO0C4_EBCSDCE2_SMCDATA12_NAME, GPIO0H_SMC_DATA12); + rk29_mux_api_set(GPIO0C5_EBCSDCE3_SMCDATA13_NAME, GPIO0H_SMC_DATA13); + rk29_mux_api_set(GPIO0C6_EBCSDCE4_SMCDATA14_NAME, GPIO0H_SMC_DATA14); + rk29_mux_api_set(GPIO0C7_EBCSDCE5_SMCDATA15_NAME, GPIO0H_SMC_DATA15); + + return 0; + +} + + + +int smc0_write(u32 addr, u16 data) +{ + // __raw_writel(data, rank0_vir_base + addr); + u16 *p = rank0_vir_base + addr; + int readdata; + *p = data; + udelay(5); + //readdata = *p; + //mdelay(5); + //mdelay(10); + //printk("%s addr=%x, data = %x, read date = %x\n",__FUNCTION__,addr,data,readdata); + return 0; +} + +int smc0_read(u32 addr) +{ + u16 * p = rank0_vir_base + addr; + int readdata = *p; + //mdelay(5); + //printk("%s addr=%x, read date = %x\n",__FUNCTION__,addr,readdata); + return readdata;//__raw_readl(rank0_vir_base + addr); +} + +void smc0_exit(void) +{ + smc0_enable(0); +} + + +