Commit b4552c1c authored by 张青山(steven.zhang)'s avatar 张青山(steven.zhang)

Merge branch 'neuros' of...

Merge branch 'neuros' of ssh://git@git.neuros.com.cn/git/git-pub/osd20/linux-davinci-2.6 into neuros
parents 268971fd 11c1e25e
......@@ -830,6 +830,7 @@ CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
CONFIG_NEUROS_IR_BLASTER=m
#
# Multifunction device drivers
......
......@@ -39,6 +39,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/arch/hardware.h>
......@@ -55,9 +56,6 @@
#define dbg(fmt, arg...)
#endif
#define GPIO01_DIR __REG(0x01C67010)
#define GPIO01_RIS_INT __REG(0x01C67024)
#define USE_WORKQUEUE 1
#define READ_ONLY_ONE_KEY 1
#define IR_RETRY_COUNT 3
......@@ -190,8 +188,10 @@ static void irrtc_do_wq(struct work_struct *work)
if (is_learning == 1)
{
//disable_irq(IRQ_TIMER1);
//outw( inw( IO_GIO_IRQPORT) & (~GIO3), IO_GIO_IRQPORT); // gio 3 external IRQ disable;
disable_irq(IRQ_TINT1_TINT34);
TIMER1_TCR &= ~(3<<22); //disable timer1 34
CLR_GPIO01_RIS_INT |= (1<<7); // gpio 7 rising edge IRQ disable
CLR_GPIO01_FAL_INT |= (1<<7); // gpio 7 falling edge IRQ disable
lock_data_protect();
set_osd_key(1);
set_is_learning(0);
......@@ -233,10 +233,7 @@ static irqreturn_t handle_irrtc_irqs(int irq, void * dev_id)
static void irqs_irrtc_init( void )
{
GPIO01_DIR |= 0x04; //gio 2 direction input
GPIO01_RIS_INT |= 0x04; // gio 2 rising edge IRQ enable
//outw( inw( IO_GIO_DIR0 ) | 0x0001, IO_GIO_DIR0 ); //gio 0 direction input
//outw( inw( IO_GIO_INV0 ) | 0x0001, IO_GIO_INV0 ); //gio 0 inv
//outw( inw( IO_GIO_IRQPORT) | 0x0001, IO_GIO_IRQPORT); // gio 0 external IRQ enable
SET_GPIO01_RIS_INT |= 0x04; // gio 2 rising edge IRQ enable
request_irq(IRQ_GPIO2, handle_irrtc_irqs, 0, "irrtc", &device);
}
......
......@@ -201,6 +201,19 @@ config THINKPAD_ACPI_BAY
notifications when the bay lever is ejected or inserted.
If you are not sure, say Y here.
config NEUROS_IR_BLASTER
tristate "Neuros IR blaster driver"
depends on ARCH_DAVINCI
---help---
This option enables the Neuros IR blaster driver.
TODO: This needs a better description.
To compile this driver as a module (recommended), choose M here: the
module will be called neuros_ir_blaster.
If unsure and targeting the Neuros OSD, say M.
endif # MISC_DEVICES
......@@ -15,3 +15,4 @@ obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_NEUROS_IR_BLASTER) += neuros_ir_blaster.o
/*
* Copyright(C) 2006-2008 Neuros Technology International LLC.
* <www.neurostechnology.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, version 2 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* IR Blaster Receiver driver.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/arch/irqs.h>
#include <linux/neuros_ir.h>
#include <linux/neuros_ir_blaster.h>
#define MOD_DESC "Neuros IR Blaster Driver (c) 2008"
#if 0
#define dbg(fmt, arg...) \
printk(KERN_INFO "%s:%d> " fmt, __func__, __LINE__ , ## arg)
#else
#define dbg(fmt, arg...)
#endif
#define WAIT_BLASTER_TIME 10
#define DELAY_FOR_IR 200
#define LEANRING_COMPLETE_DELAY (HZ)
#define POLL_RELEASE_DELAY (HZ/10)
#define KEY_WAVE_PRESENT 1
#define WAIT_LEARN_COMPLETE 2
#define WAIT_RELEASE_REMOTE 4
#define BLS_TIMER_PRESCALE 15
#define BLASTER 0
#define CAPTURE 1
#define INT_TIMER1_TIME_WASTE 3
#define INT_CAPTURE_TIME_WASTE 2
#define MAX_COUNTER (0xffffffff)
#define WAIT_HARDWARE_RESET 50 //50ms
#define GIO_BLS (1<<15)
#define GIO_CAP (1<<7)
static int learning_status = 0;
static int bls_wave_count;
static int bls_status=BLS_COMPLETE;
static int timer_int_counter=0;
static int wave_len=0;
static int int_type;
static struct timer_list learning_key_timer;
static struct blaster_data_type *BlsKey;
static struct blaster_data_pack *bls_data_pack;
struct irrtc_device {
int key;
};
static struct irrtc_device device;
static wait_queue_head_t wait;
extern void set_osd_key(int);
extern int get_osd_key(void);
extern void lock_data_protect(void);
extern void unlock_data_protect(void);
extern void set_factory_test(int);
extern void report_key(int key);
extern void set_is_learning(int value);
static void enable_learning(void)
{
SET_GPIO01_RIS_INT |= GIO_CAP; // gpio 7 rising edge IRQ enable
SET_GPIO01_FAL_INT |= GIO_CAP; // gpio 7 falling edge IRQ enable
lock_data_protect();
set_is_learning(1);
unlock_data_protect();
}
static void disable_learning(void)
{
CLR_GPIO01_RIS_INT |= GIO_CAP; // gpio 7 rising edge IRQ disable
CLR_GPIO01_FAL_INT |= GIO_CAP; // gpio 7 falling edge IRQ disable
lock_data_protect();
set_is_learning(0);
unlock_data_protect();
}
static void set_timer1_div(struct blaster_data_pack *blsdat)
{
unsigned int div;
int count;
static int sbit;
if(wave_len)
{
div=wave_len;
if(div>MAX_COUNTER)
div=MAX_COUNTER;
wave_len-=div;
}
else
{
count=blsdat->bitstimes&BITS_COUNT_MASK;
if (count==bls_wave_count)
sbit=0;
if (keybit_get(blsdat->mbits, (count-bls_wave_count)))
{
if (keybit_get(blsdat->dbits, (count-bls_wave_count)))
{
div=blsdat->specbits[sbit];
sbit++;
} else
{
div=blsdat->bit2;
}
} else
{
if (keybit_get(blsdat->dbits, (count-bls_wave_count)))
{
div=blsdat->bit1;
} else
{
div=blsdat->bit0;
}
}
}
TIMER1_TGCR &= ~(15<<8);
TIMER1_TGCR |= BLS_TIMER_PRESCALE<<8;
//div-=div>>5; // The ideal situation is that set the timer prescale to let the timer cycle is 1us
// but the nearest setting make the cycle 1.032us so do this adjustment with
// divider value
div-=INT_TIMER1_TIME_WASTE;
if(div>MAX_COUNTER)
{
wave_len=div-MAX_COUNTER;
div=MAX_COUNTER;
}
div--;
TIMER1_PRD34 = div; // set timer period
}
static void blaster_key(struct blaster_data_pack* blsdat)
{
uint16_t bitset2;
enable_irq(IRQ_TINT1_TINT34);
wave_len=0;
bls_status=BLS_START;
bls_wave_count=blsdat->bitstimes&BITS_COUNT_MASK;
if(bls_wave_count>BLASTER_MAX_CHANGE || bls_wave_count<=0)
{
bls_status=BLS_ERROR;
if(bls_data_pack)
{
kfree(bls_data_pack);
bls_data_pack=NULL;
}
return;
}
GPIO23_DIR &= ~GIO_BLS; //gio 47 direction output
/*check if the io port status correct if not correct set it's logic to reverse of start level and hold for a momemt*/
bitset2=GPIO23_OUT_DATA;
if (((bitset2 & GIO_BLS)!=0)&&((bls_data_pack->bitstimes&BITS_COUNT_MASK)!=0))
{
GPIO23_CLR_DATA |= GIO_BLS;
msleep(WAIT_HARDWARE_RESET);
}
else if (((bitset2 & GIO_BLS)==0)&&((bls_data_pack->bitstimes&BITS_COUNT_MASK)==0))
{
GPIO23_SET_DATA |= GIO_BLS;
msleep(WAIT_HARDWARE_RESET);
}
if(blsdat->bitstimes & FIRST_LEVEL_BIT_MASK)
GPIO23_SET_DATA |= GIO_BLS;
else
GPIO23_CLR_DATA |= GIO_BLS;
set_timer1_div(blsdat);
TIMER1_TCR &= ~(3<<22); //disable timer1 34
TIMER1_TCR |= (2<<22); //enable timer1 34 as continue mode
}
void timer_handle(unsigned long data)
{
int osd_key;
dbg("bitstimes=%d\n", BlsKey->bitstimes);
if (learning_status & WAIT_LEARN_COMPLETE)
{
lock_data_protect();
osd_key=get_osd_key();
unlock_data_protect();
if (!osd_key )
{
disable_irq(IRQ_TINT1_TINT34);
TIMER1_TCR &= ~(3<<22); //disable timer1 34
report_key(LEARNING_COMPLETE_KEY);
//report_key(UP_KEY);
}
learning_status |= WAIT_RELEASE_REMOTE;
learning_status &= ~WAIT_LEARN_COMPLETE;
learning_key_timer.expires = jiffies + POLL_RELEASE_DELAY;
learning_key_timer.function = timer_handle;
add_timer(&learning_key_timer);
}
else if (learning_status & WAIT_RELEASE_REMOTE)
{
if (learning_status & KEY_WAVE_PRESENT)
{
learning_status &= ~KEY_WAVE_PRESENT;
learning_key_timer.expires = jiffies + POLL_RELEASE_DELAY;
learning_key_timer.function = timer_handle;
add_timer(&learning_key_timer);
}
else
{
disable_learning();
lock_data_protect();
osd_key=get_osd_key();
unlock_data_protect();
if (!osd_key )
{
report_key(RELEASE_REMOTE_KEY);
//report_key(UP_KEY);
}
}
}
}
static int capture_key(struct blaster_data_type* blsdat)
{
static int times=0;
static int old_counter;
static int old_int_counter;
int counter;
int td;
if (!(learning_status & WAIT_RELEASE_REMOTE))
{
counter=TIMER1_TIM34;
if (old_int_counter==timer_int_counter)
td=counter - old_counter;
else
td=MAX_COUNTER - old_counter - INT_CAPTURE_TIME_WASTE + counter ;
old_counter=counter;
old_int_counter=timer_int_counter;
if (!(learning_status & WAIT_LEARN_COMPLETE))
{
times = 0;
learning_key_timer.function = timer_handle;
mod_timer(&learning_key_timer, jiffies + LEANRING_COMPLETE_DELAY);
learning_status |= WAIT_LEARN_COMPLETE;
}
if (0 == times++)
{
blsdat->bitstimes |= ((SET_GPIO01_IN_DATA & GIO_CAP) << 8);
return 0;
}
blsdat->bits[times-2]=td;
blsdat->bitstimes++;
if (times == BLASTER_MAX_CHANGE+1)
{
report_key(LEARNING_COMPLETE_KEY);
learning_key_timer.function = timer_handle;
mod_timer(&learning_key_timer, jiffies + POLL_RELEASE_DELAY);
learning_status |= WAIT_RELEASE_REMOTE;
learning_status &= ~WAIT_LEARN_COMPLETE;
}
}
else
learning_status |= KEY_WAVE_PRESENT;
return(0);
}
static irqreturn_t handle_bls_timer1_irqs(int irq, void * dev_id, struct pt_regs * regs)
{
uint32_t bitset2;
if(int_type==CAPTURE)
{
timer_int_counter++;
return IRQ_HANDLED;
}
if(bls_wave_count==0)
return IRQ_HANDLED;
if (!wave_len)
{
bitset2=GPIO23_OUT_DATA;
if (bitset2 & GIO_BLS)
GPIO23_CLR_DATA |= GIO_BLS;
else
GPIO23_SET_DATA |= GIO_BLS;
bls_wave_count--;
}
if(bls_wave_count==0)
{
disable_irq(IRQ_TINT1_TINT34);
TIMER1_TCR &= ~(3<<22); //disable timer1 34
GPIO23_DIR |= GIO_BLS; //gio 47 direction input
bls_status=BLS_COMPLETE;
if(bls_data_pack)
{
kfree(bls_data_pack);
bls_data_pack=NULL;
}
return IRQ_HANDLED;
}
else
{
set_timer1_div(bls_data_pack);
}
return IRQ_HANDLED;
}
static irqreturn_t handle_capture_irqs(int irq, void * dev_id, struct pt_regs * regs)
{
capture_key(BlsKey);
return IRQ_HANDLED;
}
//--------------------------------------------------- DEVICE --------------------------------------------------------------
static int irrtc_open(struct inode * inode, struct file * file)
{
#ifdef ONLYOPENONE
if (opened)
return -EBUSY;
opened = 1;
#endif
return 0;
}
static int irrtc_release(struct inode * inode, struct file * file)
{
#ifdef ONLYOPENONE
if (!opened)
return -ERESTARTSYS;
opened = 0;
#endif
return 0;
}
static int irrtc_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int ret = 0;
int arg_size;
if (_IOC_TYPE(cmd) != NEUROS_IR_BLASTER_IOC_MAGIC)
{
ret = -EINVAL;
goto bail;
}
arg_size = _IOC_SIZE(cmd);
if (_IOC_DIR(cmd) & _IOC_READ)
ret = !access_ok(VERIFY_WRITE, (void *)arg, arg_size);
else if (_IOC_DIR(cmd) & _IOC_WRITE)
ret = !access_ok(VERIFY_READ, (void *)arg, arg_size);
if (ret) goto bail;
switch (cmd)
{
case RRB_BLASTER_KEY:
{
if (bls_status!=BLS_START)
{
int_type=BLASTER;
bls_data_pack=kmalloc(sizeof(struct blaster_data_pack), GFP_KERNEL);
if (bls_data_pack==NULL)
{
ret = -EINVAL;
break;
}
copy_from_user(bls_data_pack, (void*)arg, sizeof(struct blaster_data_pack));
blaster_key(bls_data_pack);
}
}
break;
case RRB_CAPTURE_KEY:
{
set_osd_key(0);
int_type=CAPTURE;
timer_int_counter=0;
TIMER1_TCR &= ~(3<<22); //disable timer1 34
TIMER1_TGCR &= ~(15<<8);
TIMER1_TGCR |= BLS_TIMER_PRESCALE<<8;
TIMER1_PRD34 = MAX_COUNTER; // set timer period
TIMER1_TCR |= (2<<22); //enable timer1 34 as continuous mode
enable_irq(IRQ_TINT1_TINT34);
BlsKey=kmalloc(sizeof(struct blaster_data_type), GFP_KERNEL);
if(BlsKey==NULL)
{
ret = -EINVAL;
break;
}
memset(BlsKey, 0, sizeof(struct blaster_data_type));
learning_status=0;
enable_learning();
}
break;
case RRB_READ_LEARNING_DATA:
{
if(BlsKey)
{
ret |= copy_to_user((void*)arg, BlsKey, sizeof(struct blaster_data_type));
kfree(BlsKey);
BlsKey=NULL;
}
}
break;
case RRB_FACTORY_TEST:
{
set_factory_test(1);
}
break;
case RRB_GET_BLASTER_STATUS:
{
ret |= copy_to_user((void*)arg, &bls_status, sizeof(bls_status));
}
break;
default:
ret = -EINVAL;
break;
}
bail:
return ret;
}
static struct file_operations irrtc_fops = {
.open = irrtc_open,
.release = irrtc_release,
.ioctl = irrtc_ioctl,
};
//-------------------------------------------------- INIT / EXIT ----------------------------------------------------------
static const char * pname = "NEUROS_IRBLAST(KM):";
static int blaster_init( void )
{
PINMUX1 |= (1<<4); //set gio45/PWM0 pin works as PWM0
PWM0_CFG = 2; //set PWM0 contiguous mode
/* PWM0_PER+1=PWM0_PH1D*2 */
/*FIXME: PWM config*/
PWM0_PER = 59;
PWM0_PH1D = 30;
GPIO23_DIR |= GIO_BLS; //gio 47 direction input
TIMER1_TCR &= ~(3<<22); //disable timer1 34
disable_irq(IRQ_TINT1_TINT34);
request_irq(IRQ_TINT1_TINT34, handle_bls_timer1_irqs,SA_INTERRUPT , "ir_blaster_timer1", &device); //TIMER__INTERRUPT
disable_learning();
GPIO01_DIR |= GIO_CAP; //gpio 7 direction input
request_irq(IRQ_GPIO7, handle_capture_irqs,SA_INTERRUPT , "ir_capture", &device); //SA_SHIRQSA_INTERRUPT
}
static int __init irrtc_init(void)
{
int status = 0;
init_timer(&learning_key_timer);
init_waitqueue_head (&wait);
printk(KERN_INFO "\t" MOD_DESC "\n");
status = register_chrdev(NEUROS_IR_BLASTER_MAJOR, "ir_blaster", &irrtc_fops);
if (status != 0)
{
if (status == -EINVAL) printk(KERN_ERR "%s Couldn't register device: invalid major number %d.\n", pname, NEUROS_IR_BLASTER_MAJOR);
else if (status == -EBUSY) printk(KERN_ERR "%s Couldn't register device: major number %d already busy.\n", pname, NEUROS_IR_BLASTER_MAJOR);
else printk(KERN_ERR "%s Couldn't register device: error %d.\n", pname, status);
status = -1;
goto out;
}
blaster_init();
out:
return status;
}
static void __exit irrtc_exit(void)
{
//~ irqs_irrtc_exit();
unregister_chrdev(NEUROS_IR_BLASTER_MAJOR, "ir_blaster");
}
MODULE_AUTHOR("Neuros");
MODULE_DESCRIPTION(MOD_DESC);
MODULE_LICENSE("Neuros Technology LLC");
module_init(irrtc_init);
module_exit(irrtc_exit);
......@@ -41,5 +41,24 @@
#define TEST_KEY 0x3f
#define UP_KEY 0x00
#define GPIO01_DIR __REG(0x01C67010)
#define SET_GPIO01_IN_DATA __REG(0x01C67020)
#define SET_GPIO01_RIS_INT __REG(0x01C67024)
#define CLR_GPIO01_RIS_INT __REG(0x01C67028)
#define SET_GPIO01_FAL_INT __REG(0x01C6702C)
#define CLR_GPIO01_FAL_INT __REG(0x01C67030)
#define GPIO23_DIR __REG(0x01C67038)
#define GPIO23_OUT_DATA __REG(0x01C6703C)
#define GPIO23_SET_DATA __REG(0x01C67040)
#define GPIO23_CLR_DATA __REG(0x01C67044)
#define PINMUX1 __REG(0x01C40004)
#define PWM0_CFG __REG(0x01C22008)
#define PWM0_PER __REG(0x01C22014)
#define PWM0_PH1D __REG(0x01C22018)
#define TIMER1_TIM34 __REG(0x01C21414)
#define TIMER1_PRD34 __REG(0x01C2141C)
#define TIMER1_TCR __REG(0x01C21820)
#define TIMER1_TGCR __REG(0x01C21824)
#endif /* NEUROS_IR__H */
......@@ -32,8 +32,6 @@
#include <stdint.h>
#endif
#define BLASTER_THROUGH_ARM
#define GIO3 0x0008
#define KEY_MASK 0xff
#define NEUROS_IR_BLASTER_MAJOR 111
#define NEUROS_IR_BLASTER_IOC_MAGIC 'b'
......@@ -53,7 +51,6 @@
#define CAPTRUE_PRECISION3 17 /*averaged off x% difference.*/
#define the_same3(x,y) the_same(x,y,CAPTRUE_PRECISION3)
#ifdef BLASTER_THROUGH_ARM
#define BLS_START 0
#define BLS_COMPLETE 1
#define BLS_ERROR -1
......@@ -72,47 +69,6 @@ struct blaster_data_type {
uint32_t bits[BLASTER_MAX_CHANGE]; /*each bit length*/
};
#else
// I2C command definitions.
#define cmdBLASTER_SEND 0x18
/* RRB registers definitions. */
#define regCMND 0 // command register.
#define regBLASTER_DBITS (0x80+24) // used to put blaster data(part7)
#define regBLASTER_MBITS 0x80 // used to put blaster data(part6)
#define regFLASH_DATA 0x06 // used to put blaster data(part5)
#define regBLASTER_BIT2 (regBLASTER_DATA+6) // used to put blaster data(part4)
#define regBLASTER_BIT1 (regBLASTER_DATA+4) // used to put blaster data(part3)
#define regBLASTER_BIT0 (regBLASTER_DATA+2) // used to put blaster data(part2)
#define regBLASTER_DATA 0x1C // used to put blaster data(part1)
#define BLASTER_MAX_CHANGE (8*24) /* maximum edge changes. */
#define BLASTER_MAX_SBITS 8 /*special edge number min is 6*/
#define BLASTER_MAX_BITS (8*24) /*maximum edge changes, use for uncompacted data structure*/
#define END_COUNT 8 /*number of edges for end bit. */
#define BITS_COUNT_START 7 /*bits count start. */
#define END_FLAG_START 6 /*end flag mask. */
#define BITS_COUNT_MASK (0xFF<<BITS_COUNT_START) /*bits count mask. */
#define END_FLAG_MASK (1<<END_FLAG_START) /*end flag mask. */
#define MAX_REPEAT_TIMES 7 /*bits count start. */
#define BITS_TIMES_MASK 0xFFF8 /*bits times mask. */
#define FIRST_LEVEL_BIT_START 15 /*bits count start. */
#define FIRST_LEVEL_BIT_MASK (1<<FIRST_LEVEL_BIT_START) /*end flag mask. */
struct blaster_data_type {
uint16_t bitstimes; /*first[15] 1 bit 1=high level 0=low level;
[8+BITS_COUNT_START-BITS_COUNT_START]8 bit =how many bits;
[END_FLAG_START] 1=have end bits 0=not have end bits
[2-0]3 bit=how many repeat times*/
uint16_t start1; /*start mark first length */
uint16_t start2; /*start mark second length*/
uint16_t interval; /*interval for each times */
uint16_t bits[BLASTER_MAX_BITS]; /*each bit length*/
uint16_t end[END_COUNT];
};
#endif
struct blaster_data_pack {
uint16_t bitstimes; /*first[15] 1 bit 1=high level 0=low level;
[7+BITS_COUNT_START-BITS_COUNT_START]8 bit =how many bits;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment