From 48fddf9817b6b0c0264bd167720214780a948390 Mon Sep 17 00:00:00 2001 From: lyx Date: Sun, 3 Jul 2011 21:50:11 -0700 Subject: [PATCH] newton: add ir remote control driver(cir) --- arch/arm/configs/rk29_newton_defconfig | 6 + arch/arm/mach-rk29/board-rk29-newton.c | 34 + drivers/Kconfig | 3 + drivers/Makefile | 1 + drivers/cir/Kconfig | 20 + drivers/cir/Makefile | 6 + drivers/cir/bu92747guw_cir.c | 901 +++++++++++++++++++++++++ drivers/cir/bu92747guw_cir.h | 162 +++++ drivers/smc/Kconfig | 2 +- 9 files changed, 1134 insertions(+), 1 deletion(-) create mode 100755 drivers/cir/Kconfig create mode 100755 drivers/cir/Makefile create mode 100755 drivers/cir/bu92747guw_cir.c create mode 100755 drivers/cir/bu92747guw_cir.h diff --git a/arch/arm/configs/rk29_newton_defconfig b/arch/arm/configs/rk29_newton_defconfig index b2cc190eed2b..2689fbfb03b3 100755 --- a/arch/arm/configs/rk29_newton_defconfig +++ b/arch/arm/configs/rk29_newton_defconfig @@ -1816,6 +1816,12 @@ CONFIG_RK29_IPP=y # CONFIG_TEST_CODE is not set CONFIG_RK29_SMC=y +# +# CIR support +# +CONFIG_RK_CIR=y +CONFIG_BU92747GUW_CIR=y + # # File systems # diff --git a/arch/arm/mach-rk29/board-rk29-newton.c b/arch/arm/mach-rk29/board-rk29-newton.c index 77b164b6f620..66103a4beb1e 100755 --- a/arch/arm/mach-rk29/board-rk29-newton.c +++ b/arch/arm/mach-rk29/board-rk29-newton.c @@ -57,6 +57,10 @@ #include "devices.h" #include "../../../drivers/input/touchscreen/xpt2046_cbn_ts.h" +#ifdef CONFIG_BU92747GUW_CIR +#include "../../../drivers/cir/bu92747guw_cir.h" +#endif + #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/ @@ -499,6 +503,26 @@ static struct platform_device irda_device = { }; #endif +#ifdef CONFIG_BU92747GUW_CIR +#define BU92747_CIR_IRQ_PIN RK29_PIN5_PB0 +#define CIR_IRQ_PIN_IOMUX_NAME GPIO5B0_HSADCDATA3_NAME +#define CIR_IRQ_PIN_IOMUX_VALUE GPIO5L_GPIO5B0 +static int cir_iomux_init(void) +{ + if (CIR_IRQ_PIN_IOMUX_NAME) + rk29_mux_api_set(CIR_IRQ_PIN_IOMUX_NAME, CIR_IRQ_PIN_IOMUX_VALUE); + + rk29_mux_api_set(GPIO5A7_HSADCDATA2_NAME, GPIO5L_GPIO5A7); +} + +static struct bu92747guw_platform_data bu92747guw_pdata = { + .intr_pin = BU92747_CIR_IRQ_PIN, + .iomux_init = cir_iomux_init, + .iomux_deinit = NULL, + .cir_pwr_ctl = bu92747guw_power_ctl, +}; +#endif + static struct android_pmem_platform_data android_pmem_pdata = { .name = "pmem", @@ -919,6 +943,16 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = { .irq = RK29_PIN1_PD7, }, #endif +#ifdef CONFIG_BU92747GUW_CIR + { + .type ="bu92747_cir", + .addr = 0x77, + .flags =0, + .irq = BU92747_CIR_IRQ_PIN, + .platform_data = &bu92747guw_pdata, + }, + +#endif }; #endif diff --git a/drivers/Kconfig b/drivers/Kconfig index 32f588c5fc2c..a499ce714db4 100755 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -127,4 +127,7 @@ source "drivers/cmmb/Kconfig" source "drivers/testcode/Kconfig" source "drivers/smc/Kconfig" + +source "drivers/cir/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 8a5da3179476..8221447aef81 100755 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -117,5 +117,6 @@ obj-y += ieee802154/ obj-$(CONFIG_CMMB) += cmmb/ obj-$(CONFIG_TEST_CODE) += testcode/ obj-y += smc/ +obj-y += cir/ obj-y += dbg/ diff --git a/drivers/cir/Kconfig b/drivers/cir/Kconfig new file mode 100755 index 000000000000..edf8d04e93c4 --- /dev/null +++ b/drivers/cir/Kconfig @@ -0,0 +1,20 @@ +# +# CIR class/drivers configuration +# + + +menu "CIR support" + config RK_CIR + tristate "CIR support" + help + if you want use ir remote function , pls enable it + +choice + depends on RK_CIR + prompt "CIR module name" +config BU92747GUW_CIR + bool "bu92747guw cir" +endchoice + +endmenu + diff --git a/drivers/cir/Makefile b/drivers/cir/Makefile new file mode 100755 index 000000000000..8e4f547fa6ee --- /dev/null +++ b/drivers/cir/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for CIR class/drivers. +# + + +obj-$(CONFIG_BU92747GUW_CIR) += bu92747guw_cir.o diff --git a/drivers/cir/bu92747guw_cir.c b/drivers/cir/bu92747guw_cir.c new file mode 100755 index 000000000000..4f84d1971c74 --- /dev/null +++ b/drivers/cir/bu92747guw_cir.c @@ -0,0 +1,901 @@ +/*drivers/cir/bu92747guw_cir.c - driver for bu92747guw + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bu92747guw_cir.h" + +#if 0 +#define BU92747_DBG(x...) printk(x) +#else +#define BU92747_DBG(x...) +#endif + +#define CIR_IIC_SPEED 100 * 1000 + +#define XIN_INPUT_FREQ 48*1000 //KHz + +struct bu92747_data_info { + struct bu92747guw_platform_data *platdata; + struct i2c_client *client; + char state; + int irq; + int base_clock; + int sys_clock; + struct delayed_work dwork; + u8 inv; + u16 head_space_time; + u16 head_burst_time; +}; + +static struct miscdevice bu92747guw_device; + +int repeat_flag=-1; +int start_flag = 0; +//mutex lock between remote and irda +static DEFINE_MUTEX(bu92747_mutex); +void bu92747_lock(void) +{ + mutex_lock(&bu92747_mutex); +} +void bu92747_unlock(void) +{ + mutex_unlock(&bu92747_mutex); +} + + + + + +static int bu92747_cir_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, int len) +{ + int ret; + ret = i2c_master_reg8_recv(client, reg, buf, len, CIR_IIC_SPEED); + return ret; +} + +static int bu92747_cir_i2c_set_regs(struct i2c_client *client, u8 reg, u8 *buf, int len) +{ + int ret; + ret = i2c_master_reg8_send(client, reg, buf, len, CIR_IIC_SPEED); + return ret; +} + + +static int bu92747_stop(struct i2c_client *client) +{ + u8 reg_value[2]; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + //BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + printk("line %d: enter %s\n", __LINE__, __FUNCTION__); +// disable_irq(bu92747->irq); + //diable clk, repeat=1 + bu92747_cir_i2c_read_regs(client, REG_SETTING0, reg_value, 2); + reg_value[0] = reg_value[0]&0xfe; + reg_value[1] = reg_value[1]&0xf1; + bu92747_cir_i2c_set_regs(client, REG_SETTING0, reg_value, 2); + + repeat_flag = -1; + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} +static void bu92747_dwork_handler(struct work_struct *work) +{ + struct bu92747_data_info *bu92747 = + (struct bu92747_data_info *)container_of(work, struct bu92747_data_info, dwork.work); + u8 reg_value[2]; + + printk("------- sss enter %s\n", __func__); + + if ( !start_flag && (repeat_flag <= -1)){ + bu92747_stop(bu92747->client); + BU92747_DBG("----------exit %s\n", __func__); + return ; + } + + start_flag = 0; + //set repeat=0 + bu92747_cir_i2c_read_regs(bu92747->client, REG_SETTING1, reg_value, 1); + reg_value[0] &= 0xf0; + bu92747_cir_i2c_set_regs(bu92747->client, REG_SETTING1, reg_value, 1); + //printk("----------exit %s reg_value = %d\n", __func__, reg_value[1]); + + + reg_value[0] = 1; + + bu92747_cir_i2c_set_regs(bu92747->client, REG_SEND, reg_value, 1); +// bu92747_cir_i2c_read_regs(bu92747->client, REG_FRMLEN1, reg_value, 2); + +// printk("frame_interval = 0x%x\n", reg_value[1], reg_value[2]); + //power down + + BU92747_DBG("----------exit %s\n", __func__); + return; +} + +static irqreturn_t bu92747_cir_irq(int irq, void *dev_id) +{ +// u8 reg_value[2]; + struct i2c_client *client = container_of(bu92747guw_device.parent, struct i2c_client, dev); + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + + printk("----------enter %s repeat_flag = %d\n", __func__, repeat_flag); + + + if (((--repeat_flag%16) == 0) || (repeat_flag < 0)){ + schedule_delayed_work(&bu92747->dwork, msecs_to_jiffies(0)); + } + + return IRQ_HANDLED; +} + + + +#if 0 +static int bu92747_send_data(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + u8 inv0,inv1; + unsigned int hlo, hhi; + u8 reg_value[16]; + int i, nByte; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + struct bu92747guw_platform_data *pdata = bu92747->platdata; + int sys_clock = bu92747->sys_clock; + unsigned long flags; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + //if (bu92747->state == BU92747_BUSY) { + // printk("line %d, func: %s, dev is busy now\n", __LINE__, __func__); + // return -EBUSY; + //} + + //bu92747->state = BU92747_BUSY; + + repeat_flag = cir->repeat%16; + + bu92747_cir_i2c_read_regs(client, REG_SETTING0, reg_value, 2); + + inv0 = cir->inv & 0x01; + inv1 = (cir->inv>>1) & 0x01; + reg_value[0] = reg_value[0] | (inv0<<1) | (inv1<<2); + reg_value[1] = (reg_value[1]&0xf0) | (repeat_flag&0x0f); + bu92747_cir_i2c_set_regs(client, REG_SETTING0, reg_value, 2); + BU92747_DBG("inv0 = %d, inv1 = %d, repeat=%d\n", inv0, inv1, repeat_flag); + + //head maybe different while repeat + if ((bu92747->head_burst_time!=cir->head_burst_time) + || (bu92747->head_space_time!=cir->head_space_time)) { + hlo = (cir->head_space_time*sys_clock)/1000; + hhi = (cir->head_burst_time*sys_clock)/1000; + reg_value[0] = hlo>>8; + reg_value[1] = hlo&0xff; + reg_value[2] = hhi>>8; + reg_value[3] = hhi&0xff; + bu92747_cir_i2c_set_regs(client, REG_HLO1, reg_value, 4); + BU92747_DBG("hlo = 0x%x, hhi = 0x%x\n", hlo, hhi); + } + + //switch to remote control + //bu92747_lock(); + + //data bit length + reg_value[0] = cir->frame_bit_len; + bu92747_cir_i2c_set_regs(client, REG_BITLEN, reg_value, 1); + BU92747_DBG("frame_bit_len = 0x%x\n", cir->frame_bit_len); + + //data + nByte = (cir->frame_bit_len+7)/8; + for (i=0; iframe)>>(8*i))&0xff; + BU92747_DBG("reg_value[%d] = %d\n", i, reg_value[i]); + } + bu92747_cir_i2c_set_regs(client, REG_OUT0, reg_value, nByte); + BU92747_DBG("nByte = %d\n", nByte); + + //clear irq, start send + //reg_value[0] = 1; + //reg_value[1] = 1; + //bu92747_cir_i2c_set_regs(client, REG_IRQC, reg_value, 2); + + //send ok? +// while (gpio_get_value(pdata->intr_pin)) { +// BU92747_DBG("line %d: data register is not null\n", __LINE__); +// } + + //switch to irda control + //smc0_write(3, smc0_read(3) & 0xfbff); + //bu92747_unlock(); + + //enable_irq(bu92747->irq); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static int bu92747_set_format(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + u8 inv0, inv1; + unsigned int clo, chi, clo_org, chi_org; + unsigned int hlo, hhi; + unsigned int d0lo, d0hi, d1lo, d1hi; + unsigned int end; + u32 frame_interval; + unsigned int carry_freq = cir->carry; + u8 reg_value[20]; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + int sys_clock = bu92747->sys_clock; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + if (!cir) + return -1; + + //set inv0, inv1 + inv0 = cir->inv & 0x01; + inv1 = (cir->inv>>1) & 0x01; + bu92747_cir_i2c_read_regs(client, REG_SETTING0, reg_value, 1); + reg_value[0] = reg_value[0] | (inv0<<1) | (inv1<<2); + bu92747_cir_i2c_set_regs(client, REG_SETTING0, reg_value, 1); + BU92747_DBG("inv0 = %d, inv1 = %d\n", inv0, inv1); + bu92747->inv = cir->inv; + + //carry + chi_org = cir->duty_cycle / 10; + clo_org = (cir->duty_cycle % 10) - chi_org; + clo = (XIN_INPUT_FREQ*clo_org)/(3*carry_freq*(clo_org+chi_org)); + chi = (XIN_INPUT_FREQ*chi_org)/(3*carry_freq*(clo_org+chi_org)); + reg_value[0] = clo>>8; + reg_value[1] = clo&0xff; + reg_value[2] = chi>>8; + reg_value[3] = chi&0xff; + BU92747_DBG("clo = 0x%x, chi = 0x%x\n", clo, chi); + + //head + hlo = (cir->head_space_time*sys_clock)/1000; + hhi = (cir->head_burst_time*sys_clock)/1000; + reg_value[4] = hlo>>8; + reg_value[5] = hlo&0xff; + reg_value[6] = hhi>>8; + reg_value[7] = hhi&0xff; + BU92747_DBG("hlo = 0x%x, hhi = 0x%x\n", hlo, hhi); + bu92747->head_space_time = cir->head_space_time; + bu92747->head_burst_time = cir->head_burst_time; + + //data0 + d0lo = (cir->logic_low_space_time*sys_clock)/1000; + d0hi = (cir->logic_low_burst_time*sys_clock)/1000; + reg_value[8] = d0lo>>8; + reg_value[9] = d0lo&0xff; + reg_value[10] = d0hi>>8; + reg_value[11] = d0hi&0xff; + BU92747_DBG("d0lo = 0x%x, d0hi = 0x%x\n", d0lo, d0hi); + + //data1 + d1lo = (cir->logic_high_space_time*sys_clock)/1000; + d1hi = (cir->logic_high_burst_time*sys_clock)/1000; + reg_value[12] = d1lo>>8; + reg_value[13] = d1lo&0xff; + reg_value[14] = d1hi>>8; + reg_value[15] = d1hi&0xff; + BU92747_DBG("d1lo = 0x%x, d1hi = 0x%x\n", d1lo, d1hi); + + //end + end = (cir->stop_bit_interval*sys_clock)/1000; + reg_value[16] = end>>8; + reg_value[17] = end&0xff; + bu92747_cir_i2c_set_regs(client, REG_CLO1, reg_value, 18); + + BU92747_DBG("end = 0x%x\n", end); + + //frame interval + frame_interval = (cir->frame_interval*sys_clock)/1000; + reg_value[0] = frame_interval>>8; + reg_value[1] = frame_interval&0xff; + bu92747_cir_i2c_set_regs(client, REG_FRMLEN1, reg_value, 2); + + BU92747_DBG("frame_interval = 0x%x\n", frame_interval); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; + +} +#endif + +static int bu92747_start(struct i2c_client *client) +{ + u8 reg_value[2]; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + printk("line %d: enter %s\n", __LINE__, __FUNCTION__); + + + start_flag = 1; + //enable_irq(bu92747->irq); + //enable clk + bu92747_cir_i2c_read_regs(client, REG_SETTING0, reg_value, 1); + reg_value[0] = reg_value[0]|0x01; + bu92747_cir_i2c_set_regs(client, REG_SETTING0, reg_value, 1); + + //clear irq, start send + reg_value[0] = 1; + reg_value[1] = 1; + bu92747_cir_i2c_set_regs(client, REG_IRQC, reg_value, 2); + + + printk("line %d: exit %s\n", __LINE__, __FUNCTION__); + return 0; +} + + +static void bu92747_printk_cir(struct rk29_cir_struct_info *cir) +{ + BU92747_DBG("\ncir struct:\n"); + BU92747_DBG("carry_high = %d\n", cir->carry_high); + BU92747_DBG("carry_low = %d\n", cir->carry_low); + BU92747_DBG("repeat = %d\n", cir->repeat); + BU92747_DBG("inv = %d\n", cir->inv); + BU92747_DBG("frame_bit_len = %d\n", cir->frame_bit_len); + BU92747_DBG("stop_bit_interval = %d\n", cir->stop_bit_interval); + BU92747_DBG("frame = %lld\n", cir->frame); + BU92747_DBG("frame_interval = %d\n", cir->frame_interval); + BU92747_DBG("head_burst_time = %d\n", cir->head_burst_time); + BU92747_DBG("head_space_time = %d\n", cir->head_space_time); + BU92747_DBG("logic_high_burst_time = %d\n", cir->logic_high_burst_time); + BU92747_DBG("logic_high_space_time = %d\n", cir->logic_high_space_time); + BU92747_DBG("logic_low_burst_time = %d\n", cir->logic_low_burst_time); + BU92747_DBG("logic_low_space_time = %d\n", cir->logic_low_space_time); + BU92747_DBG("\n"); +} + + +static int bu92747_set_duration(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + u32 frame_interval; + + u8 reg_value[20]; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + int sys_clock = bu92747->sys_clock; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + if (!cir) + return -1; + + BU92747_DBG("sys_clock = %d, frame_interval = 0x%x\n", sys_clock,cir->frame_interval); + //frame interval + frame_interval = (cir->frame_interval*sys_clock)/1000; + + reg_value[0] = frame_interval>>8; + reg_value[1] = frame_interval&0xff; + bu92747_cir_i2c_set_regs(client, REG_FRMLEN1, reg_value, 2); + + BU92747_DBG("frame_interval = 0x%x\n", frame_interval); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; + +} + +static int bu92747_set_data(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + + u8 reg_value[16]; + int i, nByte; + + + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + //data bit length + reg_value[0] = cir->frame_bit_len; + bu92747_cir_i2c_set_regs(client, REG_BITLEN, reg_value, 1); + BU92747_DBG("frame_bit_len = 0x%x\n", cir->frame_bit_len); + + //data + nByte = (cir->frame_bit_len+7)/8; + for (i=0; iframe)>>(8*i))&0xff; + BU92747_DBG("reg_value[%d] = %d\n", i, reg_value[i]); + } + bu92747_cir_i2c_set_regs(client, REG_OUT0, reg_value, nByte); + BU92747_DBG("nByte = %d\n", nByte); + + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static int bu92747_set_pulse(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + u8 inv0, inv1; + + + unsigned int d0lo, d0hi, d1lo, d1hi; + + + u8 reg_value[8] = {0}; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + int sys_clock = bu92747->sys_clock; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + if (!cir) + return -1; + + //set inv0, inv1 + inv0 = cir->inv & 0x01; + inv1 = (cir->inv>>1) & 0x01; + bu92747_cir_i2c_read_regs(client, REG_SETTING0, reg_value, 1); + reg_value[0] = reg_value[0] | (inv0<<1) | (inv1<<2); + bu92747_cir_i2c_set_regs(client, REG_SETTING0, reg_value, 1); + BU92747_DBG("inv0 = %d, inv1 = %d\n", inv0, inv1); + bu92747->inv = cir->inv; + + + //data0 + d0lo = (cir->logic_low_space_time*sys_clock)/1000; + d0hi = (cir->logic_low_burst_time*sys_clock)/1000; + reg_value[0] = d0lo>>8; + reg_value[1] = d0lo&0xff; + reg_value[2] = d0hi>>8; + reg_value[3] = d0hi&0xff; + BU92747_DBG("d0lo = 0x%x, d0hi = 0x%x\n", d0lo, d0hi); + + //data1 + d1lo = (cir->logic_high_space_time*sys_clock)/1000; + d1hi = (cir->logic_high_burst_time*sys_clock)/1000; + reg_value[4] = d1lo>>8; + reg_value[5] = d1lo&0xff; + reg_value[6] = d1hi>>8; + reg_value[7] = d1hi&0xff; + BU92747_DBG("d1lo = 0x%x, d1hi = 0x%x\n", d1lo, d1hi); + bu92747_cir_i2c_set_regs(client, REG_D0LO1, reg_value, 8); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; + +} + + + +static int bu92747_set_parameter(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + unsigned int hlo, hhi; + unsigned int end; + + u8 reg_value[4]; + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + int sys_clock = bu92747->sys_clock; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + if (!cir) + return -1; + + //head + hlo = (cir->head_space_time*sys_clock)/1000; + hhi = (cir->head_burst_time*sys_clock)/1000; + reg_value[0] = hlo>>8; + reg_value[1] = hlo&0xff; + reg_value[2] = hhi>>8; + reg_value[3] = hhi&0xff; + BU92747_DBG("hlo = 0x%x, hhi = 0x%x\n", hlo, hhi); + bu92747->head_space_time = cir->head_space_time; + bu92747->head_burst_time = cir->head_burst_time; + bu92747_cir_i2c_set_regs(client, REG_HLO1, reg_value, 4); + + //end + end = (cir->stop_bit_interval*sys_clock)/1000; + reg_value[0] = end>>8; + reg_value[1] = end&0xff; + bu92747_cir_i2c_set_regs(client, REG_ENDLEN1, reg_value, 2); + + BU92747_DBG("end = 0x%x\n", end); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; + +} + + +static int bu92747_set_repeat(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + + u8 reg_value[2]; + int repeat; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + repeat_flag = cir->repeat; + printk("repeat 11111 =%d\n", repeat_flag); + + if (repeat_flag > 16){ + repeat = 16; + }else{ + repeat = repeat_flag; + } + + repeat = repeat % 16; + + bu92747_cir_i2c_read_regs(client, REG_SETTING1, reg_value, 1); + + reg_value[0] = (reg_value[0]&0xf0) | (repeat&0x0f); + bu92747_cir_i2c_set_regs(client, REG_SETTING1, reg_value, 1); + printk("repeat 2222 =%d reg_value = %d\n", repeat, reg_value[0]); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static int bu92747_set_carrier(struct i2c_client *client, struct rk29_cir_struct_info *cir) +{ + u8 reg_value[4]; + u16 clo = 0, chi = 0; + unsigned int hlo = cir->carry_low , hhi = cir->carry_high; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + if (!cir) + return -1; + + //carry + + clo = XIN_INPUT_FREQ / 3000 * hlo; + chi = XIN_INPUT_FREQ / 3000 * hhi; + reg_value[0] = clo>>8; + reg_value[1] = clo&0xff; + reg_value[2] = chi>>8; + reg_value[3] = chi&0xff; + BU92747_DBG("clo = 0x%x, chi = 0x%x\n", clo, chi); + bu92747_cir_i2c_set_regs(client, REG_CLO1, reg_value, 4); + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; + +} + + +static int bu92747_cir_init_device(struct i2c_client *client, struct bu92747_data_info *bu92747) +{ + u8 reg_value[3]; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + //transmission buff null intertupt, base clock div, irq enable, clock power up + //reg_value[0] = /*REG0_OPM | */REG0_DIVS | REG0_PWR | REG0_IRQE; + reg_value[0] = /*REG0_OPM | */REG0_DIVS | REG0_IRQE; + reg_value[1] = REG1_FRME | REG1_RPT; //enable frame interval, repeat = 1 + reg_value[2] = 80; //base clock = 100KHz + BU92747_DBG("line %d: reg0=0x%x, reg1=0x%x, reg2=0x%x\n", __LINE__, reg_value[0], reg_value[1], reg_value[2]); + bu92747_cir_i2c_set_regs(client, REG_SETTING0, reg_value, 3); + bu92747_cir_i2c_read_regs(client, REG_SETTING0, reg_value, 3); + BU92747_DBG("line %d: reg0=0x%x, reg1=0x%x, reg2=0x%x\n", __LINE__, reg_value[0], reg_value[1], reg_value[2]); + + bu92747->base_clock = 100; //KHz + bu92747->sys_clock = bu92747->base_clock; + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static int bu92747_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + char msg[CIR_FRAME_SIZE]; + int ret; + struct i2c_client *client = container_of(bu92747guw_device.parent, struct i2c_client, dev); + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + + switch (cmd) { + + case BU92747_IOCTL_START: + ret = bu92747_start(client); + if (ret < 0) + return ret; + break; + + case BU92747_IOCTL_STOP: + ret = bu92747_stop(client); + if (ret < 0) + return ret; + break; + + case BU92747_IOCTL_PULSE: + if (copy_from_user(&msg, argp, sizeof(msg))) + return -EFAULT; + + //bu92747_printk_cir((struct rk29_cir_struct_info *)msg); + ret = bu92747_set_pulse(client, (struct rk29_cir_struct_info *)msg); + if (ret < 0) + return ret; + break; + + case BU92747_IOCTL_DATA: + if (copy_from_user(&msg, argp, sizeof(msg))) + return -EFAULT; + ret = bu92747_set_data(client, (struct rk29_cir_struct_info *)msg); + if (ret < 0) + return ret; + break; + + case BU92747_IOCTL_CARRIER: + if (copy_from_user(&msg, argp, sizeof(msg))) + return -EFAULT; + ret = bu92747_set_carrier(client, (struct rk29_cir_struct_info *)msg); + if (ret < 0) + return ret; + break; + case BU92747_IOCTL_REPEAT: + if (copy_from_user(&msg, argp, sizeof(msg))) + return -EFAULT; + ret = bu92747_set_repeat(client, (struct rk29_cir_struct_info *)msg); + if (ret < 0) + return ret; + break; + + case BU92747_IOCTL_DURATION: + if (copy_from_user(&msg, argp, sizeof(msg))) + return -EFAULT; + ret = bu92747_set_duration(client, (struct rk29_cir_struct_info *)msg); + if (ret < 0) + return ret; + break; + case BU92747_IOCTL_PARAMETER: + if (copy_from_user(&msg, argp, sizeof(msg))) + return -EFAULT; + + ret = bu92747_set_parameter(client, (struct rk29_cir_struct_info *)msg); + if (ret < 0) + return ret; + break; + default: + return -ENOTTY; + } + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static int bu92747_open(struct inode *inode, struct file *file) +{ + struct i2c_client *client = container_of(bu92747guw_device.parent, struct i2c_client, dev); + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + struct bu92747guw_platform_data *pdata = bu92747->platdata; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + printk("bu92747_open\n"); +// if (BU92747_OPEN == bu92747->state) +// return -EBUSY; +// bu92747->state = BU92747_OPEN; + + //power on + if (pdata && pdata->cir_pwr_ctl) { + pdata->cir_pwr_ctl(1); + } + + //switch to remote control, mcr, ec_en=1,rc_mode=1 + smc0_write(REG_MCR_ADDR, smc0_read(REG_MCR_ADDR)|(3<<10)); + //set irda pwdownpin = 0 + smc0_write(REG_TRCR_ADDR, smc0_read(REG_TRCR_ADDR)&0xffbf); + BU92747_DBG("irda power down pin = %d\n", gpio_get_value(RK29_PIN5_PA7)); + + //register init + bu92747_cir_init_device(client, bu92747); + start_flag = 0; + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static int bu92747_release(struct inode *inode, struct file *file) +{ + struct i2c_client *client = container_of(bu92747guw_device.parent, struct i2c_client, dev); + struct bu92747_data_info *bu92747 = (struct bu92747_data_info *)i2c_get_clientdata(client); + struct bu92747guw_platform_data *pdata = bu92747->platdata; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + //power down + if (pdata && pdata->cir_pwr_ctl) { + pdata->cir_pwr_ctl(0); + } + +// bu92747->state = BU92747_CLOSE; + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + + return 0; +} + +static struct file_operations bu92747_fops = { + .owner = THIS_MODULE, + .open = bu92747_open, + .release = bu92747_release, + .ioctl = bu92747_ioctl, +}; + +static struct miscdevice bu92747guw_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "rk29_cir", + .fops = &bu92747_fops, +}; + +static int __devinit bu92747_cir_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct bu92747_data_info *bu92747; + struct bu92747guw_platform_data *pdata; + int err; + + BU92747_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + bu92747 = kzalloc(sizeof(struct bu92747_data_info), GFP_KERNEL); + if (!bu92747) { + printk("line %d: bu92747 alloc data failed.\n", __LINE__); + err = -ENOMEM; + goto MEM_ERR; + } + //ioinit + pdata = client->dev.platform_data; + if (pdata && pdata->iomux_init) { + pdata->iomux_init(); + } + + bu92747->platdata = pdata; + bu92747->client = client; + i2c_set_clientdata(client, bu92747); + bu92747->state = BU92747_CLOSE; + + //register device + bu92747guw_device.parent = &client->dev; + err = misc_register(&bu92747guw_device); + if (err) { + printk("line %d: bu92747 misc_register failed.\n", __LINE__); + goto REGISTER_ERR; + } + + //request irq + if (pdata && gpio_is_valid(pdata->intr_pin)) { + printk("-------request irq\n"); + err = gpio_request(pdata->intr_pin, "rk29 cir irq"); + if (err) { + printk("line %d: bu92747 request gpio failed.\n", __LINE__); + goto GPIO_ERR; + } + gpio_direction_input(pdata->intr_pin); + gpio_request(RK29_PIN5_PA7, NULL); + if (err) { + printk("line %d: bu92747 request gpio failed.\n", __LINE__); + } + gpio_direction_input(RK29_PIN5_PA7); + bu92747->irq = gpio_to_irq(pdata->intr_pin); + err = request_irq(bu92747->irq, bu92747_cir_irq, IRQF_TRIGGER_FALLING, client->dev.driver->name, bu92747); + if (err) { + BU92747_DBG("line %d: bu92747 request gpio failed.\n", __LINE__); + goto IRQ_ERR; + } + //disable_irq(bu92747->irq); + } + + //INIT_DELAYED_WORK(&bu92747->dwork, bu92747_dwork_handler); + INIT_DELAYED_WORK(&bu92747->dwork, bu92747_dwork_handler); + + +#if 0 + //bu92747_start(client); + //while (1) { + //bu92747_send_data_test(client); + //BU92747_DBG("line %d: test %s\n", __LINE__, __FUNCTION__); + //mdelay(500); + //} +#endif + + BU92747_DBG("line %d: exit %s\n", __LINE__, __FUNCTION__); + return 0; + +IRQ_ERR: + gpio_free(pdata->intr_pin); +GPIO_ERR: + misc_deregister(&bu92747guw_device); +REGISTER_ERR: + if (pdata && pdata->iomux_deinit) + pdata->iomux_deinit(); + kfree(bu92747); +MEM_ERR: + return err; +} + +static int __devexit bu92747_cir_remove(struct i2c_client *client) +{ + + struct bu92747_data_info *bu92747 = i2c_get_clientdata(client); + struct bu92747guw_platform_data *pdata = bu92747->platdata; + + printk(" cir_remove \n"); + start_flag = 0; + free_irq(bu92747->irq, bu92747); + gpio_free(pdata->intr_pin); + misc_deregister(&bu92747guw_device); + if (pdata && pdata->iomux_deinit) + pdata->iomux_deinit(); + kfree(bu92747); + return 0; +} + +static const struct i2c_device_id bu92747_cir_id[] = { + { "bu92747_cir", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bu92747_cir_id); + +static struct i2c_driver bu92747_cir_driver = { + .driver = { + .name = "bu92747_cir", + .owner = THIS_MODULE, + }, + .probe = bu92747_cir_probe, + .remove = __devexit_p(bu92747_cir_remove), + .id_table = bu92747_cir_id, +}; + +static int __init bu92747_cir_init(void) +{ + return i2c_add_driver(&bu92747_cir_driver); +} + +static void __exit bu92747_cir_exit(void) +{ + i2c_del_driver(&bu92747_cir_driver); +} + +MODULE_AUTHOR("zyw zyw@rock-chips.com"); +MODULE_DESCRIPTION("bu92747 cir driver"); +MODULE_LICENSE("GPL"); + +module_init(bu92747_cir_init); +module_exit(bu92747_cir_exit); + diff --git a/drivers/cir/bu92747guw_cir.h b/drivers/cir/bu92747guw_cir.h new file mode 100755 index 000000000000..5d0e15ef1e86 --- /dev/null +++ b/drivers/cir/bu92747guw_cir.h @@ -0,0 +1,162 @@ +/*drivers/cir/bu92747guw_cir.h - driver for bu92747guw + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRIVERS_CIR_BU92747GUW_CIR_H +#define _DRIVERS_CIR_BU92747GUW_CIR_H + +#include + +/* irda registers addr */ +#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 + +//remote reg +#define REG_SETTING0 0x00 +#define REG_SETTING1 0x01 + +#define REG_BASE_CLOCK 0X02 + +#define REG_CLO1 0x03 +#define REG_CLO0 0x04 +#define REG_CHI1 0x05 +#define REG_CHI0 0x06 + +#define REG_HLO1 0x07 +#define REG_HLO0 0x08 +#define REG_HHI1 0x09 +#define REG_HHI0 0x0a + +#define REG_D0LO1 0x0b +#define REG_D0LO0 0x0c +#define REG_D0HI1 0x0d +#define REG_D0HI0 0x0e + +#define REG_D1LO1 0x0f +#define REG_D1LO0 0x10 +#define REG_D1HI1 0x11 +#define REG_D1HI0 0x12 + +#define REG_ENDLEN1 0x13 +#define REG_ENDLEN0 0x14 +#define REG_BITLEN 0x15 +#define REG_FRMLEN1 0x16 +#define REG_REMLEN0 0x17 + +#define REG_OUT0 0x18 +#define REG_OUT1 0x19 +#define REG_OUT2 0x1A +#define REG_OUT3 0x1B +#define REG_OUT4 0x1C +#define REG_OUT5 0x1D +#define REG_OUT6 0x1E +#define REG_OUT7 0x1F +#define REG_OUT8 0x20 +#define REG_OUT9 0x21 +#define REG_OUT10 0x22 +#define REG_OUT11 0x23 +#define REG_OUT12 0x24 +#define REG_OUT13 0x25 +#define REG_OUT14 0x26 +#define REG_OUT15 0x27 + +#define REG_IRQC 0x28 +#define REG_SEND 0x29 +#define REG_RST 0x2a +#define REG_REGS 0X2b + +// +#define REG0_OPM (1<<5) +#define REG0_DIVS (1<<4) +#define REG0_IRQE (1<<3) +#define REG0_INV1 (1<<2) +#define REG0_INV0 (1<<1) +#define REG0_PWR (1<<0) + +#define REG1_FRMB (1<<5) +#define REG1_FRME (1<<4) +#define REG1_RPT (1<<0) + +#define ul64 unsigned long long +struct rk29_cir_struct_info { + u16 carry_high; // carry_high + u16 carry_low; // carry_low + u16 repeat; // ÊÇ·ñÊÇ Öظ´Ö¡ + u8 inv; //00 01 10 11 Lsb->inv0 + + u16 frame_bit_len; // ÃüÁîÖ¡ÓÐЧλÊý + u16 stop_bit_interval; // period of end part NEC-560us + + ul64 frame; // ÃüÁîÖ¡ LSB->MSB + u32 frame_interval; // frame interval NEC-108000s + + u16 head_burst_time; //pan-3360us(USA) or 3680(Europe)¡¢ nec-9000¡¢ sharp-0¡¢ sony-600us + u16 head_space_time; //pan-6720us(USA) or 7360(Europe)¡¢ nec-450us¡¢sharp-0¡¢ sony-3000us + + u16 logic_high_burst_time; //pan-840us(USA) or 508(Europe)¡¢ nec-560¡¢ sharp-320¡¢ sony-1200us // logic 1 burst time + u16 logic_high_space_time; //pan-3360us(USA) or 3680(Europe)¡¢ nec-1690¡¢ sharp-2000¡¢ sony-1800 // logic 1 time + + u16 logic_low_burst_time; //pan-840us(USA) or 508(Europe)¡¢ nec-560¡¢ sharp-320¡¢ sony-600us // logic 0 burst time + u16 logic_low_space_time; //pan-1680us(USA) or 1816(Europe)¡¢ nec-560¡¢ sharp-1000¡¢ sony-1200 // logic 0 time + +}; + +#define CIR_FRAME_SIZE sizeof(struct rk29_cir_struct_info) + +#define BU92747IO 'B' + +/* IOCTLs for BU92747*/ +/* +#define BU92747_IOCTL_STOP _IO(BU92747IO, 0x01) +#define BU92747_IOCTL_START _IO(BU92747IO, 0x02) +#define BU92747_IOCTL_SET_FORMAT _IOW(BU92747IO, 0x04, char[CIR_FRAME_SIZE]) +#define BU92747_IOCTL_SEND_DATA _IOW(BU92747IO, 0x08, char[CIR_FRAME_SIZE]) +*/ + +#define BU92747_IOCTL_STOP _IO(BU92747IO, 0x01) +#define BU92747_IOCTL_START _IO(BU92747IO, 0x02) +#define BU92747_IOCTL_CARRIER _IOW(BU92747IO, 0x04, char[CIR_FRAME_SIZE]) +#define BU92747_IOCTL_DATA _IOW(BU92747IO, 0x06, char[CIR_FRAME_SIZE]) +#define BU92747_IOCTL_PULSE _IOW(BU92747IO, 0x08, char[CIR_FRAME_SIZE]) +#define BU92747_IOCTL_REPEAT _IOW(BU92747IO, 0x0A, char[CIR_FRAME_SIZE]) +#define BU92747_IOCTL_DURATION _IOW(BU92747IO, 0x0C, char[CIR_FRAME_SIZE]) +#define BU92747_IOCTL_PARAMETER _IOW(BU92747IO, 0x0E, char[CIR_FRAME_SIZE]) + +/*status*/ +#define BU92747_STOP 4 +#define BU92747_BUSY 3 +#define BU92747_SUSPEND 2 +#define BU92747_OPEN 1 +#define BU92747_CLOSE 0 + +struct bu92747guw_platform_data { + u32 intr_pin; + int (*iomux_init)(void); + int (*iomux_deinit)(void); + int (*cir_pwr_ctl)(int en); +}; + +#endif /*_DRIVERS_CIR_BU92747GUW_CIR_H*/ diff --git a/drivers/smc/Kconfig b/drivers/smc/Kconfig index 618908d29318..28f75170f4d7 100755 --- a/drivers/smc/Kconfig +++ b/drivers/smc/Kconfig @@ -1,7 +1,7 @@ config RK29_SMC bool "rk29 smc interface" - default y + default n help if you want to use smc in rk29, pls enable it -- 2.34.1