modify expand gpio tca6424'interrupt to respond Matrix Keyboard,At the same

time separate soft interrupt from tca6424.c

Details:rk2818_info_defconfig default open soft interrupt and matrix keyboard.
board-infosdk.c modify I2C1 mode from IRQ to POLL,add member for struct
rk2818_tca6424_data, add  privata data for Matrix Keyboard.board.h modify
tca6424_platform_data.Kconfig and Makefile add soft interrupt Configuration.
soft_interrupt.c and tca6424.c are the main modify, they will not affect other
 modules.i2c-rk2818.c retain control SCL function for old tca6424 device,it
will remove later.Matrix Keyboard.c is modify based on kernel Matrix Keyboard.c
file.
This commit is contained in:
宋秀杰 2010-09-07 19:18:03 -07:00
parent f67fa35eb0
commit bc93e99079
11 changed files with 903 additions and 571 deletions

View File

@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.32.9
# Fri Sep 3 11:41:57 2010
# Tue Sep 7 18:19:13 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@ -711,7 +711,7 @@ CONFIG_INPUT_KEYBOARD=y
# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_KEYBOARD_MATRIX is not set
CONFIG_KEYBOARD_MATRIX=y
# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OPENCORES is not set
@ -888,6 +888,7 @@ CONFIG_GPIOLIB=y
CONFIG_IOEXTEND_TCA6424=y
CONFIG_EXPANDED_GPIO_NUM=24
CONFIG_EXPANDED_GPIO_IRQ_NUM=24
CONFIG_SOFT_INTERRUPT=y
CONFIG_SPI_FPGA_GPIO_NUM=0
CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0
# CONFIG_W1 is not set
@ -941,6 +942,7 @@ CONFIG_REGULATOR_DEBUG=y
# CONFIG_REGULATOR_LP3971 is not set
# CONFIG_REGULATOR_TPS65023 is not set
# CONFIG_REGULATOR_TPS6507X is not set
# CONFIG_RK2818_REGULATOR_CHARGE is not set
# CONFIG_RK2818_REGULATOR_LP8725 is not set
CONFIG_MEDIA_SUPPORT=y
@ -1909,4 +1911,4 @@ CONFIG_REED_SOLOMON_DEC8=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_NLATTR=y
CONFIG_NLATTR=y

View File

@ -45,6 +45,9 @@
#include "devices.h"
#include <linux/input/matrix_keypad.h>
#include "../../../drivers/spi/rk2818_spim.h"
#include "../../../drivers/input/touchscreen/xpt2046_ts.h"
#include "../../../drivers/staging/android/timed_gpio.h"
@ -449,6 +452,10 @@ struct tca6424_platform_data rk2818_tca6424_data={
.gpio_irq_start=NR_AIC_IRQS + 2*NUM_GROUP + CONFIG_SPI_FPGA_GPIO_IRQ_NUM,
.irq_pin_num=CONFIG_EXPANDED_GPIO_IRQ_NUM,
.tca6424_irq_pin=RK2818_PIN_PA1,
.expand_port_group = 3,
.expand_port_pinnum = 8,
.rk_irq_mode = IRQF_TRIGGER_LOW,
.rk_irq_gpio_pull_up_down = GPIOPullUp,
.settinginfo=extgpio_tca6424_settinginfo,
.settinginfolen=ARRAY_SIZE(extgpio_tca6424_settinginfo),
.names="extend_gpio_tca6424",
@ -513,7 +520,7 @@ struct rk2818_i2c_platform_data default_i2c1_data = {
.flags = 0,
.slave_addr = 0xff,
.scl_rate = 400*1000,
.mode = I2C_MODE_IRQ,
.mode = I2C_MODE_POLL,
.io_init = rk2818_i2c1_io_init,
};
@ -1377,6 +1384,125 @@ struct platform_device rk2818_device_dm9k = {
};
#endif
#ifdef CONFIG_KEYBOARD_MATRIX
/*
* InfoPhone Matrix Keyboard Device
*/
#define KEYOUT0 TCA6424_P01
#define KEYOUT1 TCA6424_P02
#define KEYOUT2 TCA6424_P03
#define KEYOUT3 TCA6424_P04
#define KEYOUT4 TCA6424_P05
#define KEYIN0 TCA6424_P12
#define KEYIN1 TCA6424_P13
#define KEYIN2 TCA6424_P14
#define KEYIN3 TCA6424_P15
#if 1
static const uint32_t rk2818matrix_keymap[] = {
#if 0
KEY(0, 0, KEY_1),
KEY(0, 1, KEY_3),
KEY(0, 2, KEY_5),
KEY(0, 3, KEY_6),
KEY(0, 4, KEY_7),
KEY(1, 0, KEY_2),
KEY(1, 1, KEY_4),
KEY(1, 2, KEY_R),
KEY(1, 3, KEY_Y),
KEY(1, 4, KEY_8),
KEY(2, 0, KEY_TAB),
KEY(2, 1, KEY_Q),
KEY(2, 2, KEY_E),
KEY(2, 3, KEY_T),
KEY(2, 4, KEY_G),
KEY(3, 0, KEY_LEFTCTRL),
KEY(3, 1, KEY_W),
KEY(3, 2, KEY_S),
KEY(3, 3, KEY_F),
KEY(3, 4, KEY_V),
#else
KEY(0, 0, KEY_1),
KEY(1, 0, KEY_2),
KEY(2, 0, KEY_3),
KEY(3, 0, KEY_TAB),
KEY(0, 1, KEY_4),
KEY(1, 1, KEY_5),
KEY(2, 1, KEY_6),
KEY(3, 1, KEY_R),
KEY(0, 2, KEY_7),
KEY(1, 2, KEY_8),
KEY(2, 2, KEY_9),
KEY(3, 2, KEY_Q),
KEY(0, 3, KEY_E),
KEY(1, 3, KEY_0),
KEY(2, 3, KEY_G),
KEY(3, 3, KEY_LEFTCTRL),
KEY(0, 4, KEY_W),
KEY(1, 4, KEY_S),
KEY(2, 4, KEY_F),
KEY(3, 4, KEY_V),
#endif
};
#else
static const uint32_t rk2818matrix_keymap[] = {
KEY(0, 0, KEY_1),
KEY(0, 1, KEY_2),
KEY(0, 2, KEY_3),
KEY(0, 3, KEY_TAB),
KEY(1, 0, KEY_4),
KEY(1, 1, KEY_5),
KEY(1, 2, KEY_6),
KEY(1, 3, KEY_R),
KEY(2, 0, KEY_7),
KEY(2, 1, KEY_8),
KEY(2, 2, KEY_9),
KEY(2, 3, KEY_LEFTCTRL),
KEY(3, 0, KEY_SWITCHVIDEOMODE),
KEY(3, 1, KEY_0),
KEY(3, 2, KEY_S),
KEY(3, 3, KEY_F),
KEY(4, 0, KEY_G),
KEY(4, 1, KEY_W),
KEY(4, 2, KEY_S),
KEY(4, 3, KEY_F),
};
#endif
static struct matrix_keymap_data rk2818matrix_keymap_data = {
.keymap = rk2818matrix_keymap,
.keymap_size = ARRAY_SIZE(rk2818matrix_keymap),
};
static const int rk2818matrix_row_gpios[] =
{ KEYIN0, KEYIN1, KEYIN2, KEYIN3 };
static const int rk2818matrix_col_gpios[] =
{ KEYOUT0, KEYOUT1, KEYOUT2, KEYOUT3, KEYOUT4 };
static struct matrix_keypad_platform_data rk2818matrixkey_pdata = {
.keymap_data = &rk2818matrix_keymap_data,
.row_gpios = rk2818matrix_row_gpios,
.col_gpios = rk2818matrix_col_gpios,
.num_row_gpios = ARRAY_SIZE(rk2818matrix_row_gpios),
.num_col_gpios = ARRAY_SIZE(rk2818matrix_col_gpios),
.col_scan_delay_us = 100,
.debounce_ms = 10,
.wakeup = 1,
};
static struct platform_device rk2818_device_matrixkey = {
.name = "matrix-keypad",
.id = -1,
.dev = {
.platform_data = &rk2818matrixkey_pdata,
},
};
#endif /* CONFIG_KEYBOARD_MATRIX */
#ifdef CONFIG_HEADSET_DET
struct rk2818_headset_data rk2818_headset_info = {
.irq = TCA6424_P23,
@ -1482,6 +1608,9 @@ static struct platform_device *devices[] __initdata = {
#ifdef CONFIG_DM9000
&rk2818_device_dm9k,
#endif
#ifdef CONFIG_KEYBOARD_MATRIX
&rk2818_device_matrixkey,
#endif
#ifdef CONFIG_HEADSET_DET
&rk28_device_headset,
#endif

View File

@ -127,42 +127,47 @@ struct rk2818_gpio_expander_info {
struct pca9554_platform_data {
/* the first extern gpio number in all of gpio groups */
unsigned gpio_base;
unsigned gpio_pin_num;
unsigned int gpio_base;
unsigned int gpio_pin_num;
/* the first gpio irq number in all of irq source */
unsigned gpio_irq_start;
unsigned irq_pin_num; //中断的个数
unsigned pca9954_irq_pin; //扩展IO的中断挂在哪个gpio
unsigned int gpio_irq_start;
unsigned int irq_pin_num; //中断的个数
unsigned int pca9954_irq_pin; //扩展IO的中断挂在哪个gpio
/* initial polarity inversion setting */
uint16_t invert;
uint16_t invert;
struct rk2818_gpio_expander_info *settinginfo;
int settinginfolen;
void *context; /* param to setup/teardown */
void *context; /* param to setup/teardown */
int (*setup)(struct i2c_client *client,unsigned gpio, unsigned ngpio,void *context);
int (*teardown)(struct i2c_client *client,unsigned gpio, unsigned ngpio,void *context);
char **names;
char **names;
};
struct tca6424_platform_data {
/* the first extern gpio number in all of gpio groups */
unsigned gpio_base;
unsigned gpio_pin_num;
unsigned int gpio_base;
unsigned int gpio_pin_num;
/* the first gpio irq number in all of irq source */
unsigned gpio_irq_start;
unsigned irq_pin_num; //中断的个数
unsigned tca6424_irq_pin; //扩展IO的中断挂在哪个gpio
unsigned int gpio_irq_start;
unsigned int irq_pin_num; //中断的个数
unsigned int tca6424_irq_pin; //扩展IO的中断挂在哪个gpio
unsigned int expand_port_group;
unsigned int expand_port_pinnum;
unsigned int rk_irq_mode;
unsigned int rk_irq_gpio_pull_up_down;
/* initial polarity inversion setting */
uint16_t invert;
struct rk2818_gpio_expander_info *settinginfo;
int settinginfolen;
void *context; /* param to setup/teardown */
void *context; /* param to setup/teardown */
int (*setup)(struct i2c_client *client,unsigned gpio, unsigned ngpio,void *context);
int (*teardown)(struct i2c_client *client,unsigned gpio, unsigned ngpio,void *context);
char **names;
char **names;
void (*reseti2cpin)(void);
};

View File

@ -252,6 +252,10 @@ config EXPANDED_GPIO_IRQ_NUM
int "setting the amount of expanded gpio irqs"
help
for tca6424, set 24
config SOFT_INTERRUPT
bool "soft interrupt for expand gpio use"
help
if you want expand gpio support interrupt,choose it
config SPI_FPGA_GPIO_NUM
default 96

View File

@ -21,3 +21,4 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o
obj-$(CONFIG_GPIO_PCA9554) += pca9554.o
obj-$(CONFIG_IOEXTEND_TCA6424) += tca6424.o
obj-$(CONFIG_SOFT_INTERRUPT) += soft_interrupt.o

448
drivers/gpio/soft_interrupt.c Executable file
View File

@ -0,0 +1,448 @@
/*
* 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.
*/
/*******************************************************************/
/* COPYRIGHT (C) ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED.*/
/*******************************************************************
FILE : Soft_interrupt.c
MODIFY : sxj
DATE : 2010-9-2
NOTES :
********************************************************************/
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <asm/mach-types.h>
#include <linux/irq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/rk2818_iomap.h>
#include <mach/iomux.h>
#include <linux/device.h>
#include <mach/gpio.h>
#include <asm/gpio.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <mach/board.h>
#include <linux/delay.h>
#include <linux/i2c/tca6424.h>
#include <linux/ktime.h>
#include "../drivers/gpio/soft_interrupt.h"
#if 0
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
#if 0
#define DBGERR(x...) printk(KERN_INFO x)
#else
#define DBGERR(x...)
#endif
#define EXTPAND_GPIO_GET_BIT(a,num) (((a)>>(num))&0x01)
#define EXTPAND_GPIO_SET_BIT(a,num) ((a)|(0x01<<(num)))
#define EXTPAND_GPIO_CLEAR_BIT(a,num) ((a)&(~(0x01<<(num))))
#define MIN(x,y) (((x)<(y))?(x):(y))
int expand_gpio_irq_en = -1;
int expand_gpio_irq_ctrflag = -1;
unsigned int expand_gpio_irq_num = 0;
struct workqueue_struct *irqworkqueue;
extern struct lock_class_key gpio_lock_class;
struct expand_gpio_soft_int expand_irq_data;
void expand_gpio_irq_ctr_dis(int irq,int ctrflag)
{
expand_gpio_irq_ctrflag=0;
if(expand_gpio_irq_en)
{
expand_gpio_irq_en=0;
disable_irq_nosync(irq);
DBG("***********%s %d***********\n",__FUNCTION__,__LINE__);
}
if(ctrflag)
{
expand_gpio_irq_ctrflag=-1;
}
}
void expand_gpio_irq_ctr_en(int irq)
{
if(!expand_gpio_irq_en)
{
DBG("***********%s %d***********\n",__FUNCTION__,__LINE__);
expand_gpio_irq_en = -1;
enable_irq(irq);
}
}
static int expand_checkrange(int start,int num,int val)
{
if((val<(start+num))&&(val>=start))
{
return 0;
}
else
{
return -1;
}
}
static void expand_gpio_irq_enable(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t expandpinnum;
if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
expandpinnum = irq - pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
return;
//DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_en[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->interrupt_en[gpioPortNum],gpioPortPinNum);
}
static void expand_gpio_irq_disable(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t expandpinnum;
if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
expandpinnum=irq - pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
return;
//DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_en[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->interrupt_en[gpioPortNum],gpioPortPinNum);
}
static void expand_gpio_irq_mask(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t expandpinnum;
if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
expandpinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
return;
//DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_mask[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->interrupt_mask[gpioPortNum],gpioPortPinNum);
}
static void expand_gpio_irq_unmask(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t expandpinnum;
if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
expandpinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
return;
//DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_mask[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->interrupt_mask[gpioPortNum],gpioPortPinNum);
}
static int expand_gpio_irq_type(unsigned int irq, unsigned int type)
{
struct irq_desc *desc_irq=irq_to_desc(irq);
struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)desc_irq->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t expandpinnum;
if(!expand_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
expandpinnum = irq - pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return -1;
}
gpioPortNum = expandpinnum/(pchip->expand_port_pinnum);
gpioPortPinNum= expandpinnum%(pchip->expand_port_pinnum);
if((gpioPortNum>=(pchip->expand_port_group))||(gpioPortPinNum>=(pchip->expand_port_pinnum)))
return -1;
DBG("**%s %d PortNum=%d,PortPinNum=%d**\n",__FUNCTION__,__LINE__,gpioPortNum,gpioPortPinNum);
switch (type) {
case IRQ_TYPE_NONE:
pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_NONE**\n",__FUNCTION__);
break;
case IRQ_TYPE_EDGE_RISING:
pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
pchip->inttype[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype[gpioPortNum],gpioPortPinNum);
pchip->inttype1[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype1[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
break;
case IRQ_TYPE_EDGE_FALLING:
pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
pchip->inttype[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype[gpioPortNum],gpioPortPinNum);
pchip->inttype1[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype1[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
break;
case IRQ_TYPE_EDGE_BOTH:
pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
pchip->inttype1[gpioPortNum]=EXTPAND_GPIO_SET_BIT(pchip->inttype1[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
break;
case IRQ_TYPE_LEVEL_HIGH:
pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
DBG("extern gpios does not support IRQ_TYPE_LEVEL_HIGH irq typ");
break;
case IRQ_TYPE_LEVEL_LOW:
pchip->inttype_set[gpioPortNum]=EXTPAND_GPIO_CLEAR_BIT(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
DBG("extern gpios does not support IRQ_TYPE_LEVEL_LOW irq typ");
break;
default:
return -EINVAL;
}
return 0;
}
static int expand_gpio_irq_set_wake(unsigned irq, unsigned state)
{
//no irq wake
return 0;
}
static struct irq_chip expand_gpio_irqchip = {
.name = "expand_gpio_expand ",
.enable = expand_gpio_irq_enable,
.disable = expand_gpio_irq_disable,
.mask = expand_gpio_irq_mask,
.unmask = expand_gpio_irq_unmask,
.set_type = expand_gpio_irq_type,
.set_wake = expand_gpio_irq_set_wake,
};
static irqreturn_t expand_gpio_irq_handler(int irq, void * dev_id)
{
struct irq_desc *gpio_irq_desc = irq_to_desc(irq);
struct expand_gpio_soft_int *pchip=(struct expand_gpio_soft_int *)gpio_irq_desc->chip_data;
u8 oldintputreg[MAX_SUPPORT_PORT_GROUP]={0,0,0,0,0};
u8 tempintputreg[MAX_SUPPORT_PORT_GROUP]={0,0,0,0,0};
u8 tempallowint=0;
u8 levelchg=0;
u8 intbit[MAX_SUPPORT_PORT_GROUP]={0,0,0,0,0};
u8 tempinttype=0;
u8 int_en_flag=0;
int i,j;
DBG("******************%s*******************\n",__FUNCTION__);
expand_gpio_irq_ctr_dis(pchip->irq_chain,0);
memcpy(&oldintputreg[0],&pchip->gvar->reg_input[0],pchip->expand_port_pinnum);
if(pchip->irq_data.read_allinputreg(pchip->irq_data.data,&tempintputreg[0]))
{
expand_gpio_irq_ctr_dis(pchip->irq_chain,-1);
DBG("**%s[%d] reading reg is error\n",__FUNCTION__,__LINE__);
queue_work(irqworkqueue,&pchip->irq_work);
return IRQ_HANDLED;
}
memcpy(&pchip->gvar->reg_input[0],&tempintputreg[0],pchip->expand_port_pinnum);
//DBG("**has run at %s**,input[0] = %x,input[1] = %x,input[2] = %x\n",__FUNCTION__,pchip->gvar.reg_input[0],pchip->gvar.reg_input[1],pchip->gvar.reg_input[2]);
//Handle for different expand_port_group
for(i=0,int_en_flag=0;i<MIN(pchip->expand_port_group,MAX_SUPPORT_PORT_GROUP);i++)
{
int_en_flag|=pchip->interrupt_en[i];
}
if(!int_en_flag)
{
if(expand_gpio_irq_num<0xFFFFFFFF)
{
expand_gpio_irq_num++;
}
else
{
expand_gpio_irq_num=0;
}
DBGERR("there are no pin reg irq\n");
expand_gpio_irq_ctr_en(pchip->irq_chain);
return IRQ_HANDLED;
}
for(i=0;i<pchip->expand_port_group;i++)
{
tempallowint=pchip->interrupt_en[i]&pchip->gvar->reg_direction[i]&(~pchip->interrupt_mask[i]);// 满足中断条件
levelchg=oldintputreg[i]^tempintputreg[i];// 找出前后状态不一样的pin
tempinttype=~(tempintputreg[i]^pchip->inttype[i]);// 找出触发状态和当前pin状态一样的pin注意只支持low high两种pin触发
tempinttype=(~pchip->inttype1[i])&tempinttype;// inttype1 为真的位对应的tempinttype位清零因为该位只受inttype1控制
tempinttype|=pchip->inttype1[i];//电平只要是变化就产生中断
tempinttype&=pchip->inttype_set[i];//已经设置了type类型
intbit[i]=tempallowint&levelchg&tempinttype;
//DBG(" tempallowint=%x,levelchg=%x,tempinttype=%x,intbit=%d\n",tempallowint,levelchg,tempinttype,intbit[i]);
}
if(expand_gpio_irq_num<0xFFFFFFFF)
{
expand_gpio_irq_num++;
}
else
{
expand_gpio_irq_num=0;
}
for(i=0;i<pchip->expand_port_group;i++)
{
if(intbit[i])
{
for(j=0;j<pchip->expand_port_pinnum;j++)
{
if(EXTPAND_GPIO_GET_BIT(intbit[i],j))
{
irq=pchip->gpio_irq_start+pchip->expand_port_pinnum*i+j;
gpio_irq_desc = irq_to_desc(irq);
gpio_irq_desc->chip->mask(irq);
generic_handle_irq(irq);
gpio_irq_desc->chip->unmask(irq);
//DBG("expand_i2c_irq_handler port=%d,pin=%d,pinlevel=%d\n",i,j,EXTPAND_GPIO_GET_BIT(tempintputreg[i],j));
}
}
}
}
expand_gpio_irq_ctr_en(pchip->irq_chain);
return IRQ_HANDLED;
}
static void irq_call_back_handler(struct work_struct *work)
{
struct expand_gpio_soft_int *pchip = container_of(work, struct expand_gpio_soft_int,irq_work);
//printk("irq_call_back_handle\n");
expand_gpio_irq_handler(pchip->irq_chain,NULL);
}
void expand_gpio_irq_setup(struct expand_gpio_soft_int *pchip)
{
unsigned int pioc, irq_num;
int ret;
struct irq_desc *desc;
irq_num = pchip->gpio_irq_start; //中断号扩展io的中断号应该紧跟在内部io中断号的后面。如rk内部中断48个加上内部gpio 16个虚拟中断这里pin应该从48+16开始
DBG("**%s**\n",__FUNCTION__);
for (pioc = 0; pioc < pchip->irq_pin_num; pioc++,irq_num++)
{
lockdep_set_class(&irq_desc[irq_num].lock, &gpio_lock_class);
/*
* Can use the "simple" and not "edge" handler since it's
* shorter, and the AIC handles interrupts sanely.
*/
set_irq_chip(irq_num, &expand_gpio_irqchip);
set_irq_handler(irq_num, handle_simple_irq);
set_irq_chip_data(irq_num,(void *)pchip);
desc = irq_to_desc(irq_num);
DBG("**%s line=%d,irq_num=%d**\n",__FUNCTION__,__LINE__,irq_num);
set_irq_flags(irq_num, IRQF_VALID);
}
ret = gpio_request(pchip->irq_gpiopin,NULL);
if(ret!=0)
{
gpio_free(pchip->irq_gpiopin);
DBG("expand_gpio_irq_setup request gpio is err\n");
}
gpio_pull_updown(pchip->irq_gpiopin, pchip->rk_irq_gpio_pull_up_down); //gpio 需要拉高irq_to_gpio(pchip->irq_chain)
irqworkqueue=create_rt_workqueue("irq workqueue");
INIT_WORK(&pchip->irq_work,irq_call_back_handler);
set_irq_chip_data(pchip->irq_chain, pchip);
if(request_irq(pchip->irq_chain,expand_gpio_irq_handler,pchip->rk_irq_mode, "expand", pchip)!=0)
{
DBG("**%s line=%d is err**\n",__FUNCTION__,__LINE__);
}
}
int wait_untill_input_reg_flash(void)
{
unsigned int num = 0;
unsigned int tempnum = expand_gpio_irq_num;
while(expand_gpio_irq_ctrflag&&(expand_gpio_irq_num==tempnum))
{
mdelay(1);
num++;
if(num>5)
return -1;
}
return 0;
}
void expand_irq_init(void *data,struct expand_gpio_global_variable *var,irq_read_inputreg handler)
{
expand_irq_data.irq_data.data = data;
expand_irq_data.irq_data.read_allinputreg = handler;
expand_irq_data.gvar = var;
expand_gpio_irq_setup(&expand_irq_data);
}

47
drivers/gpio/soft_interrupt.h Executable file
View File

@ -0,0 +1,47 @@
#ifndef _SOFT_INTERRUPT_H
#define _SOFT_INTERRUPT_H
#define MAX_SUPPORT_PORT_GROUP 5
typedef int (*irq_read_inputreg)(void *,char *);
struct expand_gpio_irq_data
{
void *data;
irq_read_inputreg read_allinputreg;
};
struct expand_gpio_global_variable
{
uint8_t reg_input[MAX_SUPPORT_PORT_GROUP];
uint8_t reg_output[MAX_SUPPORT_PORT_GROUP];
uint8_t reg_direction[MAX_SUPPORT_PORT_GROUP];
};
struct expand_gpio_soft_int
{
unsigned int gpio_irq_start;
unsigned int irq_pin_num; //中断的个数
unsigned int irq_gpiopin; //父中断的中断 脚
unsigned int irq_chain; //父中断的中断号
unsigned int expand_port_group;
unsigned int expand_port_pinnum;
unsigned int rk_irq_mode;
unsigned int rk_irq_gpio_pull_up_down;
uint8_t interrupt_en[MAX_SUPPORT_PORT_GROUP]; // 0 dis
uint8_t interrupt_mask[MAX_SUPPORT_PORT_GROUP]; // 0 unmask
uint8_t inttype_set[MAX_SUPPORT_PORT_GROUP]; // Inttype enable
uint8_t inttype[MAX_SUPPORT_PORT_GROUP];
uint8_t inttype1[MAX_SUPPORT_PORT_GROUP];
struct expand_gpio_irq_data irq_data;
struct work_struct irq_work;
struct expand_gpio_global_variable *gvar;
};
extern struct expand_gpio_soft_int expand_irq_data;
extern int wait_untill_input_reg_flash(void);
extern void expand_irq_init(void *data,struct expand_gpio_global_variable *var,irq_read_inputreg handler);
#endif

View File

@ -11,13 +11,14 @@
* GNU General Public License for more details.
*/
/*******************************************************************/
/* COPYRIGHT (C) ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED. */
/* COPYRIGHT (C) ROCK-CHIPS FUZHOU . ALL RIGHTS RESERVED.*/
/*******************************************************************
FILE : tca6424.c
MODIFY : sxj
DATE : 2010-8-11
NOTES :
********************************************************************/
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@ -41,6 +42,8 @@ NOTES :
#include <mach/board.h>
#include <linux/delay.h>
#include <linux/i2c/tca6424.h>
#include <linux/ktime.h>
#include "../drivers/gpio/soft_interrupt.h"
#if 0
#define TCA6424DEB
@ -49,30 +52,17 @@ NOTES :
#define DBG(x...)
#endif
#if 1
#if 0
#define DBGERR(x...) printk(KERN_INFO x)
#else
#define DBGERR(x...)
#endif
struct tca6424_chip {
/* the first extern gpio number in all of gpio groups */
unsigned gpio_start;
unsigned gpio_pin_num;
/* the first gpio irq number in all of irq source */
unsigned gpio_irq_start;
unsigned irq_pin_num; //中断的个数
unsigned irq_gpiopin; //父中断的中断号
unsigned irq_chain; //父中断的中断号
uint8_t reg_input[TCA6424_PortNum];
uint8_t reg_output[TCA6424_PortNum];
uint8_t reg_direction[TCA6424_PortNum];
uint8_t interrupt_en[TCA6424_PortNum]; // 0 dis
uint8_t interrupt_mask[TCA6424_PortNum];// 0 unmask
uint8_t inttype_set[TCA6424_PortNum]; // Inttype enable
uint8_t inttype[TCA6424_PortNum];
uint8_t inttype1[TCA6424_PortNum];
unsigned int gpio_start;
unsigned int gpio_pin_num;
#ifdef TCA6424_OUTREGLOCK
struct mutex outreglock;
#endif
@ -82,10 +72,10 @@ struct tca6424_chip {
#ifdef TCA6424_CONFIGREGLOCK
struct mutex configreglock;
#endif
struct i2c_client *client;
//struct extgpio_data_s *p;
struct tca6424_platform_data *dyn_pdata;
struct work_struct tca6424_work;
struct expand_gpio_soft_int *expand;
struct expand_gpio_global_variable gtca6424_struct;
struct gpio_chip gpio_chip;
char **names;
};
@ -99,14 +89,17 @@ MODULE_DEVICE_TABLE(i2c, tca6424_id);
static short int portnum[TCA6424_PortNum]={ TCA6424_Port0PinNum,
TCA6424_Port1PinNum,TCA6424_Port2PinNum};
typedef struct _tca6424_access_{
u8 portreg[TCA6424_PortNum];
u8 accessflag[TCA6424_PortNum];//0 不进行操作
} tca6424_access;
extern inline struct gpio_chip *gpio_to_chip(unsigned gpio);
extern struct lock_class_key gpio_lock_class;
struct workqueue_struct *tca6424workqueue;
int tca6424_irq_read_inputreg(void *data,char *buf)
{
struct tca6424_chip *tca6424data=(struct tca6424_chip *)data;
int ret = -1;
ret = i2c_master_reg8_recv(tca6424data->client, TCA6424_Auto_InputLevel_Reg, buf, 3, TCA6424_I2C_RATE);
return (ret>0)?0:ret;
}
static int tca6424_write_reg(struct i2c_client *client, uint8_t reg, uint8_t val)
{
@ -125,7 +118,6 @@ static int tca6424_write_reg(struct i2c_client *client, uint8_t reg, uint8_t val
msg.len = 1 +1;
msg.flags = client->flags;
msg.scl_rate = TCA6424_I2C_RATE;
ret = i2c_transfer(adap, &msg, 1);
return ret;
}
@ -157,6 +149,20 @@ static int tca6424_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *val
}
static int tca6424_write_three_reg(struct i2c_client *client, const char reg, const char *buf, int count, int rate)
{
int ret = -1;
ret = i2c_master_reg8_send(client, reg, buf, count, rate);
return (ret>0)?0:ret;
}
static int tca6424_read_three_reg(struct i2c_client *client, const char reg, char *buf, int count, int rate)
{
int ret = -1;
ret = i2c_master_reg8_recv(client, reg, buf, count, rate);
return (ret>0)?0:ret;
}
static int tca6424_gpio_direction_input(struct gpio_chip *gc, uint8_t pin_num)
{
struct tca6424_chip *chip;
@ -172,29 +178,28 @@ static int tca6424_gpio_direction_input(struct gpio_chip *gc, uint8_t pin_num)
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return ret;
Regaddr = TCA6424_Config_Reg+gpioPortNum;
#ifdef TCA6424_CONFIGREGLOCK
if (!mutex_trylock(&chip->configreglock))
{
DBGERR("**%s[%d]Did not get the configreglock**\n",__FUNCTION__,__LINE__);
return ret;
return -1;
}
#endif
reg_val = tca6424setbit(chip->reg_direction[gpioPortNum], gpioPortPinNum);
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if(ret<0)
goto err;
chip->reg_direction[gpioPortNum] = reg_val;
if(((chip->gtca6424_struct.reg_direction[gpioPortNum]>>gpioPortPinNum)& 0x01)==EXTGPIO_OUTPUT)
{
reg_val = tca6424setbit(chip->gtca6424_struct.reg_direction[gpioPortNum], gpioPortPinNum);
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if(ret<0)
goto err;
chip->gtca6424_struct.reg_direction[gpioPortNum] = reg_val;
//DBG("**%s[%d],set config address[0x%2x]=%2x,ret=%d**\n",__FUNCTION__,__LINE__,Regaddr,reg_val,ret);
}
err:
DBG("**%s[%d],config_reg=%2x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
#ifdef TCA6424_CONFIGREGLOCK
mutex_unlock(&chip->configreglock);
mutex_unlock(&chip->configreglock);
#endif
return (ret<0)?-1:0;
}
@ -203,8 +208,8 @@ static int tca6424_gpio_direction_output(struct gpio_chip *gc,uint8_t pin_num, i
struct tca6424_chip *chip;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t reg_val;
uint8_t Regaddr;
uint8_t reg_val = 0;
uint8_t Regaddr = 0;
int ret = -1;
chip = container_of(gc, struct tca6424_chip, gpio_chip);
@ -213,7 +218,7 @@ static int tca6424_gpio_direction_output(struct gpio_chip *gc,uint8_t pin_num, i
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return ret;
Regaddr = TCA6424_Config_Reg+gpioPortNum;
#ifdef TCA6424_CONFIGREGLOCK
if (!mutex_trylock(&chip->configreglock))
{
@ -221,23 +226,28 @@ static int tca6424_gpio_direction_output(struct gpio_chip *gc,uint8_t pin_num, i
return -1;
}
#endif
/* then direction */
reg_val = tca6424clearbit(chip->reg_direction[gpioPortNum], gpioPortPinNum);
DBG("**%s[%d],reg_val=%2x, Regaddr=%2x,**\n",__FUNCTION__,__LINE__,reg_val,Regaddr);
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if(ret<0)
if(((chip->gtca6424_struct.reg_direction[gpioPortNum]>>gpioPortPinNum)& 0x01)==EXTGPIO_INPUT)
{
#ifdef TCA6424_CONFIGREGLOCK
mutex_unlock(&chip->configreglock);
#endif
DBGERR("**%s[%d] set direction reg is error,reg_val=%x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
reg_val = tca6424clearbit(chip->gtca6424_struct.reg_direction[gpioPortNum], gpioPortPinNum);
//DBG("**%s[%d],set config address[0x%2x]=%2x,**\n",__FUNCTION__,__LINE__,Regaddr,reg_val);
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if(ret<0)
{
#ifdef TCA6424_CONFIGREGLOCK
mutex_unlock(&chip->configreglock);
#endif
DBGERR("**%s[%d] set direction reg is error,reg_val=%x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
return ret;
}
chip->gtca6424_struct.reg_direction[gpioPortNum] = reg_val;
}
chip->reg_direction[gpioPortNum] = reg_val;
#ifdef TCA6424_CONFIGREGLOCK
mutex_unlock(&chip->configreglock);
#endif
ret=-1;
ret = -1;
#ifdef TCA6424_OUTREGLOCK
if (!mutex_trylock(&chip->outreglock))
{
@ -245,29 +255,31 @@ static int tca6424_gpio_direction_output(struct gpio_chip *gc,uint8_t pin_num, i
return ret;
}
#endif
/* set output level */
if (val)
reg_val = tca6424setbit(chip->reg_output[gpioPortNum], gpioPortPinNum);
else
reg_val = tca6424clearbit(chip->reg_output[gpioPortNum], gpioPortPinNum);
Regaddr = TCA6424_OutputLevel_Reg+gpioPortNum;
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if (ret<0)
if(((chip->gtca6424_struct.reg_output[gpioPortNum]>>gpioPortPinNum)& 0x01) != val)
{
#ifdef TCA6424_OUTREGLOCK
mutex_unlock(&chip->outreglock);
#endif
DBGERR("**%s[%d] set out reg is error,reg_val=%x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
return ret;
if (val)
reg_val = tca6424setbit(chip->gtca6424_struct.reg_output[gpioPortNum], gpioPortPinNum);
else
reg_val = tca6424clearbit(chip->gtca6424_struct.reg_output[gpioPortNum], gpioPortPinNum);
Regaddr = TCA6424_OutputLevel_Reg+gpioPortNum;
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if (ret<0)
{
#ifdef TCA6424_OUTREGLOCK
mutex_unlock(&chip->outreglock);
#endif
DBGERR("**%s[%d] set out reg is error,reg_val=%x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
return ret;
}
chip->gtca6424_struct.reg_output[gpioPortNum] = reg_val;
}
chip->reg_output[gpioPortNum] = reg_val;
#ifdef TCA6424_OUTREGLOCK
mutex_unlock(&chip->outreglock);
#endif
DBG("**%s[%d],output_reg=%2x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
//DBG("**%s[%d],set output address[0x%2x]=%2x,ret=%d**\n",__FUNCTION__,__LINE__,Regaddr,reg_val,ret);
return (ret<0)?-1:0;
}
@ -276,44 +288,34 @@ static int tca6424_gpio_get_value(struct gpio_chip *gc, uint8_t pin_num)
struct tca6424_chip *chip;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t reg_val;
uint8_t Regaddr;
int ret=-1;
int ret;
chip = container_of(gc, struct tca6424_chip, gpio_chip);
#ifdef CONFIG_SOFT_INTERRUPT
ret = wait_untill_input_reg_flash( );
if(ret<0)
return -1;
#endif
gpioPortNum = pin_num/8;
gpioPortPinNum= pin_num%8;
Regaddr = TCA6424_OutputLevel_Reg+gpioPortNum;
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return -1;
Regaddr = TCA6424_InputLevel_Reg+gpioPortNum;
if(!tca6424getbit(chip->reg_direction[gpioPortNum],gpioPortPinNum)) //判断该pin是否设置成输出
{
DBG("**it is a output pin**\n");
return -1;
}
#ifdef TCA6424_INPUTREGLOCK
if (!mutex_trylock(&chip->inputreglock))
{
DBGERR("**%s[%d]Did not get the inputreglock**\n",__FUNCTION__,__LINE__);
return -1;
}
#endif
#ifndef CONFIG_SOFT_INTERRUPT
uint8_t reg_val;
ret = tca6424_read_reg(chip->client, Regaddr, &reg_val);
if (ret < 0)
goto err;
chip->reg_input[gpioPortNum] = reg_val;
err:
#ifdef TCA6424_CONFIGREGLOCK
mutex_unlock(&chip->inputreglock);
return -1;
chip->gtca6424_struct.reg_input[gpioPortNum] = reg_val;
#endif
DBGERR("**%s[%d] input_reg=%2x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
return (ret < 0)?-1:((chip->reg_input[gpioPortNum] >> gpioPortPinNum) & 0x01);
//DBG("**%s[%d] read input address[0x%2x]=%2x**\n",__FUNCTION__,__LINE__,Regaddr,chip->reg_input[gpioPortNum]);
return ((chip->gtca6424_struct.reg_input[gpioPortNum] >> gpioPortPinNum) & 0x01);
}
static void tca6424_gpio_set_value(struct gpio_chip *gc, uint8_t pin_num, int val)
@ -324,365 +326,78 @@ static void tca6424_gpio_set_value(struct gpio_chip *gc, uint8_t pin_num, int va
uint8_t reg_val;
uint8_t Regaddr;
int ret=-1;
DBG("**run in the %s**\n",__FUNCTION__);
chip = container_of(gc, struct tca6424_chip, gpio_chip);
gpioPortNum = pin_num/8;
gpioPortPinNum= pin_num%8;
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return;// -1;
return;
Regaddr = TCA6424_OutputLevel_Reg+gpioPortNum;
if(tca6424getbit(chip->reg_direction[gpioPortNum],gpioPortPinNum)) // input state
return;// -1;
#ifdef TCA6424_OUTREGLOCK
if(tca6424getbit(chip->gtca6424_struct.reg_direction[gpioPortNum],gpioPortPinNum)) // input state
{
return;
}
#ifdef TCA6424_OUTREGLOCK
if (!mutex_trylock(&chip->outreglock))
{
DBGERR("**%s[%d] Did not get the outreglock**\n",__FUNCTION__,__LINE__);
return;// -1;
return;
}
#endif
if (val)
reg_val = tca6424setbit(chip->reg_output[gpioPortNum], gpioPortPinNum);
else
reg_val = tca6424clearbit(chip->reg_output[gpioPortNum], gpioPortPinNum);
#endif
if(((chip->gtca6424_struct.reg_output[gpioPortNum]>>gpioPortPinNum)& 0x01) != val)
{
if(val)
reg_val = tca6424setbit(chip->gtca6424_struct.reg_output[gpioPortNum], gpioPortPinNum);
else
reg_val = tca6424clearbit(chip->gtca6424_struct.reg_output[gpioPortNum], gpioPortPinNum);
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if (ret<0)
goto err;
chip->reg_output[gpioPortNum] = reg_val;
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
if (ret<0)
goto err;
chip->gtca6424_struct.reg_output[gpioPortNum] = reg_val;
//DBG("**%s[%d],set output address[0x%2x]=%2x,ret=%d**\n",__FUNCTION__,__LINE__,Regaddr,reg_val,ret);
}
err:
#ifdef TCA6424_OUTREGLOCK
mutex_unlock(&chip->outreglock);
#endif
DBG("**%s[%d],output_reg=%2x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
return;// (ret<0)?-1:0;
}
static int tca6424_gpio_to_irq(struct gpio_chip *chip,unsigned offset)
{
struct tca6424_chip *pca_chip = container_of(chip, struct tca6424_chip, gpio_chip);
if(((pca_chip->gpio_start+offset)>=chip->base)&&((pca_chip->gpio_start+offset)<(chip->base+chip->ngpio)))
{
//DBG("**%s,offset=%d,gpio_irq_start=%d,base=%d,ngpio=%d,gpio_irq_start=%d**\n",
// __FUNCTION__,offset,pca_chip->gpio_irq_start,chip->base,chip->ngpio,pca_chip->gpio_irq_start);
return (offset+pca_chip->gpio_irq_start);
}
else
{
return -1;
}
}
int tca6424_checkrange(int start,int num,int val)
{
if((val<(start+num))&&(val>=start))
return 0;
else return -1;
}
static void tca6424_gpio_irq_enable(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
//int gpiopinnum;
struct tca6424_chip *pchip=(struct tca6424_chip *)desc->chip_data;
//struct gpio_chip *chip_gpio;
uint8_t gpio_num;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t tca6424pinnum;
if(!tca6424_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
tca6424pinnum = irq-pchip->gpio_irq_start;
}
else
{
return;
}
gpioPortNum = tca6424pinnum/8;
gpioPortPinNum= tca6424pinnum%8;
gpio_num=pchip->gpio_start+tca6424pinnum;
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return;
DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_en[gpioPortNum]=tca6424setbit(pchip->interrupt_en[gpioPortNum],gpioPortPinNum);
}
static void tca6424_gpio_irq_disable(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct tca6424_chip *pchip=(struct tca6424_chip *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t tca6424pinnum;
if(!tca6424_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
tca6424pinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = tca6424pinnum/8;
gpioPortPinNum= tca6424pinnum%8;
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return;
DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_en[gpioPortNum]=tca6424clearbit(pchip->interrupt_en[gpioPortNum],gpioPortPinNum);
}
static void tca6424_gpio_irq_mask(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct tca6424_chip *pchip=(struct tca6424_chip *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t tca6424pinnum;
if(!tca6424_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
tca6424pinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = tca6424pinnum/8;
gpioPortPinNum= tca6424pinnum%8;
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return;
DBG("**%s**\n",__FUNCTION__);
pchip->interrupt_mask[gpioPortNum]=tca6424setbit(pchip->interrupt_mask[gpioPortNum],gpioPortPinNum);
}
static void tca6424_gpio_irq_unmask(unsigned irq)
{
struct irq_desc *desc = irq_to_desc(irq);
//int gpiopinnum;//=irq_to_gpio(irq);
struct tca6424_chip *pchip=(struct tca6424_chip *)desc->chip_data;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t tca6424pinnum;
DBG("**%s**\n",__FUNCTION__);
if(!tca6424_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
tca6424pinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
}
else
{
return;
}
gpioPortNum = tca6424pinnum/8;
gpioPortPinNum= tca6424pinnum%8;
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
return;
pchip->interrupt_mask[gpioPortNum]=tca6424clearbit(pchip->interrupt_mask[gpioPortNum],gpioPortPinNum);
}
static int tca6424_gpio_irq_type(unsigned int irq, unsigned int type)
{
struct irq_desc *desc_irq=irq_to_desc(irq);
struct tca6424_chip *pchip=(struct tca6424_chip *)desc_irq->chip_data;
//struct gpio_chip *chip_gpio;
int gpio_num;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum;
uint8_t tca6424pinnum;
if(!tca6424_checkrange(pchip->gpio_irq_start,pchip->irq_pin_num,irq))
{
tca6424pinnum=irq-pchip->gpio_irq_start;//irq_to_gpio(irq)
gpio_num=pchip->gpio_start+tca6424pinnum;
}
else
return -1;
gpioPortNum = tca6424pinnum/8;
gpioPortPinNum= tca6424pinnum%8;
//DBG("**%s %d gpio_num=%d,PortNum=%d,PortPinNum=%d**\n",__FUNCTION__,__LINE__,gpio_num,gpioPortNum,gpioPortPinNum);
switch (type) {
case IRQ_TYPE_NONE:
pchip->inttype_set[gpioPortNum]=tca6424clearbit(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_NONE**\n",__FUNCTION__);
break;
case IRQ_TYPE_EDGE_RISING:
pchip->inttype_set[gpioPortNum]=tca6424setbit(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
pchip->inttype[gpioPortNum]=tca6424setbit(pchip->inttype[gpioPortNum],gpioPortPinNum);
pchip->inttype1[gpioPortNum]=tca6424clearbit(pchip->inttype1[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
break;
case IRQ_TYPE_EDGE_FALLING:
pchip->inttype_set[gpioPortNum]=tca6424setbit(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
pchip->inttype[gpioPortNum]=tca6424clearbit(pchip->inttype[gpioPortNum],gpioPortPinNum);
pchip->inttype1[gpioPortNum]=tca6424clearbit(pchip->inttype1[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
break;
case IRQ_TYPE_EDGE_BOTH:
pchip->inttype_set[gpioPortNum]=tca6424setbit(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
pchip->inttype1[gpioPortNum]=tca6424setbit(pchip->inttype1[gpioPortNum],gpioPortPinNum);
DBG("**%s IRQ_TYPE_EDGE_RISING,inttype=%x,inttype1=%x**\n",__FUNCTION__,pchip->inttype[gpioPortNum],pchip->inttype1[gpioPortNum]);
break;
case IRQ_TYPE_LEVEL_HIGH:
pchip->inttype_set[gpioPortNum]=tca6424clearbit(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
DBG("extern gpios does not support IRQ_TYPE_LEVEL_HIGH irq typ");
break;
case IRQ_TYPE_LEVEL_LOW:
pchip->inttype_set[gpioPortNum]=tca6424clearbit(pchip->inttype_set[gpioPortNum],gpioPortPinNum);
DBG("extern gpios does not support IRQ_TYPE_LEVEL_LOW irq typ");
break;
default:
return -EINVAL;
}
return 0;
}
static int tca6424_gpio_irq_set_wake(unsigned irq, unsigned state)
{
//no irq wake
return 0;
}
static struct irq_chip tca6424_gpio_irqchip = {
.name = "extend_gpio_tca6424",
.enable = tca6424_gpio_irq_enable,
.disable = tca6424_gpio_irq_disable,
.mask = tca6424_gpio_irq_mask,
.unmask = tca6424_gpio_irq_unmask,
.set_type = tca6424_gpio_irq_type,
.set_wake = tca6424_gpio_irq_set_wake,
};
static void tca6424_extend_gpio_irq_handler(struct work_struct *work)
{
struct tca6424_chip *pchip = container_of(work, struct tca6424_chip,tca6424_work);
u8 tempintputreg[TCA6424_PortNum]={0,0,0};
u8 tempallowint=0;
u8 levelchg=0;
u8 intbit=0;
u8 tempinttype=0;
int i,j;
struct irq_desc *gpio_irq_desc;
unsigned int irq;
if(tca6424_read_reg(pchip->client,TCA6424_InputLevel_Reg,&tempintputreg[0])<0)
{
DBG("**%s[%d] reading reg is error\n",__FUNCTION__,__LINE__);
enable_irq(pchip->irq_chain);
return;
}
if(tca6424_read_reg(pchip->client,(TCA6424_InputLevel_Reg+1),&tempintputreg[1])<0)
{
DBG("**%s[%d] reading reg is error\n",__FUNCTION__,__LINE__);
enable_irq(pchip->irq_chain);
return;
}
if(tca6424_read_reg(pchip->client,(TCA6424_InputLevel_Reg+2),&tempintputreg[2])<0)
{
DBG("**%s[%d] reading reg is error\n",__FUNCTION__,__LINE__);
enable_irq(pchip->irq_chain);
return;
}
DBG("**has run at %s**,tempintreg[0] = %x,tempintreg[1] = %x,tempintreg[2] = %x\n",__FUNCTION__,tempintputreg[0],tempintputreg[1],tempintputreg[2]);
if((pchip->interrupt_en[0]==0)&&(pchip->interrupt_en[1]==0)&&(pchip->interrupt_en[2]==0))
{
memcpy(&pchip->reg_input[0],&tempintputreg[0],sizeof(tempintputreg));
DBGERR("there are no pin reg irq\n");
enable_irq(pchip->irq_chain);
return;
}
for(i=0;i<TCA6424_PortNum;i++)
{
tempallowint=pchip->interrupt_en[i]&pchip->reg_direction[i]&(~pchip->interrupt_mask[i]);// 满足中断条件
levelchg=pchip->reg_input[i]^tempintputreg[i];// 找出前后状态不一样的pin
tempinttype=~(tempintputreg[i]^pchip->inttype[i]);// 找出触发状态和当前pin状态一样的pin注意只支持low high两种pin触发
tempinttype=(~pchip->inttype1[i])&tempinttype;// inttype1 为真的位对应的tempinttype位清零因为该位只受inttype1控制
tempinttype|=pchip->inttype1[i];//电平只要是变化就产生中断
tempinttype&=pchip->inttype_set[i];//已经设置了type类型
intbit=tempallowint&levelchg&tempinttype;
DBG(" tempallowint=%x,levelchg=%x,tempinttype=%x,intbit=%d\n",tempallowint,levelchg,tempinttype,intbit);
if(intbit)
for(j=0;j<portnum[i];j++)
{
if(tca6424getbit(intbit,j))
{
irq=pchip->gpio_irq_start+TCA6424_PortPinNum*i+j;
gpio_irq_desc = irq_to_desc(irq);
gpio_irq_desc->chip->mask(irq);
generic_handle_irq(irq);
gpio_irq_desc->chip->unmask(irq);
DBG("tca6424_i2c_irq_handler port=%d,pin=%d,pinlevel=%d\n",i,j,tca6424getbit(tempintputreg[i],j));
}
}
pchip->reg_input[i]=tempintputreg[i];
}
enable_irq(pchip->irq_chain);
return;
}
static irqreturn_t tca6424_gpio_irq_handler(int irq, void * dev_id)
{
struct irq_desc *gpio_irq_desc = irq_to_desc(irq);
struct tca6424_chip *pchip=(struct tca6424_chip *)gpio_irq_desc->chip_data;
DBG("******************%s*******************\n",__FUNCTION__);
disable_irq_nosync(pchip->irq_chain);
queue_work(tca6424workqueue,&pchip->tca6424_work);
return IRQ_HANDLED;
int tca6424_checkrange(int start,int num,int val)
{
if((val<(start+num))&&(val>=start))
return 0;
else
return -1;
}
static irqreturn_t test_handler(int irq, void * dev_id)
static int tca6424_gpio_to_irq(struct gpio_chip *chip,unsigned offset)
{
DBG("******************%s*******************\n",__FUNCTION__);
return IRQ_HANDLED;
struct tca6424_chip *pchip = container_of(chip, struct tca6424_chip, gpio_chip);
if(((pchip->gpio_start+offset)>=chip->base)&&((pchip->gpio_start+offset)<(chip->base+chip->ngpio)))
{
//DBG("**%s,offset=%d,gpio_irq_start=%d,base=%d,ngpio=%d,gpio_irq_start=%d**\n",
// __FUNCTION__,offset,pchip->expand->gpio_irq_start,chip->base,chip->ngpio,pchip->expand->gpio_irq_start);
return (offset+pchip->expand->gpio_irq_start);
}
else
{
return -1;
}
}
static void tca6424_setup_gpio(struct tca6424_chip *chip, int gpios)
{
struct gpio_chip *gc;
gc = &chip->gpio_chip;
gc->direction_input = tca6424_gpio_direction_input;
gc->direction_output = tca6424_gpio_direction_output;
gc->get = tca6424_gpio_get_value;
gc->set = tca6424_gpio_set_value;
gc->to_irq = tca6424_gpio_to_irq;
gc->can_sleep = 1;
gc->base = chip->gpio_start;
gc->ngpio = chip->gpio_pin_num;
gc->label = chip->client->name;
@ -691,69 +406,17 @@ static void tca6424_setup_gpio(struct tca6424_chip *chip, int gpios)
gc->names = chip->names;
}
static void tca6424_gpio_irq_setup(struct tca6424_chip *pchip)
{
unsigned pioc, irq_num;
int ret;
int testprint1 = 0;
int testprint2 = 0;
struct irq_desc *desc;
irq_num = pchip->gpio_irq_start; //中断号扩展io的中断号应该紧跟在内部io中断号的后面。如rk内部中断48个加上内部gpio 16个虚拟中断这里pin应该从48+16开始
for (pioc = 0; pioc < pchip->irq_pin_num; pioc++,irq_num++)
{
lockdep_set_class(&irq_desc[irq_num].lock, &gpio_lock_class);
/*
* Can use the "simple" and not "edge" handler since it's
* shorter, and the AIC handles interrupts sanely.
*/
testprint1 = set_irq_chip(irq_num, &tca6424_gpio_irqchip);
set_irq_handler(irq_num, handle_simple_irq);
testprint2 = set_irq_chip_data(irq_num,(void *)pchip);
desc = irq_to_desc(irq_num);
DBG("**%s line=%d,test1=%d,test2=%d,desc=%x,chipdate=%x,pchip=%x,irq_num=%d**\n",__FUNCTION__,__LINE__,testprint1,testprint2,desc,desc->chip_data,pchip,irq_num);
set_irq_flags(irq_num, IRQF_VALID);
}
ret = gpio_request(pchip->irq_gpiopin,NULL);
if(ret!=0)
{
gpio_free(pchip->irq_gpiopin);
DBG("tca6424_gpio_irq_setup request gpio is err\n");
}
gpio_pull_updown(pchip->irq_gpiopin, GPIOPullUp); //gpio 需要拉高irq_to_gpio(pchip->irq_chain)
#if 0
set_irq_chip_data(pchip->irq_chain, pchip);
set_irq_chained_handler(pchip->irq_chain, gpio_irq_handlerxxx);
set_irq_type(pchip->irq_chain,IRQ_TYPE_LEVEL_LOW);
enable_irq(pchip->irq_chain);
#else
tca6424workqueue=create_workqueue("tca6424 workqueue");
INIT_WORK(&pchip->tca6424_work,tca6424_extend_gpio_irq_handler);
set_irq_chip_data(pchip->irq_chain, pchip);
if(request_irq(pchip->irq_chain,tca6424_gpio_irq_handler, IRQF_TRIGGER_LOW, "tca6424", pchip)!=0)
{
DBG("**%s line=%d is err**\n",__FUNCTION__,__LINE__);
}
#endif
}
int tca6424_init_pintype(struct tca6424_chip *chip,struct i2c_client *client)
{
int i;
struct tca6424_platform_data *platform_data=(struct tca6424_platform_data *)client->dev.platform_data;
struct rk2818_gpio_expander_info *tca6424_gpio_settinginfo;
uint8_t reg_output[TCA6424_PortNum]={0,0,0};
uint8_t reg_direction[TCA6424_PortNum]={0,0,0};
uint8_t reg_invert[TCA6424_PortNum]={0,0,0};
uint8_t tca6424_pin_num;
uint8_t gpioPortNum;
uint8_t gpioPortPinNum,tca6424_settingpin_num=0;
int i = 0;
if(platform_data)
{
tca6424_gpio_settinginfo=platform_data->settinginfo;
@ -776,15 +439,10 @@ int tca6424_init_pintype(struct tca6424_chip *chip,struct i2c_client *client)
}
else
{
reg_direction[gpioPortNum]=tca6424clearbit(reg_direction[gpioPortNum],gpioPortPinNum);
if(tca6424_gpio_settinginfo[i].pin_value==GPIO_HIGH)
{
reg_output[gpioPortNum]=tca6424setbit(reg_output[gpioPortNum],gpioPortPinNum);
}
else
{
reg_output[gpioPortNum]=tca6424clearbit(reg_output[gpioPortNum],gpioPortPinNum);
}
}
}
@ -801,37 +459,32 @@ int tca6424_init_pintype(struct tca6424_chip *chip,struct i2c_client *client)
mutex_init(&chip->configreglock);
#endif
if(tca6424_write_three_reg(client, TCA6424_Auto_Config_Reg , &reg_direction[0], 3, TCA6424_I2C_RATE)<0)
{
DBGERR("*%s %d* write reg err\n",__FUNCTION__,__LINE__);
return -1;
}
if (tca6424_write_three_reg(client, TCA6424_Auto_OutputLevel_Reg, &reg_output[0], 3, TCA6424_I2C_RATE)<0)
{
DBGERR("*%s %d* write reg err\n",__FUNCTION__,__LINE__);
return -1;
}
if (tca6424_write_three_reg(client, TCA6424_Auto_Invert_Reg, &reg_invert[0], 3, TCA6424_I2C_RATE)<0) //make sure this reg be 0
{
DBGERR("*%s %d* write reg err\n",__FUNCTION__,__LINE__);
return -1;
}
if(tca6424_read_three_reg(client, TCA6424_Auto_InputLevel_Reg, &chip->gtca6424_struct.reg_input[0], 3, TCA6424_I2C_RATE)<0)
{
DBGERR("*%s %d read reg err*\n",__FUNCTION__,__LINE__);
return -1;
}
for(i=0; i<TCA6424_PortNum; i++)
{
if (tca6424_write_reg(client, (TCA6424_Config_Reg+i), reg_direction[i])<0)
{
DBGERR("*%s %d* write reg err\n",__FUNCTION__,__LINE__);
return -1;
}
chip->reg_direction[i]=reg_direction[i];
if (tca6424_write_reg(client, (TCA6424_OutputLevel_Reg+i), reg_output[i])<0)
{
DBGERR("*%s %d write reg err*\n",__FUNCTION__,__LINE__);
return -1;
}
chip->reg_output[i]=reg_output[i];
if (tca6424_write_reg(client, (TCA6424_Invert_Reg+i), 0)<0) //make sure this reg be 0
{
DBGERR("*%s %d* write reg err\n",__FUNCTION__,__LINE__);
return -1;
}
if(tca6424_read_reg(client, (TCA6424_InputLevel_Reg+i), &chip->reg_input[i])<0)
{
DBGERR("*%s %d read reg err*\n",__FUNCTION__,__LINE__);
return -1;
}
//DBG("reg_direction=%x,reg_output=%x,reg_input=%x\n",chip->reg_direction[i],chip->reg_output[i],chip->reg_input[i]);
chip->gtca6424_struct.reg_direction[i]=reg_direction[i];
chip->gtca6424_struct.reg_output[i]=reg_output[i];
DBG("reg_direction=%x,reg_output=%x,reg_input=%x\n",chip->gtca6424_struct.reg_direction[i],chip->gtca6424_struct.reg_output[i],chip->gtca6424_struct.reg_input[i]);
}
return 0;
}
@ -840,8 +493,6 @@ static int __devinit tca6424_probe(struct i2c_client *client,const struct i2c_de
struct tca6424_chip *chip;
struct tca6424_platform_data *pdata;
int ret;
uint8_t val;
DBG(KERN_ALERT"*******gpio %s in %d line,dev adr is %x**\n",__FUNCTION__,__LINE__,client->addr);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -EIO;
@ -855,46 +506,48 @@ static int __devinit tca6424_probe(struct i2c_client *client,const struct i2c_de
ret = -EINVAL;
goto out_failed;
}
//used by old tca6424,it will remove later
client->adapter->dev.platform_data = pdata;
chip->gpio_start = pdata->gpio_base;
chip->gpio_irq_start =pdata->gpio_irq_start;
chip->gpio_pin_num=pdata->gpio_pin_num;
chip->irq_pin_num = pdata->irq_pin_num;
chip->irq_gpiopin=pdata->tca6424_irq_pin;
chip->irq_chain = gpio_to_irq(pdata->tca6424_irq_pin);
chip->names =pdata->names;
//DBG("**%s in %d start=%d,irq_start=%d,pin_num=%d,irq_pin_num=%d,irq_gpiopin=%d,irq_chain=%d,**\n",
// __FUNCTION__,__LINE__,chip->gpio_start,chip->gpio_irq_start,chip->gpio_pin_num,chip->irq_pin_num,chip->irq_gpiopin
// ,chip->irq_chain);
chip->names = pdata->names;
#ifdef CONFIG_SOFT_INTERRUPT
chip->expand = &expand_irq_data;
chip->expand->gpio_irq_start =pdata->gpio_irq_start;
chip->expand->irq_pin_num = pdata->irq_pin_num;
chip->expand->irq_gpiopin=pdata->tca6424_irq_pin;
chip->expand->irq_chain = gpio_to_irq(pdata->tca6424_irq_pin);
chip->expand->expand_port_group = pdata->expand_port_group;
chip->expand->expand_port_pinnum = pdata->expand_port_pinnum;
chip->expand->rk_irq_mode = pdata->rk_irq_mode;
chip->expand->rk_irq_gpio_pull_up_down = pdata->rk_irq_gpio_pull_up_down;
#endif
/* initialize cached registers from their original values.
* we can't share this chip with another i2c master.
*/
tca6424_setup_gpio(chip, id->driver_data);
ret = gpiochip_add(&chip->gpio_chip);
if (ret)
goto out_failed;
goto out_failed;
if(tca6424_init_pintype(chip,client))
goto out_failed;
if (pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context);
if (ret < 0)
DBGERR(" %s setup failed, %d\n",__FUNCTION__,ret);
}
tca6424_gpio_irq_setup(chip);
i2c_set_clientdata(client, chip);
chip->client = client;
return 0;
#ifdef CONFIG_SOFT_INTERRUPT
expand_irq_init(chip,&chip->gtca6424_struct,tca6424_irq_read_inputreg);
#endif
return 0;
out_failed:
kfree(chip);
return 0;
}
@ -924,6 +577,17 @@ static int tca6424_remove(struct i2c_client *client)
return 0;
}
static int tca6424_suspend(struct i2c_client *client, pm_message_t mesg)
{
DBG("*****************tca6424 suspend*******************");
return 0;
}
static int tca6424_resume(struct i2c_client *client)
{
DBG("*****************tca6424 resume*******************");
return 0;
}
static struct i2c_driver tca6424_driver = {
.driver = {
@ -933,9 +597,9 @@ static struct i2c_driver tca6424_driver = {
.probe = tca6424_probe,
.remove = tca6424_remove,
.id_table = tca6424_id,
.resume = tca6424_resume,
.suspend = tca6424_suspend,
};
static int __init tca6424_init(void)
{
int tmp;

View File

@ -463,14 +463,12 @@ static int rk2818_xfer_msg(struct i2c_adapter *adap,
}
//not I2C code,add by sxj,used for extend gpio intrrupt,set SCL and SDA pin.
if(msg->flags & I2C_M_RD)
{
#if defined (CONFIG_IOEXTEND_TCA6424)
if (pdata && pdata->reseti2cpin) {
pdata->reseti2cpin();
}
#endif
#if defined (CONFIG_IOEXTEND_TCA6424)
if (pdata && pdata->reseti2cpin) {
pdata->reseti2cpin();
}
#endif
}
return ret;

56
drivers/input/keyboard/matrix_keypad.c Normal file → Executable file
View File

@ -44,13 +44,14 @@ struct matrix_keypad {
static void __activate_col(const struct matrix_keypad_platform_data *pdata,
int col, bool on)
{
bool level_on = !pdata->active_low;
// bool level_on = !pdata->active_low;
bool level_on = pdata->active_low;
if (on) {
gpio_direction_output(pdata->col_gpios[col], level_on);
} else {
gpio_set_value_cansleep(pdata->col_gpios[col], !level_on);
gpio_direction_input(pdata->col_gpios[col]);
//gpio_direction_input(pdata->col_gpios[col]);
}
}
@ -84,6 +85,7 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
//printk("enable_row_irqs \n");
for (i = 0; i < pdata->num_row_gpios; i++)
enable_irq(gpio_to_irq(pdata->row_gpios[i]));
}
@ -92,7 +94,7 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
//printk("disable_row_irqs \n");
for (i = 0; i < pdata->num_row_gpios; i++)
disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
}
@ -102,13 +104,14 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
*/
static void matrix_keypad_scan(struct work_struct *work)
{
struct matrix_keypad *keypad =
container_of(work, struct matrix_keypad, work.work);
struct input_dev *input_dev = keypad->input_dev;
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
uint32_t new_state[MATRIX_MAX_COLS];
int row, col, code;
#if 1
/* de-activate all columns for scanning */
activate_all_cols(pdata, false);
@ -121,11 +124,16 @@ static void matrix_keypad_scan(struct work_struct *work)
for (row = 0; row < pdata->num_row_gpios; row++)
new_state[col] |=
row_asserted(pdata, row) ? (1 << row) : 0;
// new_state[col] &=
// row_asserted(pdata, row) ? (1 << row) : 0;
row_asserted(pdata, row) ? 0: (1 << row) ;
//printk("matrix_keypad_scan: new_state[0]=0x%x,new_state[1]=0x%x,new_state[2]=0x%x,new_state[3]=0x%x \n",new_state[0] ,new_state[1] ,new_state[2] ,new_state[3]);
// printk("matrix_keypad_scan: row0=0x%x,row1=0x%x,row2=0x%x,row3=0x%x \n",row_asserted(pdata, 0),row_asserted(pdata, 1),row_asserted(pdata, 2),row_asserted(pdata,3));
activate_col(pdata, col, false);
}
for (col = 0; col < pdata->num_col_gpios; col++) {
uint32_t bits_changed;
@ -138,12 +146,16 @@ static void matrix_keypad_scan(struct work_struct *work)
continue;
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
//printk("matrix_keypad_scan: MATRIX_SCAN_CODE = 0x%x \n",code);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev,
input_report_key(input_dev,
keypad->keycodes[code],
new_state[col] & (1 << row));
//printk("matrix_keypad_scan:input_report_key- keypad->keycodes[code] = 0x%x,state=0x%x \n", keypad->keycodes[code], new_state[col] & (1 << row));
}
}
}
input_sync(input_dev);
memcpy(keypad->last_key_state, new_state, sizeof(new_state));
@ -155,6 +167,17 @@ static void matrix_keypad_scan(struct work_struct *work)
keypad->scan_pending = false;
enable_row_irqs(keypad);
spin_unlock_irq(&keypad->lock);
#else
//activate_all_cols(pdata, false);
activate_all_cols(pdata, true);
//row_asserted(pdata, 0);
/* Enable IRQs again */
spin_lock_irq(&keypad->lock);
keypad->scan_pending = false;
enable_row_irqs(keypad);
spin_unlock_irq(&keypad->lock);
#endif
}
static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
@ -162,6 +185,8 @@ static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
struct matrix_keypad *keypad = id;
unsigned long flags;
//printk("enter matrix_keypad_interrupt \n");
spin_lock_irqsave(&keypad->lock, flags);
/*
@ -172,7 +197,7 @@ static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
if (unlikely(keypad->scan_pending || keypad->stopped))
goto out;
disable_row_irqs(keypad);
disable_row_irqs(keypad);
keypad->scan_pending = true;
schedule_delayed_work(&keypad->work,
msecs_to_jiffies(keypad->pdata->debounce_ms));
@ -263,9 +288,12 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
goto err_free_cols;
}
gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
//gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
gpio_direction_output(pdata->col_gpios[i], pdata->active_low);
}
//printk("init_matrix_gpio:pdata->active_low = 0x%x \n",pdata->active_low);
for (i = 0; i < pdata->num_row_gpios; i++) {
err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row");
if (err) {
@ -279,10 +307,11 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
}
for (i = 0; i < pdata->num_row_gpios; i++) {
printk("%d %d\n", pdata->row_gpios[i], gpio_to_irq(pdata->row_gpios[i]));
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
matrix_keypad_interrupt,
IRQF_DISABLED |
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
/*IRQF_DISABLED |*/
IRQ_TYPE_EDGE_BOTH,
"matrix-keypad", keypad);
if (err) {
dev_err(&pdev->dev,
@ -321,6 +350,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
unsigned int row_shift;
int err;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
@ -381,6 +411,8 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad);
printk(KERN_INFO "matrix keypad: driver initialized\n");
return 0;
err_free_mem:

View File

@ -18,6 +18,8 @@ Revision: 1.00
#define TCA6424_Port0PinNum 8
#define TCA6424_Port1PinNum 8
#define TCA6424_Port2PinNum 8
#define EXTGPIO_OUTPUT 0
#define EXTGPIO_INPUT 1
#define TCA6424_TotalPortPinNum (TCA6424_Port0PinNum+TCA6424_Port1PinNum+TCA6424_Port2PinNum)
@ -40,6 +42,6 @@ Revision: 1.00
#define tca6424setbit(a,num) ((a)|(0x01<<(num)))
#define tca6424clearbit(a,num) ((a)&(~(0x01<<(num))))
#define TCA6424_I2C_RATE 300*1000
#define TCA6424_I2C_RATE 400*1000
#endif