mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
’增加了扩展IOtca6424的驱动,目前中断方式还在测试,尚不可用,暂时屏蔽了FPGA的GPIO接口‘
This commit is contained in:
@@ -254,6 +254,72 @@ struct pca9554_platform_data rk2818_pca9554_data={
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_IOEXTEND_TCA6424)
|
||||
struct rk2818_gpio_expander_info extgpio_tca6424_settinginfo[] = {
|
||||
{
|
||||
.gpio_num = TCA6424_P01,
|
||||
.pin_type = GPIO_OUT,
|
||||
.pin_value = GPIO_LOW,
|
||||
},
|
||||
|
||||
{
|
||||
.gpio_num = TCA6424_P02,// tp3
|
||||
.pin_type = GPIO_OUT,
|
||||
.pin_value = GPIO_LOW,
|
||||
},
|
||||
{
|
||||
.gpio_num = TCA6424_P03,
|
||||
.pin_type = GPIO_OUT,
|
||||
.pin_value = GPIO_LOW,
|
||||
},
|
||||
|
||||
{
|
||||
.gpio_num = TCA6424_P04,// tp3
|
||||
.pin_type = GPIO_OUT,
|
||||
.pin_value = GPIO_LOW,
|
||||
},
|
||||
{
|
||||
.gpio_num = TCA6424_P05,
|
||||
.pin_type = GPIO_OUT,
|
||||
.pin_value = GPIO_LOW,
|
||||
},
|
||||
{
|
||||
.gpio_num = TCA6424_P12,
|
||||
.pin_type = GPIO_IN,
|
||||
//.pin_value =GPIO_HIGH,
|
||||
},
|
||||
|
||||
{
|
||||
.gpio_num = TCA6424_P13,// tp3
|
||||
.pin_type = GPIO_IN,
|
||||
//.pin_value =GPIO_HIGH,
|
||||
},
|
||||
{
|
||||
.gpio_num = TCA6424_P14,
|
||||
.pin_type = GPIO_IN,
|
||||
//.pin_value =GPIO_HIGH,
|
||||
},
|
||||
|
||||
{
|
||||
.gpio_num = TCA6424_P15,// tp3
|
||||
.pin_type = GPIO_IN,
|
||||
//.pin_value =GPIO_HIGH,
|
||||
},
|
||||
};
|
||||
|
||||
struct tca6424_platform_data rk2818_tca6424_data={
|
||||
.gpio_base=GPIOS_EXPANDER_BASE,
|
||||
.gpio_pin_num=CONFIG_EXPANDED_GPIO_NUM,
|
||||
.gpio_irq_start=NR_AIC_IRQS + 2*NUM_GROUP,
|
||||
.irq_pin_num=CONFIG_EXPANDED_GPIO_IRQ_NUM,
|
||||
.tca6424_irq_pin=RK2818_PIN_PA1,
|
||||
.settinginfo=extgpio_tca6424_settinginfo,
|
||||
.settinginfolen=ARRAY_SIZE(extgpio_tca6424_settinginfo),
|
||||
.names="extend_gpio_tca6424",
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
* I2C devices
|
||||
*author: kfx
|
||||
@@ -357,6 +423,15 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
|
||||
.platform_data=&rk2818_pca9554_data.gpio_base,
|
||||
},
|
||||
#endif
|
||||
#if defined (CONFIG_IOEXTEND_TCA6424)
|
||||
{
|
||||
.type = "extend_gpio_tca6424",
|
||||
.addr = 0x23,
|
||||
.flags = 0,
|
||||
.platform_data=&rk2818_tca6424_data.gpio_base,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_PMIC_LP8725)
|
||||
{
|
||||
.type = "lp8725",
|
||||
|
||||
21
arch/arm/mach-rk2818/include/mach/board.h
Normal file → Executable file
21
arch/arm/mach-rk2818/include/mach/board.h
Normal file → Executable file
@@ -105,6 +105,27 @@ struct pca9554_platform_data {
|
||||
char **names;
|
||||
};
|
||||
|
||||
struct tca6424_platform_data {
|
||||
/* the first extern gpio number in all of gpio groups */
|
||||
unsigned gpio_base;
|
||||
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 tca6424_irq_pin; //<2F><>չIO<49><4F><EFBFBD>жϹ<D0B6><CFB9><EFBFBD><EFBFBD>ĸ<EFBFBD>gpio
|
||||
/* initial polarity inversion setting */
|
||||
uint16_t invert;
|
||||
struct rk2818_gpio_expander_info *settinginfo;
|
||||
int settinginfolen;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/*lcd*/
|
||||
struct lcd_td043mgea1_data{
|
||||
u32 pin_txd;
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
#include <linux/init.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#define PIN_BASE 0//<2F><><EFBFBD><EFBFBD>RK2818<31>ڲ<EFBFBD>GPIO<49>ĵ<EFBFBD>һ<EFBFBD><D2BB>PIN<49><4E>(<28><>GPIO0_A0)<29><>gpio_desc<73><63><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>ַ
|
||||
#define PIN_BASE 0//<2F><><EFBFBD><EFBFBD>RK2818<31>ڲ<EFBFBD>GPIO<49>ĵ<EFBFBD>һ<EFBFBD><D2BB>PIN<49><4E>(<28><>GPIO0_A0)<29><>gpio_desc<73><63><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>ַ
|
||||
#define NUM_GROUP 8// <20><><EFBFBD><EFBFBD>RK2818<31>ڲ<EFBFBD>GPIOÿһ<C3BF><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>PIN<49><4E>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>Ϊ8<CEAA><38><EFBFBD><EFBFBD><EFBFBD><EFBFBD>GPIOX_Y0~ GPIOX_Y7(<28><><EFBFBD><EFBFBD>X=0/1;Y=A/B/C/D)
|
||||
#define MAX_GPIO_BANKS 8//<2F><><EFBFBD><EFBFBD>RK2818<31>ڲ<EFBFBD>GPIO<49>ܹ<EFBFBD><DCB9>м<EFBFBD><D0BC>飬<EFBFBD><E9A3AC><EFBFBD>ڶ<EFBFBD>Ϊ8<CEAA>飬<EFBFBD><E9A3AC>GPIO0_A~ GPIO0_D<5F><44>GPIO1_A~ GPIO1_D<5F><44>
|
||||
#define GPIOS_EXPANDER_BASE (PIN_BASE+NUM_GROUP*MAX_GPIO_BANKS)
|
||||
//<2F><><EFBFBD><EFBFBD>GPIO<49><4F>PIN<49><4E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF>(NUM_GROUP*MAX_GPIO_BANKS)<29><>ʾRK2818<31><38><EFBFBD>ڲ<EFBFBD>GPIO<49><4F>PIN<49><4E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF>CONFIG_ARCH_EXTEND_GPIOS<4F><53>ʾ<EFBFBD><CABE>չIO<49><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF>
|
||||
#define ARCH_NR_GPIOS (NUM_GROUP*MAX_GPIO_BANKS) + CONFIG_EXPANDED_GPIO_NUM
|
||||
#define ARCH_NR_GPIOS (NUM_GROUP*MAX_GPIO_BANKS)+CONFIG_EXPANDED_GPIO_NUM
|
||||
typedef enum eGPIOPinLevel
|
||||
{
|
||||
GPIO_LOW=0,
|
||||
@@ -122,14 +122,14 @@ struct rk2818_gpio_bank {
|
||||
#define RK2818_PIN_PC6 (PIN_BASE + 2*NUM_GROUP + 6)
|
||||
#define RK2818_PIN_PC7 (PIN_BASE + 2*NUM_GROUP + 7)
|
||||
|
||||
#define RK2818_PIN_PD0 (PIN_BASE + 3*NUM_GROUP + 0)
|
||||
#define RK2818_PIN_PD1 (PIN_BASE + 3*NUM_GROUP + 1)
|
||||
#define RK2818_PIN_PD2 (PIN_BASE + 3*NUM_GROUP + 2)
|
||||
#define RK2818_PIN_PD3 (PIN_BASE + 3*NUM_GROUP + 3)
|
||||
#define RK2818_PIN_PD4 (PIN_BASE + 3*NUM_GROUP + 4)
|
||||
#define RK2818_PIN_PD5 (PIN_BASE + 3*NUM_GROUP + 5)
|
||||
#define RK2818_PIN_PD6 (PIN_BASE + 3*NUM_GROUP + 6)
|
||||
#define RK2818_PIN_PD7 (PIN_BASE + 3*NUM_GROUP + 7)
|
||||
#define RK2818_PIN_PD0 (PIN_BASE + 3*NUM_GROUP + 0)
|
||||
#define RK2818_PIN_PD1 (PIN_BASE + 3*NUM_GROUP + 1)
|
||||
#define RK2818_PIN_PD2 (PIN_BASE + 3*NUM_GROUP + 2)
|
||||
#define RK2818_PIN_PD3 (PIN_BASE + 3*NUM_GROUP + 3)
|
||||
#define RK2818_PIN_PD4 (PIN_BASE + 3*NUM_GROUP + 4)
|
||||
#define RK2818_PIN_PD5 (PIN_BASE + 3*NUM_GROUP + 5)
|
||||
#define RK2818_PIN_PD6 (PIN_BASE + 3*NUM_GROUP + 6)
|
||||
#define RK2818_PIN_PD7 (PIN_BASE + 3*NUM_GROUP + 7)
|
||||
|
||||
#define RK2818_PIN_PE0 (PIN_BASE + 4*NUM_GROUP + 0)
|
||||
#define RK2818_PIN_PE1 (PIN_BASE + 4*NUM_GROUP + 1)
|
||||
@@ -168,7 +168,7 @@ struct rk2818_gpio_bank {
|
||||
#define RK2818_PIN_PH6 (PIN_BASE + 7*NUM_GROUP + 6)
|
||||
#define RK2818_PIN_PH7 (PIN_BASE + 7*NUM_GROUP + 7)
|
||||
/***********************define extern gpio pin num******************************/
|
||||
#if defined(CONFIG_SPI_GPIO)
|
||||
#if 0//defined(CONFIG_SPI_GPIO)
|
||||
#define FPGA_PIO0_00 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 0)
|
||||
#define FPGA_PIO0_01 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 1)
|
||||
#define FPGA_PIO0_02 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 2)
|
||||
@@ -279,6 +279,37 @@ struct rk2818_gpio_bank {
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_IOEXTEND_TCA6424)
|
||||
#define TCA6424_P00 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 0)
|
||||
#define TCA6424_P01 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 1)
|
||||
#define TCA6424_P02 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 2)
|
||||
#define TCA6424_P03 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 3)
|
||||
#define TCA6424_P04 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 4)
|
||||
#define TCA6424_P05 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 5)
|
||||
#define TCA6424_P06 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 6)
|
||||
#define TCA6424_P07 (GPIOS_EXPANDER_BASE + 0*NUM_GROUP + 7)
|
||||
|
||||
#define TCA6424_P10 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 0)
|
||||
#define TCA6424_P11 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 1)
|
||||
#define TCA6424_P12 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 2)
|
||||
#define TCA6424_P13 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 3)
|
||||
#define TCA6424_P14 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 4)
|
||||
#define TCA6424_P15 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 5)
|
||||
#define TCA6424_P16 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 6)
|
||||
#define TCA6424_P17 (GPIOS_EXPANDER_BASE + 1*NUM_GROUP + 7)
|
||||
|
||||
#define TCA6424_P20 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 0)
|
||||
#define TCA6424_P21 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 1)
|
||||
#define TCA6424_P22 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 2)
|
||||
#define TCA6424_P23 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 3)
|
||||
#define TCA6424_P24 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 4)
|
||||
#define TCA6424_P25 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 5)
|
||||
#define TCA6424_P26 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 6)
|
||||
#define TCA6424_P27 (GPIOS_EXPANDER_BASE + 2*NUM_GROUP + 7)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern void __init rk2818_gpio_init(struct rk2818_gpio_bank *data, int nr_banks);
|
||||
extern void __init rk2818_gpio_irq_setup(void);
|
||||
@@ -314,12 +345,19 @@ static inline int irq_to_gpio(unsigned irq)
|
||||
{
|
||||
return (RK2818_PIN_PE0 + (irq - __gpio_to_irq(RK2818_PIN_PE0)));
|
||||
}
|
||||
#if defined(CONFIG_SPI_GPIO)
|
||||
#if 0//defined(CONFIG_SPI_GPIO)
|
||||
else if((irq - __gpio_to_irq(FPGA_PIO0_00)) <2*NUM_GROUP)
|
||||
{
|
||||
return (FPGA_PIO0_00 + (irq - __gpio_to_irq(FPGA_PIO0_00)));
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_IOEXTEND_TCA6424)
|
||||
else if((irq - __gpio_to_irq(TCA6424_P00)) <3*NUM_GROUP)
|
||||
{
|
||||
return (TCA6424_P00 + (irq - __gpio_to_irq(TCA6424_P00)));
|
||||
}
|
||||
#endif
|
||||
|
||||
else
|
||||
{
|
||||
return -ENXIO;
|
||||
|
||||
12
drivers/gpio/Kconfig
Normal file → Executable file
12
drivers/gpio/Kconfig
Normal file → Executable file
@@ -236,13 +236,21 @@ config GPIO_PCA9554
|
||||
help
|
||||
Say yes here to access the PCA9554 GPIO EXPANDER
|
||||
|
||||
config IOEXTEND_TCA6424
|
||||
default y
|
||||
bool "ROCKCHIP TCA6424 CONTROL"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to access the TCA6424 GPIO EXPANDER
|
||||
|
||||
|
||||
config EXPANDED_GPIO_NUM
|
||||
int "setting the amount of expanded gpios"
|
||||
default 8 if GPIO_PCA9554
|
||||
default 8 if (GPIO_PCA9554||IOEXTEND_TCA6424)
|
||||
default 0
|
||||
|
||||
config EXPANDED_GPIO_IRQ_NUM
|
||||
int "setting the amount of expanded gpio irqs"
|
||||
default 8 if GPIO_PCA9554
|
||||
default 8 if (GPIO_PCA9554||IOEXTEND_TCA6424)
|
||||
default 0
|
||||
endif
|
||||
|
||||
2
drivers/gpio/Makefile
Normal file → Executable file
2
drivers/gpio/Makefile
Normal file → Executable file
@@ -20,3 +20,5 @@ obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
|
||||
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_IOEXTEND_TCA6424) += soft_interrupt.o
|
||||
|
||||
983
drivers/gpio/tca6424.c
Executable file
983
drivers/gpio/tca6424.c
Executable file
@@ -0,0 +1,983 @@
|
||||
/*
|
||||
* 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 : tca6424.c
|
||||
MODIFY : sxj
|
||||
DATE : 2010-8-11
|
||||
NOTES :
|
||||
********************************************************************/
|
||||
#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 "../drivers/gpio/tca6424.h"
|
||||
|
||||
#if 0
|
||||
#define TCA6424DEB
|
||||
#define DBG(x...) printk(KERN_INFO x)
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#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];
|
||||
|
||||
#ifdef TCA6424_OUTREGLOCK
|
||||
struct mutex outreglock;
|
||||
#endif
|
||||
#ifdef TCA6424_INPUTREGLOCK
|
||||
struct mutex inputreglock;
|
||||
#endif
|
||||
#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 gpio_chip gpio_chip;
|
||||
char **names;
|
||||
};
|
||||
|
||||
static const struct i2c_device_id tca6424_id[] =
|
||||
{
|
||||
{"extend_gpio_tca6424",8,},
|
||||
{ }
|
||||
};
|
||||
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;
|
||||
|
||||
static int tca6424_write_reg(struct i2c_client *client, uint8_t reg, uint8_t val)
|
||||
{
|
||||
int ret=-1;
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_msg msg;
|
||||
char tx_buf[2];
|
||||
if(!client)
|
||||
return ret;
|
||||
adap = client->adapter;
|
||||
tx_buf[0] = reg;
|
||||
tx_buf[1]= val;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.buf = tx_buf;
|
||||
msg.len = 1 +1;
|
||||
msg.flags = client->flags;
|
||||
msg.scl_rate = TCA6424_I2C_RATE;
|
||||
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tca6424_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
int ret=-1;
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_msg msgs[2];
|
||||
|
||||
if(!client)
|
||||
return ret;
|
||||
adap = client->adapter;
|
||||
//<2F><><EFBFBD>ͼĴ<CDBC><C4B4><EFBFBD><EFBFBD><EFBFBD>ַ
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].buf = ®
|
||||
msgs[0].flags = client->flags;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].scl_rate = TCA6424_I2C_RATE;
|
||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
msgs[1].buf = val;
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = client->flags | I2C_M_RD;
|
||||
msgs[1].len = 1;
|
||||
msgs[1].scl_rate = TCA6424_I2C_RATE;
|
||||
|
||||
ret = i2c_transfer(adap, msgs, 2);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int tca6424_gpio_direction_input(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;
|
||||
|
||||
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 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;
|
||||
}
|
||||
#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;
|
||||
err:
|
||||
|
||||
DBG("**%s[%d],config_reg=%2x,ret=%d**\n",__FUNCTION__,__LINE__,reg_val,ret);
|
||||
|
||||
#ifdef TCA6424_CONFIGREGLOCK
|
||||
mutex_unlock(&chip->configreglock);
|
||||
#endif
|
||||
|
||||
return (ret<0)?-1:0;
|
||||
}
|
||||
|
||||
static int tca6424_gpio_direction_output(struct gpio_chip *gc,uint8_t pin_num, int val)
|
||||
{
|
||||
struct tca6424_chip *chip;
|
||||
uint8_t gpioPortNum;
|
||||
uint8_t gpioPortPinNum;
|
||||
uint8_t reg_val;
|
||||
uint8_t Regaddr;
|
||||
int ret = -1;
|
||||
|
||||
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 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 -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)
|
||||
{
|
||||
#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->reg_direction[gpioPortNum] = reg_val;
|
||||
#ifdef TCA6424_CONFIGREGLOCK
|
||||
mutex_unlock(&chip->configreglock);
|
||||
#endif
|
||||
ret=-1;
|
||||
#ifdef TCA6424_OUTREGLOCK
|
||||
if (!mutex_trylock(&chip->outreglock))
|
||||
{
|
||||
DBGERR("**%s[%d] Did not get the outreglock**\n",__FUNCTION__,__LINE__);
|
||||
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)
|
||||
{
|
||||
#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->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);
|
||||
return (ret<0)?-1:0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
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);
|
||||
#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);
|
||||
}
|
||||
|
||||
static void tca6424_gpio_set_value(struct gpio_chip *gc, uint8_t pin_num, int val)
|
||||
{
|
||||
struct tca6424_chip *chip;
|
||||
uint8_t gpioPortNum;
|
||||
uint8_t gpioPortPinNum;
|
||||
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;
|
||||
|
||||
Regaddr = TCA6424_OutputLevel_Reg+gpioPortNum;
|
||||
|
||||
if(tca6424getbit(chip->reg_direction[gpioPortNum],gpioPortPinNum)) // input state
|
||||
return;// -1;
|
||||
|
||||
#ifdef TCA6424_OUTREGLOCK
|
||||
if (!mutex_trylock(&chip->outreglock))
|
||||
{
|
||||
DBGERR("**%s[%d] Did not get the outreglock**\n",__FUNCTION__,__LINE__);
|
||||
return;// -1;
|
||||
}
|
||||
#endif
|
||||
if (val)
|
||||
reg_val = tca6424setbit(chip->reg_output[gpioPortNum], gpioPortPinNum);
|
||||
else
|
||||
reg_val = tca6424clearbit(chip->reg_output[gpioPortNum], gpioPortPinNum);
|
||||
|
||||
ret = tca6424_write_reg(chip->client, Regaddr, reg_val);
|
||||
if (ret<0)
|
||||
goto err;
|
||||
chip->reg_output[gpioPortNum] = reg_val;
|
||||
|
||||
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**\n",__FUNCTION__);
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
gc->dev = &chip->client->dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
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 tca6424_pin_num;
|
||||
uint8_t gpioPortNum;
|
||||
uint8_t gpioPortPinNum,tca6424_settingpin_num=0;
|
||||
|
||||
if(platform_data)
|
||||
{
|
||||
tca6424_gpio_settinginfo=platform_data->settinginfo;
|
||||
if(tca6424_gpio_settinginfo)
|
||||
{
|
||||
tca6424_settingpin_num=platform_data->settinginfolen;
|
||||
for(i=0;i<tca6424_settingpin_num;i++)
|
||||
{
|
||||
if(!tca6424_checkrange(chip->gpio_start,chip->gpio_pin_num,tca6424_gpio_settinginfo[i].gpio_num))
|
||||
{
|
||||
tca6424_pin_num=tca6424_gpio_settinginfo[i].gpio_num-chip->gpio_start;
|
||||
gpioPortNum = tca6424_pin_num/ TCA6424_PortPinNum;
|
||||
gpioPortPinNum= tca6424_pin_num% TCA6424_PortPinNum;
|
||||
//DBG("gpioPortNum=%d,gpioPortNum=%d,tca6424_pin_num=%d,reg_direction=%x,reg_output=%x,reg_input=%x\n",gpioPortNum,gpioPortPinNum,tca6424_pin_num,reg_direction[i],reg_output[i]);
|
||||
if((gpioPortNum>=TCA6424_PortNum)||(gpioPortPinNum>=portnum[gpioPortNum]))
|
||||
continue;
|
||||
if(tca6424_gpio_settinginfo[i].pin_type==GPIO_IN)
|
||||
{
|
||||
reg_direction[gpioPortNum]=tca6424setbit(reg_direction[gpioPortNum],gpioPortPinNum);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef TCA6424_OUTREGLOCK
|
||||
mutex_init(&chip->outreglock);
|
||||
#endif
|
||||
#ifdef TCA6424_INPUTREGLOCK
|
||||
mutex_init(&chip->inputreglock);
|
||||
#endif
|
||||
#ifdef TCA6424_OUTREGLOCK
|
||||
mutex_init(&chip->configreglock);
|
||||
#endif
|
||||
|
||||
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]);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
void tca6424_reset_itr(void)
|
||||
{
|
||||
// udelay(1);
|
||||
//if(client->Channel==I2C_CH1)
|
||||
//{
|
||||
//gpio_direction_output(RK2818_PIN_PE6,GPIO_HIGH);
|
||||
//gpio_direction_output(RK2818_PIN_PE7,GPIO_LOW);
|
||||
|
||||
//GPIOSetPinDirection(RK2818_PIN_PE6,GPIO_OUT);// data
|
||||
//GPIOSetPinDirection(RK2818_PIN_PE7,GPIO_OUT);
|
||||
|
||||
rk2818_mux_api_set(GPIOE_U1IR_I2C1_NAME, IOMUXA_GPIO1_A67);
|
||||
udelay(3);
|
||||
gpio_set_value(RK2818_PIN_PE7,GPIO_HIGH);
|
||||
udelay(1);
|
||||
rk2818_mux_api_set(GPIOE_U1IR_I2C1_NAME, IOMUXA_I2C1);
|
||||
//}
|
||||
/*else
|
||||
{
|
||||
gpio_direction_output(RK2818_PIN_PE4,GPIO_HIGH);
|
||||
gpio_direction_output(RK2818_PIN_PE5,GPIO_LOW);
|
||||
|
||||
//GPIOSetPinDirection(RK2818_PIN_PE4,GPIO_OUT);// data
|
||||
//GPIOSetPinDirection(RK2818_PIN_PE5,GPIO_OUT);
|
||||
rk2818_mux_api_set(GPIOE_I2C0_SEL_NAME, IOMUXA_GPIO1_A45);
|
||||
|
||||
udelay(3);
|
||||
gpio_set_value(RK2818_PIN_PE5,GPIO_HIGH);
|
||||
udelay(1);
|
||||
|
||||
rk2818_mux_api_set(GPIOE_I2C0_SEL_NAME, IOMUXA_I2C0);
|
||||
}*/
|
||||
}
|
||||
|
||||
static int __devinit tca6424_probe(struct i2c_client *client,const struct i2c_device_id *id)
|
||||
{
|
||||
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;
|
||||
|
||||
chip = kzalloc(sizeof(struct tca6424_chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
pdata = client->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
DBGERR(" %s no platform data\n",__FUNCTION__);
|
||||
ret = -EINVAL;
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
|
||||
out_failed:
|
||||
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tca6424_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tca6424_platform_data *pdata = client->dev.platform_data;
|
||||
struct tca6424_chip *chip = i2c_get_clientdata(client);
|
||||
int ret = 0;
|
||||
|
||||
if (pdata->teardown) {
|
||||
ret = pdata->teardown(client, chip->gpio_chip.base,
|
||||
chip->gpio_chip.ngpio, pdata->context);
|
||||
if (ret < 0) {
|
||||
DBGERR(" %s failed, %d\n",__FUNCTION__,ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_remove(&chip->gpio_chip);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", ret);
|
||||
return ret;
|
||||
}
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct i2c_driver tca6424_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "extend_gpio_tca6424",
|
||||
},
|
||||
.probe = tca6424_probe,
|
||||
.remove = tca6424_remove,
|
||||
.id_table = tca6424_id,
|
||||
};
|
||||
|
||||
|
||||
static int __init tca6424_init(void)
|
||||
{
|
||||
int tmp;
|
||||
DBG(KERN_ALERT"**********tca6424_init**********\n");
|
||||
tmp=i2c_add_driver(&tca6424_driver);
|
||||
return 0;
|
||||
}
|
||||
static void __exit tca6424_exit(void)
|
||||
{
|
||||
DBG(KERN_ALERT"**********tca6424_exit**********\n");
|
||||
i2c_del_driver(&tca6424_driver);
|
||||
}
|
||||
|
||||
module_init(tca6424_init);
|
||||
module_exit(tca6424_exit);
|
||||
|
||||
MODULE_AUTHOR(" XXX XXX@rock-chips.com");
|
||||
MODULE_DESCRIPTION("Driver for rk2818 tca6424 device");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
45
drivers/gpio/tca6424.h
Executable file
45
drivers/gpio/tca6424.h
Executable file
@@ -0,0 +1,45 @@
|
||||
/******************************************************************/
|
||||
/* Copyright (C) 2008 ROCK-CHIPS FUZHOU . All Rights Reserved. */
|
||||
/*******************************************************************
|
||||
File : gpio.h
|
||||
Desc : <20><><EFBFBD><EFBFBD>gpio<69>ļĴ<C4BC><C4B4><EFBFBD><EFBFBD>ṹ<EFBFBD><E1B9B9>\<5C>Ĵ<EFBFBD><C4B4><EFBFBD>λ<EFBFBD>ĺ궨<C4BA><EAB6A8>\<5C>ӿں<D3BF><DABA><EFBFBD>
|
||||
|
||||
Author :
|
||||
Date : 2008-11-20
|
||||
Modified:
|
||||
Revision: 1.00
|
||||
$Log: gpio.h,v $
|
||||
*********************************************************************/
|
||||
#ifndef _DRIVER_TCA6424_GPIO_H_
|
||||
#define _DRIVER_TCA6424_GPIO_H_
|
||||
|
||||
#define TCA6424_PortNum 3
|
||||
#define TCA6424_PortPinNum 8
|
||||
#define TCA6424_Port0PinNum 8
|
||||
#define TCA6424_Port1PinNum 8
|
||||
#define TCA6424_Port2PinNum 8
|
||||
|
||||
#define TCA6424_TotalPortPinNum (TCA6424_Port0PinNum+TCA6424_Port1PinNum+TCA6424_Port2PinNum)
|
||||
|
||||
#define TCA6424_InputLevel_Reg 0x0 //r only
|
||||
#define TCA6424_OutputLevel_Reg 0x4 // r/w default ffff
|
||||
#define TCA6424_Invert_Reg 0x8 // r/w default 0
|
||||
#define TCA6424_Config_Reg 0x0c // r/w default ffff
|
||||
|
||||
|
||||
#define TCA6424_Auto_InputLevel_Reg 0x80
|
||||
#define TCA6424_Auto_OutputLevel_Reg 0x84
|
||||
#define TCA6424_Auto_Invert_Reg 0x88
|
||||
#define TCA6424_Auto_Config_Reg 0x8c
|
||||
|
||||
#define TCA6424_OUTREGLOCK
|
||||
#define TCA6424_INPUTREGLOCK
|
||||
#define TCA6424_CONFIGREGLOCK
|
||||
|
||||
#define tca6424getbit(a,num) (((a)>>(num))&0x01)
|
||||
#define tca6424setbit(a,num) ((a)|(0x01<<(num)))
|
||||
#define tca6424clearbit(a,num) ((a)&(~(0x01<<(num))))
|
||||
|
||||
#define TCA6424_I2C_RATE 300*1000
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user