从 module_init 和 module_exit 开始读
static int __init pn544_dev_init(void)
{
pr_info("Loading pn544 driver\n");
return i2c_add_driver(&pn544_driver);
}
module_init(pn544_dev_init);
static void __exit pn544_dev_exit(void)
{
pr_info("Unloading pn544 driver\n");
i2c_del_driver(&pn544_driver);
}
module_exit(pn544_dev_exit);
通过 i2c_add_driver 和 i2c_del_driver 来注册与卸载 nfc driver
pn544_driver:
static struct i2c_driver pn544_driver = {
.id_table = pn544_id,
.probe = pn544_probe,
.remove = pn544_remove,
.driver = {
.owner = THIS_MODULE,
.name = PN544_NAME,
.of_match_table = msm_match_table,
},
};
其中 id_table为
static const struct i2c_device_id pn544_id[] = {
{ PN544_NAME, 0 },
{ }
};
由于 Linux3.0 后采用了 DTS 机制,使用 Device Tree 后,驱动需要与.dts中描述的设备结点进行匹配,从而引发驱动的probe()函数执行。对于platform_driver而言,需要添加一个OF匹配表 of_match_table,在这里即 msm_match_table[]。
static struct of_device_id msm_match_table[] = {
{.compatible = "nxp,nfc-pn544"},
{}
};
MODULE_DEVICE_TABLE(of, msm_match_table);
probe函数如下,只保留了关键代码。
static int pn544_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int r = 0;
int ret;
//struct pn544_i2c_platform_data *platform_data_from_board;
struct pn544_dev *pn544_dev;
printk("pn547 enter probe\n");
//iomux_set(GPIO3_A3); //FIRM
//iomux_set(GPIO3_A6); //VEN
//iomux_set(GPIO3_A7); //IRQ
//platform_data_from_board = client->dev.platform_data;
//if (platform_data_from_board == NULL) {
// printk("%s : nfc probe fail\n", __func__);
// return -ENODEV;
//}
printk("nfc probe step01 is ok\n");
//判定适配器能力,这里检测适配器具有I2C功能
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
printk("%s : need I2C_FUNC_I2C\n", __func__);
return -ENODEV;
}
printk("nfc probe step02 is ok\n");
printk("nfc probe step03 is ok\n");
//分配内核空间,填充 pn544_dev 结构
pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL);
//g_pn544_dev指向所分配内核空间的起始位置
g_pn544_dev = pn544_dev;
if (pn544_dev == NULL) {
dev_err(&client->dev,
"failed to allocate memory for module data\n");
ret = -ENOMEM;
goto err_exit;
}
printk("nfc probe step04 is ok\n");
//pn547_dev->irq_gpio = platform_data_from_board->irq_gpio;
//pn547_dev->ven_gpio = platform_data_from_board->ven_gpio;
//pn547_dev->firm_gpio = platform_data_from_board->firm_gpio;
//填充 pn544_dev 中的 client
pn544_dev->client = client;
//使用这个函数填充 pdata->xxx_gpio
//包括 使能管脚 VEN_GPIO、中断管脚IRQ_GPIO、固件下载管脚 FIRM_GPIO
ret=nfc_parse_dt(&client->dev,pn544_dev);
pr_info("irq_gpio=%d; ven_gpio=%d; firm_gpio=%d; \n", \
pn544_dev->irq_gpio,pn544_dev->ven_gpio,pn544_dev->firm_gpio);
if(ret){
pr_err("parse node error. pls check the dts file \n");
ret = -EINVAL;
//goto err_parser;
}
//???禁能时钟功能???
pn544_dev->clk_run = false;
//if (0)
// pn544_clock_select(pn544_dev);
#if 0
//gpio_is_valid 测试gpio管脚是否合法
if (gpio_is_valid(pn544_dev->clkreq_gpio)) {
//gpio_request是申请gpio
//第一个参数是你要申请的管脚,第二个参数是名字,成功返回 0
r = gpio_request(pn544_dev->clkreq_gpio,"nfc_clkreq_gpio");
if (r) {
dev_err(&client->dev, "unable to request gpio [%d]\n",
pn544_dev->clkreq_gpio);
goto err_clkreq_gpio;
}
//设置gpio方向为输入,成功返回 0
r = gpio_direction_input(pn544_dev->clkreq_gpio);
if (r) {
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
pn544_dev->clkreq_gpio);
goto err_clkreq_gpio;
}
} else {
dev_err(&client->dev, "clkreq gpio not provided\n");
goto err_clk;
}
#endif
//return 0;
//初始化 互斥锁 和 等待队列
/* init mutex and queues */
//初始化等待队列头
init_waitqueue_head(&pn544_dev->read_wq);
//初始化互斥锁
mutex_init(&pn544_dev->read_mutex);
//初始化自旋锁
spin_lock_init(&pn544_dev->irq_enabled_lock);
//填充 pn544_dev 中的 pn544_device 的
//次级设备号,设备名,设备操作符
pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR;
pn544_dev->pn544_device.name = PN544_NAME;
//在此处与 pn544_dev_fops 操作列表进行连接
//在 pn544_dev_fops 中实现了一些函数,具体在后面分析
pn544_dev->pn544_device.fops = &pn544_dev_fops;
//注册混杂设备
ret = misc_register(&pn544_dev->pn544_device);
if (ret) {
printk("%s : misc_register failed\n", __FILE__);
goto err_misc_register;
}
printk("nfc probe step05 is ok\n");
//申请中断的 GPIO
if(gpio_request(pn544_dev->irq_gpio,"nfc_int") != 0)
{
printk("PN544: gpio_IRQ_request error\n");
goto err_irq;
}
//申请使能的 GPIO
if(gpio_request(pn544_dev->ven_gpio,"nfc_ven") != 0)
{
printk("PN544: gpio_VEN_request error\n");
goto err_ven;
}
//申请固件下载的 GPIO
if(gpio_request(pn544_dev->firm_gpio,"nfc_firm") != 0)
{
printk("PN544: gpio_firm_request error\n");
goto err_firm;
}
//设置GPIO 方向
gpio_direction_output(pn544_dev->firm_gpio, 0);
gpio_direction_output(pn544_dev->ven_gpio, 1);
printk("nfc probe GPIO is ok\n");
gpio_direction_input(pn544_dev->irq_gpio);
printk("pn544 client->irq = %d", client->irq); //kingsun, zhudm
client->irq = gpio_to_irq(pn544_dev->irq_gpio);
printk("%s : requesting IRQ %d\n", __func__, client->irq);
pn544_dev->irq_enabled = true;
ret = request_irq(client->irq, pn544_dev_irq_handler,
IRQF_TRIGGER_HIGH, client->name, pn544_dev);
#if 1
if (ret) {
printk("request_irq failed\n");
goto err_request_irq_failed;
}
#endif
printk("nfc probe step06 is ok\n");
pn544_disable_irq(pn544_dev);
//return 0;
i2c_set_clientdata(client, pn544_dev);
printk("nfc probe successful\n");
#if defined(PN544_DEBUG)
ret = device_create_file(&client->dev, &pn544_dev_attr);
if (ret) {
//NFC_ERR("sysfs registration failed, error %d \n", ret);
goto err_request_irq_failed;
}
#endif
return 0;
err_request_irq_failed:
misc_deregister(&pn544_dev->pn544_device);
err_misc_register:
mutex_destroy(&pn544_dev->read_mutex);
//kfree(pn547_dev);
//err_clkreq_gpio:
//gpio_free(pn544_dev->clkreq_gpio);
//err_clk:
//pn544_clock_deselect(pn544_dev);
err_exit:
gpio_free(pn544_dev->firm_gpio);
err_ven:
gpio_free(pn544_dev->ven_gpio);
err_irq:
gpio_free(pn544_dev->irq_gpio);
err_firm:
gpio_free(pn544_dev->firm_gpio);
kfree(pn544_dev);
return ret;
}
static int pn544_remove(struct i2c_client *client)
{
struct pn544_dev *pn544_dev;
pn544_dev = i2c_get_clientdata(client);
//释放中断
free_irq(client->irq, pn544_dev);
//卸载字符设备
misc_deregister(&pn544_dev->pn544_device);
//kingsun, jerome/zhudm add
#if defined(PN544_DEBUG)
device_remove_file(&client->dev, &pn544_dev_attr);
#endif
//pn544_clock_deselect(pn544_dev);
//销毁互斥锁
mutex_destroy(&pn544_dev->read_mutex);
//释放 GPIO
gpio_free(pn544_dev->irq_gpio);
gpio_free(pn544_dev->ven_gpio);
gpio_free(pn544_dev->firm_gpio);
//释放内核空间
kfree(pn544_dev);
return 0;
}
在 probe 中,有这样一行代码
pn544_dev->pn544_device.fops = &pn544_dev_fops;
此处将 fops 注册到节点
static const struct file_operations pn544_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = pn544_dev_read,
.write = pn544_dev_write,
.open = pn544_dev_open,
.unlocked_ioctl = pn544_dev_ioctl,
};
fops 中包含了 ioctl 的操作方式,cmd 为 0 关闭 nfc , 1 为开启,2 为固件下载。
static long pn544_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct pn544_dev *pn544_dev = filp->private_data;
switch (cmd) {
case PN544_SET_PWR:
if (arg == 2) {
/* power on with firmware download (requires hw reset) */
printk("%s power on with firmware\n", __func__);
gpio_set_value(pn544_dev->ven_gpio, 1);
gpio_set_value(pn544_dev->firm_gpio, 1);
msleep(10);
gpio_set_value(pn544_dev->ven_gpio, 0);
msleep(50);
gpio_set_value(pn544_dev->ven_gpio, 1);
msleep(10);
} else if (arg == 1) {
/* power on */
printk("%s power on\n", __func__);
gpio_set_value(pn544_dev->firm_gpio, 0);
gpio_set_value(pn544_dev->ven_gpio, 1);
irq_set_irq_wake(pn544_dev->client->irq, 1);
msleep(10);
} else if (arg == 0) {
/* power off */
printk("%s power off\n", __func__);
gpio_set_value(pn544_dev->firm_gpio, 0);
gpio_set_value(pn544_dev->ven_gpio, 0);
irq_set_irq_wake(pn544_dev->client->irq, 0);
msleep(10);
} else {
printk("%s bad arg %lu\n", __func__, arg);
return -EINVAL;
}
break;
default:
printk("%s bad ioctl %u\n", __func__, cmd);
return -EINVAL;
}
return 0;
}
NFC 的 Kernel 并没有很多的东西,总的来说其实只是提供了一个 ioctl 来给我们上层进行操作。