动手写的input中断驱动(挂在i2c上)
it7230.c
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/input-polldev.h>
#include <linux/delay.h>
#include <linux/fsl_devices.h>
#include "It7230.h"
#include <linux/time.h>
#define stage00 0x001 //menu pad
#define stage01 0x002 //back pad
#define stage02 0x004 //home pad
#define stage03 0x008
#define stage04 0x010 //
#define POLL_INTERVAL 200
#define DEVICE_NAME "it7230"
//#define DEBUG 1
u8 current_page = 1;
static int suspend_flag = 0;
static struct workqueue_struct *it7230_wq;
static struct work_struct it7230_work;
static int globle_irq;
//init it7230 register
const sInitCapSReg asInitCapSReg[] = {
{ PAGE_1, CAPS_PCR ,0x0001},
{ PAGE_1, CAPS_PSR ,0x0001},
{ PAGE_1, CAPS_PMR ,0x0000},
{ PAGE_1, CAPS_RTR ,0x0000},
{ PAGE_1, CAPS_CTR ,0x0000},
{ PAGE_1, CAPS_CRMR ,0x0020},
{ PAGE_1, CAPS_PDR ,0x1FFF},
{ PAGE_1, CAPS_DR ,0x0050},
{ PAGE_1, CAPS_S0CR ,0xC021},
{ PAGE_1, CAPS_S1CR ,0xC043},
{ PAGE_1, CAPS_S2CR ,0xC097},
{ PAGE_1, CAPS_C1COR ,0x71B1},
{ PAGE_1, CAPS_C2COR ,0x71B1},
{ PAGE_1, CAPS_C3COR ,0x70B2},
{ PAGE_1, CAPS_C4COR ,0x71B2},
{ PAGE_1, CAPS_C7COR ,0x7AB2},
{ PAGE_1, CAPS_C9COR ,0x70B2},
{ PAGE_1, CAPS_ICR0 ,0xBFBB},
{ PAGE_1, CAPS_ICR1 ,0x0FFF},
{ PAGE_1, CAPS_COER0 ,0xFFFF},
{ PAGE_1, CAPS_COER1 ,0x03FF},
{ PAGE_1, CAPS_CGCR ,0x0001},
{ PAGE_1, CAPS_LEDBR ,0x0000},
{ PAGE_1, CAPS_GPIODR ,0x0000},
{ PAGE_1, CAPS_GPIOOR ,0x0000},
{ PAGE_1, CAPS_GPIOMR ,0x0000},
{ PAGE_1, CAPS_GPIOLR ,0x001C},
{ PAGE_1, CAPS_GPIOER ,0x0000},
{ PAGE_1, CAPS_LEDCMR0 ,0x20DD},
{ PAGE_1, CAPS_LEDCMR1 ,0xDDD1},
{ PAGE_1, CAPS_LEDCMR2 ,0xDDDD},
{ PAGE_1, CAPS_LEDCMR3 ,0x0DDD},
{ PAGE_1, CAPS_LEDRPR ,0x3030},
{ PAGE_1, CAPS_LEDBR ,0x001F},
{ PAGE_1, CAPS_LEDCGCR ,0x0000},
{ PAGE_1, CAPS_LEDPR0 ,0x2244},
{ PAGE_1, CAPS_LEDPR1 ,0x4442},
{ PAGE_1, CAPS_LEDPR2 ,0x4444},
{ PAGE_1, CAPS_LEDPR3 ,0x0444},
{ PAGE_1, CAPS_GPIOMSR ,0x001C},
{ PAGE_0, CAPS_S0DLR ,0x8000},
{ PAGE_0, CAPS_S0OHCR ,0x0700},
{ PAGE_0, CAPS_S0OLCR ,0x7000},
{ PAGE_0, CAPS_S0SR ,0xCC88},
{ PAGE_0, CAPS_S1DLR ,0x8000},
{ PAGE_0, CAPS_S1OHCR ,0x0700},
{ PAGE_0, CAPS_S1OLCR ,0x7000},
{ PAGE_0, CAPS_S1SR ,0xCC88},
{ PAGE_0, CAPS_S2DLR ,0x8000},
{ PAGE_0, CAPS_S2OHCR ,0x0700},
{ PAGE_0, CAPS_S2OLCR ,0x7000},
{ PAGE_0, CAPS_S2SR ,0xCC88},
{ PAGE_0, CAPS_SXCHAIER ,0x0000},
{ PAGE_0, CAPS_SXCHRIER ,0x0000},
{ PAGE_0, CAPS_SXCLAIER ,0x0000},
{ PAGE_0, CAPS_SXCLRIER ,0x0000},
{ PAGE_1, CAPS_GPIONPCR ,0x1FFF},
{ PAGE_1, CAPS_CFER ,0x4000},
{ PAGE_1, CAPS_PCR ,0x2C06}
};
struct capsTouch {
//const struct ov5642_platform_data *platform_data;
//struct v4l2_int_device *v4l2_int_device;
struct i2c_client *i2c_client;
//struct v4l2_pix_format pix;
//struct v4l2_captureparm streamcap;
//bool on;
int (*get_key_status) (int);
} it7230_data;
static struct input_dev *it7230_idev;
//static struct input_polled_dev *it7230_idev;
extern void it7230_i2c_clk(void);
extern void it7230_i2c_gpio_low(void);
static int it7230_probe(struct i2c_client *client,
const struct i2c_device_id *device_id);
static int it7230_remove(struct i2c_client *client);
static int it7230_suspend(struct i2c_client *client, pm_message_t state);
static int it7230_resume(struct i2c_client *client);
static s32 it7230_read_reg(u8 reg);
static s32 it7230_write_reg(u8 reg, u16 val);
//static void it7230_dev_poll(struct input_dev *it7230_idev);
void it7230_delay(int ms)
{
if(suspend_flag)
udelay(1000*ms);//suspend use udelay
else
msleep(ms);
}
static const struct i2c_device_id it7230_id[] = {
{"it7230", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, it7230_id);
static struct i2c_driver it7230_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "it7230",
},
.probe = it7230_probe,
.remove = it7230_remove,
.suspend = it7230_suspend,
.resume = it7230_resume,
.id_table = it7230_id,
};
/*reset it7230 when i2c clk always high if press three keys.
pull i2c1_scl pin low for 4ms,it7230 ic will reset*/
void reset_it7230_i2c(void)
{
//struct i2c_adapter *adap = it7230_data.i2c_client->adapter;
//rt_mutex_lock(&adap->bus_lock);//get real time mutex lock
it7230_i2c_gpio_low();//pull low the i2c1_scl pin
#ifdef DEBUG
printk("it7230 i2c reset\n");
#endif
//msleep(10);
it7230_delay(15);//delay 10ms
it7230_i2c_clk();
//rt_mutex_unlock(&adap->bus_lock);
}
//write i2c
static s32 it7230_write_reg(u8 reg, u16 val)
{
s32 ret = 0;
int retry = 3;
do {
ret = i2c_smbus_write_word_data(it7230_data.i2c_client,reg,val);
if(!retry--)
{
pr_err("%s:write reg error:page=%x,reg=%x,val=%x\n",
__func__, current_page,reg, val);
reset_it7230_i2c();
break;
}
}while(ret < 0);
return ret;
}
//read i2c
static s32 it7230_read_reg(u8 reg)
{
s32 ret = 0;
//int retry = 3;
/*do {
ret = i2c_smbus_read_word_data(it7230_data.i2c_client,reg);
if(!retry--)
{
pr_err("%s:read reg error:page=%x,reg=%x,val=%x\n",
__func__, current_page,reg, ret);
reset_it7230_i2c();
break;
}
}while(ret < 0);*/
//for it7230 reset quickly,reduce read time
ret = i2c_smbus_read_word_data(it7230_data.i2c_client,reg);
if((ret > 0x00ff)||(ret < 0))//this program,only need to read CAPS_SIR and CAPS_SXCHSR,if above 0x00ff,I think it is failed too
{
pr_err("%s:read reg error:page=%x,reg=%x,val=%x\n",
__func__, current_page,reg, ret);
reset_it7230_i2c();
}
return ret;
}
//power on
void CapS_PowerOn(void)
{
u8 temp = 0x00;//59
while (temp < (sizeof(asInitCapSReg)/sizeof(sInitCapSReg)))
{
CapS_Write_Reg(asInitCapSReg[temp].page, asInitCapSReg[temp].reg, asInitCapSReg[temp].value);
temp++;
if (temp == 1)
{
udelay(1000);//Delay 1 ms
}
}
}
//check page
void checkPage(u8 page)
{
u16 bTempData = 0x00;
s32 ret = 0;
if (page != current_page)
{
if (page == 0x01)
{
bTempData = 0x01;
ret = it7230_write_reg(CAPS_PSR,bTempData);
}
else
{
bTempData = 0x00;
ret = it7230_write_reg(CAPS_PSR,bTempData);
}
if(ret >= 0)
current_page = page;
}
}
s32 CapS_Write_Reg(u8 page,u8 reg, u16 val)
{
s32 flag = 0;
checkPage(page);
flag = it7230_write_reg(reg,val);
if (CAPS_PCR == reg && 1 == page && (val & 0x0001))
{
current_page = 0;
}
return flag;
}
s32 CapS_Read_Reg(u8 page, u8 reg)
{
s32 value;
checkPage(page);
value = it7230_read_reg(reg);
if(value < 0)
value = 0;
#ifdef DEBUG
printk("it7230 i2c read data:%x \n", value);
#endif
return value;
}
void resetIT7230(void)
{
int i;
CapS_PowerOn();
for( i=0; i<200; i++)//delay 200ms
{
udelay(1000);
}
CapS_Write_Reg(PAGE_1, CAPS_RTR, 0x005f);//me must set the value ??.
CapS_Write_Reg(PAGE_1, CAPS_CTR, 0x001f);
CapS_Write_Reg(PAGE_1, CAPS_CFER, 0xC000);
CapS_Read_Reg(PAGE_0, CAPS_SIR);//To clear contact interrupts if any.
CapS_Write_Reg(PAGE_0, CAPS_SXCHAIER, 0x0007);
CapS_Write_Reg(PAGE_0, CAPS_SXCHRIER, 0x0007);
//CapS_Write_Reg(PAGE_0, CAPS_SXCLAIER, 0x0000);
}
/*******************************************
read the SXCHSR
*****************************************/
s32 KeyPolling(void)
{
s32 wKeyValue = 0x0000;
//if(CapS_Read_Reg(PAGE_0,CAPS_SXCSR)&0x0007)//conversion complete?
wKeyValue=( CapS_Read_Reg(PAGE_0,CAPS_SXCHSR)&0x0007);//|(CapS_Read_Reg(PAGE_0,CAPS_SXCLSR)&0x0007);
return wKeyValue;
}
//
static irqreturn_t it7230_dev_detect_handler(int irq, void *data)
{
//printk("requst globle irq %d irq %d\n", globle_irq, irq);//debug
disable_irq_nosync(irq);
queue_work( it7230_wq, &it7230_work);//use queue work
return IRQ_HANDLED;
}
//work to schedule
static void it7230_ts_poscheck(struct work_struct *work)
{
//struct timeval tpstart,tpend;
//int timeuse;
//do_gettimeofday(&tpstart);
u32 ButtonValue = 0x0000;
static u32 lastButtonValue = 0;
//int PinStatus;
//struct mxc_ite_platform_data *plat = it7230_data.i2c_client->dev.platform_data;
//it7230_data.get_key_status = plat->get_pins;
//PinStatus = it7230_int_pin_getstatus(0);
//printk("pin status:%x",PinStatus);
ButtonValue = KeyPolling();//CapS_Read_Reg(PAGE_0,CAPS_SXCHSR)&0x0007;
#ifdef DEBUG
printk("ButtonValue:%x",ButtonValue);
#endif
if( (ButtonValue!=7) && (ButtonValue!=3) && (ButtonValue!=5) && (ButtonValue!=6))
{
if(lastButtonValue != ButtonValue)
{
u32 tmpLastButtonValue = lastButtonValue;
u32 tmpButtonValue = ButtonValue;
lastButtonValue = ButtonValue;
tmpButtonValue ^= tmpLastButtonValue;
if(tmpButtonValue & stage00)
{
if(ButtonValue & stage00)
input_event(it7230_idev, EV_KEY, 0x8b, 1);//menu pad
else
input_event(it7230_idev, EV_KEY, 0x8b, 0);//menu pad
}
if(tmpButtonValue & stage01)
{
if(ButtonValue & stage01)
input_event(it7230_idev, EV_KEY, 0x9e, 1);//back pad
else
input_event(it7230_idev, EV_KEY, 0x9e, 0);//back pad
}
if(tmpButtonValue & stage02)
{
if(ButtonValue & stage02)
input_event(it7230_idev, EV_KEY, 0x66, 1);//home pad
else
input_event(it7230_idev, EV_KEY, 0x66, 0);//home pad
}
input_sync(it7230_idev);
}
}
//do_gettimeofday(&tpend);
//timeuse = 1000000*(tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
//timeuse /= 1000;//ms
//printk("used time:%d\n",timeuse);
enable_irq(globle_irq);
}
static int it7230_probe(struct i2c_client *client,
const struct i2c_device_id *device_id)
{
int ret,i;
it7230_data.i2c_client = client;
resetIT7230();
for(i=0; i<200; i++)//delay 200ms
{
udelay(1000);
}
/*input device register */
it7230_idev = input_allocate_device();
if (!it7230_idev)
{
dev_err(&client->dev, "alloc input device failed!\n");
ret = -ENOMEM;
//goto error_rm_hwmon_dev;
}
INIT_WORK(&it7230_work, it7230_ts_poscheck);
//it7230_idev->poll = it7230_dev_poll;
//it7230_idev->poll_interval = POLL_INTERVAL;
/*idev = it7230_idev->input;*/
it7230_idev->name = DEVICE_NAME;
it7230_idev->id.bustype = BUS_I2C;
it7230_idev->dev.parent = &client->dev;
it7230_idev->evbit[0] = BIT_MASK(EV_KEY);
input_set_capability(it7230_idev,EV_KEY,0x8b);//menu pad
input_set_capability(it7230_idev,EV_KEY,0x9e);//back pad
input_set_capability(it7230_idev,EV_KEY,0x66);//home pad
ret = input_register_device(it7230_idev);
if (ret)
{
dev_err(&client->dev, "register device failed!\n");
//goto error_free_poll_dev;
}
globle_irq = client->irq;
if(client->irq)
{
//ret = request_irq(client->irq, it7230_dev_detect_handler, IRQF_TRIGGER_FALLING, DEVICE_NAME, &it7230_data);
ret = request_irq(client->irq, it7230_dev_detect_handler, IRQF_TRIGGER_LOW, DEVICE_NAME, &it7230_data);
if(ret < 0)
{
dev_warn(&client->dev, "error:it7230 can not requst irq %d\n", client->irq);
}
else
printk("it7230 can requst irq %d\n", client->irq);
}
return ret;
}
static int it7230_remove(struct i2c_client *client)
{
input_unregister_device(it7230_idev);
input_free_device(it7230_idev);
return 0;
}
static int it7230_suspend(struct i2c_client *client, pm_message_t state)
{
suspend_flag = 1;
CapS_Write_Reg(PAGE_1, CAPS_PMR, 0x0008);//idle mode
printk("it7230 SUSPEND\n");
return 0;
}
//need init register after resume
static int it7230_resume(struct i2c_client *client)
{
int i;
suspend_flag = 0;
//CapS_Write_Reg(PAGE_1, CAPS_PMR, 0x0000);//active mode
resetIT7230();
for(i=0; i<200; i++)//delay 200ms
{
udelay(1000);
}
return 0;
}
static __init int it7230_init(void)
{
u8 err;
err = i2c_add_driver(&it7230_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed, error=%d \n",
__func__, err);
it7230_wq = create_singlethread_workqueue("it7230_wq");
return err;
}
/*
* @return Error code indicating success or failure
*/
static void __exit it7230_clean(void)
{
i2c_del_driver(&it7230_i2c_driver);
if(it7230_wq)
destroy_workqueue(it7230_wq);
}
module_init(it7230_init);
module_exit(it7230_clean);
MODULE_AUTHOR("GAEA, Inc.");
MODULE_DESCRIPTION("it7230 cap sensor touch driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");
在mx51_babbage.c中,一些gpio操作函数和i2c注册
//envi20110825 +<< change gpio
void it7230_i2c_clk(void)
{
gpio_free(BABBAGE_IT7230_I2C1_GPIO);
iomux_v3_cfg_t i2c_clk = MX51_PAD_EIM_D19__I2C1_SCL;
mxc_iomux_v3_setup_pad(i2c_clk);
}
EXPORT_SYMBOL(it7230_i2c_clk);
void it7230_i2c_gpio_low(void)
{
iomux_v3_cfg_t i2c_gpio = MX51_PAD_EIM_D19__GPIO2_3;
mxc_iomux_v3_setup_pad(i2c_gpio);
gpio_request(BABBAGE_IT7230_I2C1_GPIO, "it7230-gpio");
gpio_direction_output(BABBAGE_IT7230_I2C1_GPIO, 0);
gpio_set_value(BABBAGE_IT7230_I2C1_GPIO, 0);
}
EXPORT_SYMBOL(it7230_i2c_gpio_low);
//envi
//envi20110809++ <<
static int it7230_int_pin_getstatus(int id)
{
return gpio_get_value(BABBAGE_IT7230_INT_PIN);
};
EXPORT_SYMBOL(it7230_int_pin_getstatus);
static struct mxc_ite_platform_data it7230_pin_data = {
.get_pins = it7230_int_pin_getstatus,
};
//envi20110809++ >>
static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
{
.type = "it7230",
.addr = 0x46,
.irq = gpio_to_irq(BABBAGE_IT7230_INT_PIN),
.platform_data =(void *)&it7230_pin_data,
},