mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
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:
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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; //<2F>жϵĸ<CFB5><C4B8><EFBFBD>
|
||||
unsigned pca9954_irq_pin; //<2F><>չIO<49><4F><EFBFBD>жϹ<D0B6><CFB9><EFBFBD><EFBFBD>ĸ<EFBFBD>gpio
|
||||
unsigned int gpio_irq_start;
|
||||
unsigned int irq_pin_num; //<2F>жϵĸ<CFB5><C4B8><EFBFBD>
|
||||
unsigned int pca9954_irq_pin; //<2F><>չIO<49><4F><EFBFBD>жϹ<D0B6><CFB9><EFBFBD><EFBFBD>ĸ<EFBFBD>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; //<2F>жϵĸ<CFB5><C4B8><EFBFBD>
|
||||
unsigned tca6424_irq_pin; //<2F><>չIO<49><4F><EFBFBD>жϹ<D0B6><CFB9><EFBFBD><EFBFBD>ĸ<EFBFBD>gpio
|
||||
unsigned int gpio_irq_start;
|
||||
unsigned int irq_pin_num; //<2F>жϵĸ<CFB5><C4B8><EFBFBD>
|
||||
unsigned int tca6424_irq_pin; //<2F><>չIO<49><4F><EFBFBD>жϹ<D0B6><CFB9><EFBFBD><EFBFBD>ĸ<EFBFBD>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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
448
drivers/gpio/soft_interrupt.c
Executable 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]);// <20><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
|
||||
levelchg=oldintputreg[i]^tempintputreg[i];// <20>ҳ<EFBFBD>ǰ<EFBFBD><C7B0>״̬<D7B4><CCAC>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>pin
|
||||
tempinttype=~(tempintputreg[i]^pchip->inttype[i]);// <20>ҳ<EFBFBD><D2B3><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4>͵<EFBFBD>ǰpin״̬һ<CCAC><D2BB><EFBFBD><EFBFBD>pin<69><6E>ע<EFBFBD><D7A2>ֻ֧<D6BB><D6A7>low high<67><68><EFBFBD><EFBFBD>pin<69><6E><EFBFBD><EFBFBD>
|
||||
|
||||
tempinttype=(~pchip->inttype1[i])&tempinttype;// inttype1 Ϊ<><CEAA><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>Ӧ<EFBFBD><D3A6>tempinttypeλ<65><CEBB><EFBFBD>㣬<EFBFBD><E3A3AC>Ϊ<EFBFBD><CEAA>λֻ<CEBB><D6BB>inttype1<65><31><EFBFBD><EFBFBD>
|
||||
tempinttype|=pchip->inttype1[i];//<2F><>ƽֻҪ<D6BB>DZ仯<C7B1>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD>ж<EFBFBD>
|
||||
tempinttype&=pchip->inttype_set[i];//<2F>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>type<70><65><EFBFBD><EFBFBD>
|
||||
|
||||
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; //<2F>жϺţ<CFBA><C5A3><EFBFBD>չio<69><6F><EFBFBD>жϺ<D0B6>Ӧ<EFBFBD>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>io<69>жϺŵĺ<C5B5><C4BA>档<EFBFBD><E6A1A3>rk<72>ڲ<EFBFBD><DAB2>ж<EFBFBD>48<34><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>gpio 16<31><36><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<D0B6><CFA3><EFBFBD><EFBFBD><EFBFBD>pinӦ<6E>ô<EFBFBD>48+16<31><36>ʼ
|
||||
|
||||
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 <20><>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>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
47
drivers/gpio/soft_interrupt.h
Executable 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; //<2F>жϵĸ<CFB5><C4B8><EFBFBD>
|
||||
unsigned int irq_gpiopin; //<2F><><EFBFBD>жϵ<D0B6><CFB5>ж<EFBFBD> <20><>
|
||||
unsigned int irq_chain; //<2F><><EFBFBD>жϵ<D0B6><CFB5>жϺ<D0B6>
|
||||
|
||||
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
|
||||
|
||||
@@ -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; //<2F>жϵĸ<CFB5><C4B8><EFBFBD>
|
||||
unsigned irq_gpiopin; //<2F><><EFBFBD>жϵ<D0B6><CFB5>жϺ<D0B6>
|
||||
unsigned irq_chain; //<2F><><EFBFBD>жϵ<D0B6><CFB5>жϺ<D0B6>
|
||||
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 <20><><EFBFBD><EFBFBD><EFBFBD>в<EFBFBD><D0B2><EFBFBD>
|
||||
} 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)) //<2F>жϸ<D0B6>pin<69>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
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, ®_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]);// <20><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
|
||||
levelchg=pchip->reg_input[i]^tempintputreg[i];// <20>ҳ<EFBFBD>ǰ<EFBFBD><C7B0>״̬<D7B4><CCAC>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>pin
|
||||
tempinttype=~(tempintputreg[i]^pchip->inttype[i]);// <20>ҳ<EFBFBD><D2B3><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4>͵<EFBFBD>ǰpin״̬һ<CCAC><D2BB><EFBFBD><EFBFBD>pin<69><6E>ע<EFBFBD><D7A2>ֻ֧<D6BB><D6A7>low high<67><68><EFBFBD><EFBFBD>pin<69><6E><EFBFBD><EFBFBD>
|
||||
|
||||
tempinttype=(~pchip->inttype1[i])&tempinttype;// inttype1 Ϊ<><CEAA><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>Ӧ<EFBFBD><D3A6>tempinttypeλ<65><CEBB><EFBFBD>㣬<EFBFBD><E3A3AC>Ϊ<EFBFBD><CEAA>λֻ<CEBB><D6BB>inttype1<65><31><EFBFBD><EFBFBD>
|
||||
tempinttype|=pchip->inttype1[i];//<2F><>ƽֻҪ<D6BB>DZ仯<C7B1>Ͳ<EFBFBD><CDB2><EFBFBD><EFBFBD>ж<EFBFBD>
|
||||
tempinttype&=pchip->inttype_set[i];//<2F>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>type<70><65><EFBFBD><EFBFBD>
|
||||
|
||||
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; //<2F>жϺţ<CFBA><C5A3><EFBFBD>չio<69><6F><EFBFBD>жϺ<D0B6>Ӧ<EFBFBD>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>io<69>жϺŵĺ<C5B5><C4BA>档<EFBFBD><E6A1A3>rk<72>ڲ<EFBFBD><DAB2>ж<EFBFBD>48<34><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>gpio 16<31><36><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<D0B6><CFA3><EFBFBD><EFBFBD><EFBFBD>pinӦ<6E>ô<EFBFBD>48+16<31><36>ʼ
|
||||
|
||||
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 <20><>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>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 , ®_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, ®_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, ®_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;
|
||||
|
||||
@@ -463,14 +463,12 @@ exit:
|
||||
}
|
||||
|
||||
//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
56
drivers/input/keyboard/matrix_keypad.c
Normal file → Executable 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:
|
||||
|
||||
@@ -18,6 +18,8 @@ $Log: gpio.h,v $
|
||||
#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 @@ $Log: gpio.h,v $
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user