初始化与卸载
从 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_dev *pn544_dev;
printk("pn547 enter probe
");
printk("nfc probe step01 is ok
");
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 = kzalloc(sizeof(*pn544_dev), GFP_KERNEL);
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
");
pn544_dev->client = client;
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;
}
pn544_dev->clk_run = false;
#if 0
if (gpio_is_valid(pn544_dev->clkreq_gpio)) {
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;
}
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
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.minor = MISC_DYNAMIC_MINOR;
pn544_dev->pn544_device.name = PN544_NAME;
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
");
if(gpio_request(pn544_dev->irq_gpio,"nfc_int") != 0)
{
printk("PN544: gpio_IRQ_request error
");
goto err_irq;
}
if(gpio_request(pn544_dev->ven_gpio,"nfc_ven") != 0)
{
printk("PN544: gpio_VEN_request error
");
goto err_ven;
}
if(gpio_request(pn544_dev->firm_gpio,"nfc_firm") != 0)
{
printk("PN544: gpio_firm_request error
");
goto err_firm;
}
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);
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);
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) {
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);
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);
#if defined(PN544_DEBUG)
device_remove_file(&client->dev, &pn544_dev_attr);
#endif
mutex_destroy(&pn544_dev->read_mutex);
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) {
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) {
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) {
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 来给我们上层进行操作。