1.设备树中添加设备信息
nfc_reader:zlg600a@59 {
compatible = “nfc,zlg600a”;
reg = <0x59>;
interrupt-parent = <&gpio2>;
interrupts = <17 0>;
status = “disabled”;
};
2.驱动代码框架,具体细节不方便列出。
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio_keys.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <asm-generic/errno.h>
#include <linux/slab.h>
#define __FRAME_LEN 0 /< \brief 帧长度 */
#define __FRAME_CMD_TYPE 1 /< \brief 命令类型(高4位为包号) /
#define __FRAME_CMD 2 /**< \brief 命令/
#define __FRAME_STATUS 2 /< \brief 响应状态 */
#define __FRAME_DATA_LEN 3 /< \brief 数据长度 */
#define __FRAME_DATA 4 /< \brief 数据起始位置 */
#define __FRAME_PRTC_LEN 6 /< \brief 协议字符长度 */
#define __CMD_TYPE_DEV_CTRL 0x01 /< \brief 设备控制类命令 */
#define __CMD_TYPE_MFIARE 0x02 /< \brief TypeA(包括Mifare卡)类命令 */
#define __CMD_TYPE_ISO7816 0x05 /< \brief ISO7816类命令 */
#define __CMD_TYPE_PICC 0x06 /< \brief ISO14443(PICC)卡类命令 */
#define __CMD_TYPE_PLUS_CPU 0x07 /**< \brief PLUS CPU卡(不包括Mifare卡)类命令 */
#define __ACK_LENGTH_DEV_INFO 0x1A /返回设备信息时的数据总长度/
#define __ACK_LENGTH_AUTO_DETECT 0x1F /返回设备信息时的数据总长度/
static struct i2c_client *zlg600_client;
static int request_id = 0;
wait_queue_head_t read_data_wq; //定义一个等待工作队列
static volatile int irq_come_in = 0;
static volatile int g_cmd_seq = 0x00;
static int nfc_zlg_open(struct inode *inode, struct file *file)
{
//open的时候要进行初始化,初始化模块进入自动工作模式
printk(“Open Device: Initial Auto Work Mode\n”);
return 1;
}
static ssize_t nfc_zlg_read(struct file *filp, char __user *buf,
size_t count, loff_t *offset)
{
int ret;
if (filp->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
goto FAIL;
}
ret = wait_event_interruptible(read_data_wq, (irq_come_in==1));
FAIL:
return ret;
}
static const struct file_operations nfc_zlg_fops = {
.owner = THIS_MODULE,
.open = nfc_zlg_open,
.read = nfc_zlg_read,
};
static struct miscdevice nfc_zlg_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = “zlg600a”,
.fops = &nfc_zlg_fops,
};
uint8_t g_send_buf[100]; /< \brief 发送缓冲区 */
uint8_t g_recv_buf[100]; /< \brief 接收缓冲区 */
static uint8_t nfc_drive_bcc_cacl (const uint8_t *p_buf)
{
int i;
uint8_t bcc = 0x00;
for (i = 0; i < (p_buf[0] - 2); i++) {
bcc ^= p_buf[i];
}
return (~bcc);
}
static int nfc_set_cmd(uint8_t cmd_type,
uint8_t cmd,
uint8_t *p_info,
uint8_t info_nbytes)
{
int bcc;
int bcc_site;
int ret,i=0;
memset(g_send_buf, 0, sizeof(g_send_buf));
memset(g_recv_buf, 0, sizeof(g_recv_buf));
g_send_buf[__FRAME_CMD_TYPE] = cmd_type | g_cmd_seq;
g_cmd_seq += 0x10;
g_send_buf[__FRAME_CMD] = cmd;
g_send_buf[__FRAME_DATA_LEN] = info_nbytes;
g_send_buf[__FRAME_LEN] = 0x06 + info_nbytes;
memcpy(&g_send_buf[__FRAME_DATA], p_info, info_nbytes);
bcc_site = __FRAME_DATA + info_nbytes;
bcc = nfc_drive_bcc_cacl(g_send_buf);
g_send_buf[bcc_site] = bcc;
g_send_buf[bcc_site + 1] = 0x03;
printk("\n");
for(i=0; i< g_send_buf[__FRAME_LEN]; i++)
{
printk("%02X",g_send_buf[i]);
}
printk("\n");
msleep(500);
ret = i2c_master_send(zlg600_client, g_send_buf, g_send_buf[__FRAME_LEN]);
msleep(500);
ret = i2c_master_recv(zlg600_client, g_recv_buf, sizeof(g_recv_buf));
printk("Recv Data Size:%02X\n", g_recv_buf[0]);
return ret;
}
static int nfc_zlg_get_dev_info (uint8_t cmd_type,
uint8_t cmd,
uint8_t *p_info,
uint8_t info_nbytes)
{
int bcc;
int bcc_site;
int ret,i=0;
memset(g_send_buf, 0, sizeof(g_send_buf));
memset(g_recv_buf, 0, sizeof(g_recv_buf));
g_send_buf[__FRAME_CMD_TYPE] = cmd_type | g_cmd_seq;
g_cmd_seq += 0x10;
g_send_buf[__FRAME_CMD] = cmd;
g_send_buf[__FRAME_DATA_LEN] = info_nbytes;
g_send_buf[__FRAME_LEN] = 0x06 + info_nbytes;
memcpy(&g_send_buf[__FRAME_DATA], p_info, info_nbytes);
bcc_site = __FRAME_DATA + info_nbytes;
bcc = nfc_drive_bcc_cacl(g_send_buf);
g_send_buf[bcc_site] = bcc;
g_send_buf[bcc_site + 1] = 0x03;
msleep(500);
for( i=0; i < 3; i++)
{
ret = i2c_master_send(zlg600_client, g_send_buf, g_send_buf[__FRAME_LEN]);
//printk("Send Data By Smbus size=%d;\n", ret);
msleep(500);
ret = i2c_master_recv(zlg600_client , g_recv_buf , __ACK_LENGTH_DEV_INFO);
if(g_recv_buf[__FRAME_LEN] == __ACK_LENGTH_DEV_INFO)
{
break;
}
}
//__FRAME_DATA
//取出设备信息 数据的4 -- 14
uint8_t *info = kzalloc(g_recv_buf[__FRAME_DATA_LEN], GFP_KERNEL);;
for(i=4; i < 19; i++)
{
memcpy(info, &g_recv_buf[__FRAME_DATA], g_recv_buf[__FRAME_DATA_LEN]);
}
printk("Detect Nfc zlg600a: %s\n", info);
return ret;
}
//外部中断的处理函数
static irqreturn_t nfc_zlg600a_interrupt(int irq, void *dev_id)
{
printk(“zlg600a interrupt now, card data report\n”);
irq_come_in = 1;
//当发生中断时,唤醒工作队列,读取数据
wake_up(&read_data_wq);
return IRQ_HANDLED;
}
static int nfc_zlg_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int error;
zlg600_client = client;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) {
dev_err(&adapter->dev, "doesn't support required functionality\n");
error = -EIO;
}
msleep(500);
//动态初始化等待工作队列
init_waitqueue_head(&read_data_wq);
//申请中断
request_id = client->irq;
printk("Client Address:%02X,%d\n", zlg600_client->addr, request_id);
error = request_irq(request_id, nfc_zlg600a_interrupt, IRQF_TRIGGER_FALLING, "zlg600a_int", NULL);
if (error < 0) {
dev_err(&client->dev, "ZLG NFC Module: request irq failed %s:%d \n ",__FILE__,__LINE__);
goto exit_irq_request_failed;
}
//获取设备信息
nfc_zlg_get_dev_info(__CMD_TYPE_DEV_CTRL, 'A', NULL, 0);
// 设置Mifare 自动检测
// uint8_t check_buf[1];
// check_buf[0] = 0x01;
// nfc_zlg_set_auto_detect(__CMD_TYPE_MFIARE, 'O', check_buf, sizeof(check_buf));
//设置天线范围内的所有A类卡请求
uint8_t check_buf[1];
check_buf[0] = 0x52;
int i = 0;
for( i=0; i < 4; i++)
{
nfc_set_cmd(__CMD_TYPE_MFIARE, 'A', check_buf, sizeof(check_buf));
}
int ret = misc_register(&nfc_zlg_miscdev);
if (ret < 0)
{
printk("ZLG600A Misc Register Failed:%d\n",ret);
return ret;
}
exit_irq_request_failed:
return 0;
}
static int nfc_zlg_remove(struct i2c_client *client)
{
free_irq(request_id, NULL);
misc_deregister(&nfc_zlg_miscdev);
return 0;
}
static int nfc_zlg_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
return 0;
}
static const struct i2c_device_id nfc_zlg_id[] = {
{ “zlg600a”, 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, nfc_zlg_id);
#ifdef CONFIG_OF
static const struct of_device_id nfc_zlg_ids[] = {
{ .compatible = “nfc,zlg600a”, },
{ /* sentinel / }
};
MODULE_DEVICE_TABLE(of, nfc_zlg_ids);
#endif
/ 1. 分配/设置i2c_driver */
static struct i2c_driver nfc_zlg_driver = {
.driver = {
.owner = THIS_MODULE,
.name = “zlg600a”,
.of_match_table = of_match_ptr(nfc_zlg_ids),
},
.probe = nfc_zlg_probe,
.id_table = nfc_zlg_id,
.remove = nfc_zlg_remove,
.detect = nfc_zlg_detect,
};
static int nfc_zlg_module_init(void)
{
i2c_add_driver(&nfc_zlg_driver);
return 0;
}
static void nfc_zlg_module_exit(void)
{
i2c_del_driver(&nfc_zlg_driver);
}
module_init(nfc_zlg_module_init);
module_exit(nfc_zlg_module_exit);
MODULE_LICENSE(“GPL”);