20160719
I2C驱动开发总结
一. I2C设备驱动代码示例
1.1 源代码
1.1.1 max7359_keypad.c
/* max7359_keypad.c - MAX7359 Key Switch Controller Driver */
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/delay.h>
#define MAX7359_MAX_KEY_ROWS 8
#define MAX7359_MAX_KEY_COLS 8
#define MAX7359_MAX_KEY_NUM (MAX7359_MAX_KEY_ROWS * MAX7359_MAX_KEY_COLS)
#define MAX7359_ROW_SHIFT 3
/*
* MAX7359 registers
*/
#define MAX7359_REG_KEYFIFO 0x00
#define MAX7359_REG_CONFIG 0x01
#define MAX7359_REG_DEBOUNCE 0x02
#define MAX7359_REG_INTERRUPT 0x03
#define MAX7359_REG_PORTS 0x04
#define MAX7359_REG_KEYREP 0x05
#define MAX7359_REG_SLEEP 0x06
/*
* Configuration register bits
*/
#define MAX7359_CFG_SLEEP (1 << 7)
#define MAX7359_CFG_INTERRUPT (1 << 5)
#define MAX7359_CFG_KEY_RELEASE (1 << 3)
#define MAX7359_CFG_WAKEUP (1 << 1)
#define MAX7359_CFG_TIMEOUT (1 << 0)
/*
* Autosleep register values (ms)
*/
#define MAX7359_AUTOSLEEP_8192 0x01
#define MAX7359_AUTOSLEEP_4096 0x02
#define MAX7359_AUTOSLEEP_2048 0x03
#define MAX7359_AUTOSLEEP_1024 0x04
#define MAX7359_AUTOSLEEP_512 0x05
#define MAX7359_AUTOSLEEP_256 0x06
#if 1
#define PRINTK_C(fmt, args...) printk(KERN_INFO#fmt, ##args)
#else
#define PRINTK_C(fmt, args...)
#endif
struct max7359_keypad {
/* matrix key code map */
unsigned short keycodes[MAX7359_MAX_KEY_NUM];
struct input_dev *input_dev;
struct i2c_client *client;
/* +++ Added by XXXX2013-09-04 +++ */
unsigned long last_jiffies;
int bCrA;
int bCrB;
int bCwA;
int bCwB;
/* --- Added by XXXX2013-09-04 --- */
};
static int max7359_write_reg(struct i2c_client *client, u8 reg, u8 val)
{
int ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, reg, val, ret);
return ret;
}
static int max7359_read_reg(struct i2c_client *client, int reg)
{
int ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
__func__, reg, ret);
return ret;
}
static void max7359_build_keycode(struct max7359_keypad *keypad,
const struct matrix_keymap_data *keymap_data)
{
struct input_dev *input_dev = keypad->input_dev;
int i;
for (i = 0; i < keymap_data->keymap_size; i++) {
unsigned int key = keymap_data->keymap[i];
unsigned int row = KEY_ROW(key);
unsigned int col = KEY_COL(key);
unsigned int scancode = MATRIX_SCAN_CODE(row, col,
MAX7359_ROW_SHIFT);
unsigned short keycode = KEY_VAL(key);
/*设置扫描码与按键码对应,并标记按键码为下标的数组位为1*/
keypad->keycodes[scancode] = keycode;
__set_bit(keycode, input_dev->keybit);
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
}
/* runs in an IRQ thread -- can (and will!) sleep */
static irqreturn_t max7359_interrupt(int irq, void *dev_id)
{
struct max7359_keypad *keypad = dev_id;
struct input_dev *input_dev = keypad->input_dev;
int val, row, col, release, code, i;
/* Modified by XXXX2013-08-30 Clear FIFO of MAX7359. */
i = 16;
do {
val = max7359_read_reg(keypad->client, MAX7359_REG_KEYFIFO);
row = val & 0x7;
col = (val >> 3) & 0x7;
release = val & 0x40;
code = MATRIX_SCAN_CODE(row, col, MAX7359_ROW_SHIFT);
PRINTK_C("[MAX7359]val:0x%02X row:%d col:%d, release:%d\n", val, row, col, release);
if ((val < 0) || (0 == (val & 0xC0))) {
return IRQ_HANDLED;
}
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keypad->keycodes[code], !release);
input_sync(input_dev);
} while (i--);
return IRQ_HANDLED;
}
#define MAX7359_DEBOUNCE_JIFFIES msecs_to_jiffies(10)
/* +++ Added