NXP

NXP NFC kernel 分析

2019-07-12 12:08发布

初始化与卸载

从 module_init 和 module_exit 开始读 static int __init pn544_dev_init(void) { pr_info("Loading pn544 driver "); return i2c_add_driver(&pn544_driver); } module_init(pn544_dev_init); static void __exit pn544_dev_exit(void) { pr_info("Unloading pn544 driver "); 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 函数

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 "); //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 ", __func__); // return -ENODEV; //} printk("nfc probe step01 is ok "); //判定适配器能力,这里检测适配器具有I2C功能 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { printk("%s : need I2C_FUNC_I2C ", __func__); return -ENODEV; } printk("nfc probe step02 is ok "); printk("nfc probe step03 is ok "); //分配内核空间,填充 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 "); ret = -ENOMEM; goto err_exit; } printk("nfc probe step04 is ok "); //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; ", pn544_dev->irq_gpio,pn544_dev->ven_gpio,pn544_dev->firm_gpio); if(ret){ pr_err("parse node error. pls check the dts file "); 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] ", 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] ", pn544_dev->clkreq_gpio); goto err_clkreq_gpio; } } else { dev_err(&client->dev, "clkreq gpio not provided "); 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 ", __FILE__); goto err_misc_register; } printk("nfc probe step05 is ok "); //申请中断的 GPIO if(gpio_request(pn544_dev->irq_gpio,"nfc_int") != 0) { printk("PN544: gpio_IRQ_request error "); goto err_irq; } //申请使能的 GPIO if(gpio_request(pn544_dev->ven_gpio,"nfc_ven") != 0) { printk("PN544: gpio_VEN_request error "); goto err_ven; } //申请固件下载的 GPIO if(gpio_request(pn544_dev->firm_gpio,"nfc_firm") != 0) { printk("PN544: gpio_firm_request error "); 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 "); 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 ", __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 "); goto err_request_irq_failed; } #endif printk("nfc probe step06 is ok "); pn544_disable_irq(pn544_dev); //return 0; i2c_set_clientdata(client, pn544_dev); printk("nfc probe successful "); #if defined(PN544_DEBUG) ret = device_create_file(&client->dev, &pn544_dev_attr); if (ret) { //NFC_ERR("sysfs registration failed, error %d ", 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; }

remove 函数

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 ", __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 ", __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 ", __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 ", __func__, arg); return -EINVAL; } break; default: printk("%s bad ioctl %u ", __func__, cmd); return -EINVAL; } return 0; } NFC 的 Kernel 并没有很多的东西,总的来说其实只是提供了一个 ioctl 来给我们上层进行操作。