1 Linux IIO 子系统给内核模块提供了一个标准的接口给上层应用。
我们今天要做的是如何给上层提供一个温度计的数据,如果没有IIO子系统 , 那我们还需要自己提供接口给上层,比如通过设备文件读写的方式。
如果我们使用了IIO子系统,那我们只需要按照IIO的框架往里面填入数据即可,上层程序按照IIO的框架格式去读就可以。
IIO 里面有通道的概念,我们今天只使用一个通道来提供温度数据36.5.
下面是驱动源码:注意内核版本是 4.4.194
#include /* Needed for the macros */
#include /* Needed for pr_info() */
#include /* Needed by all modules */
#include
#include
/**
*
pressure@78 {
compatible = "mychipt";
reg = <0x78>;
};
https://www.linuxjournal.com/search/node?keys=input+subsystem
There are two ways for a user space application to interact with an IIO driver.
/sys/bus/iio/iio:deviceX/, this represents a hardware sensor and groups together the data channels of the same chip.
/dev/iio:deviceX, character device node interface used for buffered data transfer and for events information retrieval.
Available standard attributes for IIO devices are described in the Documentation/ABI/testing/sysfs-bus-iio file in the Linux kernel sources.
https://bootlin.com/blog/the-backbone-of-a-linux-industrial-i-o-driver/
https://www.kernel.org/doc/html/v4.12/driver-api/iio/intro.html
There are two ways for a user space application to interact with an IIO driver.
/sys/bus/iio/iio:deviceX/, this represents a hardware sensor and groups together the data channels of the same chip.
/dev/iio:deviceX, character device node interface used for buffered data transfer and for events information retrieval.
/sys/bus/iio/devices/iio:device2
*/
struct iio_dev *myiio;
/**
* function to request a value from the device. mask specifies which value. Note 0 means a reading of the channel in question.
* Return value will specify the type of value returned by the device. val and val2 will contain the elements making up the returned value.
*
*
*/
int myiio_readraw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
int *val, int *val2, long mask) {
pr_info("myiio_readraw start\n");
pr_info("myiio_readraw: iio_dev.name = %s\n", indio_dev->name);
pr_info("myiio_readraw: iio_dev.type = %d\n", chan->type);
pr_info("myiio_readraw: mask = %ld", mask);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
pr_info("mask = IIO_CHAN_INFO_PROCESSED\n");
break;
default:
pr_info("wha are you \n");
break;
}
*val = 365;
*val2 = 10;
pr_info("myiio_readraw end\n");
return IIO_VAL_FRACTIONAL;
}
static const struct iio_chan_spec temp_channel[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
};
static const struct iio_info info = { .driver_module = THIS_MODULE, .read_raw =
myiio_readraw, };
int myprobe(struct i2c_client *client, const struct i2c_device_id *id) {
pr_info("probe\n");
pr_err("name: = %s \n", client->name);
pr_err("name: = 0x%x \n", client->addr);
pr_err("i2c_device_id: = %s \n", id->name);
myiio = devm_iio_device_alloc(&client->dev, sizeof(*myiio));
myiio->channels = temp_channel;
myiio->num_channels = ARRAY_SIZE(temp_channel);
myiio->name = "myiio1025";
myiio->dev.parent = &client->dev;
myiio->info = &info;
myiio->modes = INDIO_DIRECT_MODE;
return devm_iio_device_register(&client->dev, myiio);
}
int myremove(struct i2c_client *client) {
pr_info("remove\n");
devm_iio_device_unregister(&client->dev, myiio);
iio_device_free(myiio);
return 0;
}
static const struct i2c_device_id my_i2c_id[] = { { "mychipt", 0 }, { }, };
static struct i2c_driver my_i2c_driver = { .driver =
{ .name = "my_i2c_driver", }, .probe = myprobe, .id_table = my_i2c_id,
.remove = myremove, };
static int __init foo_init(void)
{
pr_info("init my_i2c_driver\n");
return i2c_add_driver(&my_i2c_driver);
}
static void __exit foo_cleanup(void)
{
i2c_del_driver(&my_i2c_driver);
}
module_init(foo_init);
module_exit(foo_cleanup);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("andy one-key driver");
MODULE_ALIAS("one-key");
指定一个通道,掩码是告诉上层数据是已经处理过的。
static const struct iio_chan_spec temp_channel[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
};
myiio_readraw 里面的:
*val = 365;
*val2 = 10;
return IIO_VAL_FRACTIONAL; 表明返回值是小数,结果是 *val除以 *val2, 所以是 36.5 。
设备树的内容是 :
pressure@78 {
compatible = “mychipt”;
reg = <0x78>;
};
我是加在 &i2c6 下面 。 编译设备树,烧录内核。
然后编译安装模块之后,
可以执行 tree /sys/bus/iio/devices 看到新增的IIO设备,我这里是 iio:device2, 然后cd到 /sys/bus/iio/devicesiio:device2,ls 可以看到有如下输出:
dev in_temp_input name of_node power subsystem uevent
in_temp_input 就是我们的通道 ,现在执行 cat in_temp_input
就有如下输出:
36.500000000
完工。
欢迎评论。