史上最简单的Linux内核IIO子系统入门demo_内核版本4.4.194

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

完工。

欢迎评论。

你可能感兴趣的:(IIO,linux,服务器,运维)