AM3353平台上的Linux 3.2.0 IIO子文件系统框架的驱动
2017-06-28 16:18
1086 查看
在Linux kernel 3.2已经引入了IIO子文件系统,但是驱动不多,毕竟刚开始的一个新的子文件系统 。在kernel 3.x版本中目录在drivers/staging/iio目录下,到了kernel 4.x版本下被移到了drivers/iio,显然大家认可了这个子文件系统的框架。
由于我所使用的平台是 kernel 3.2版本,在对DHT11的驱动上这一版本并没支持,需要自己的移植。虽然kernel 4.x有了支持,但是对整体版本升级,有所得不偿失。我就自己移植了。
下面的记录就是对移植过程的记录:
1、修改kernel-3.2/drivers/staging/iio目录下的industrialio-core.c文件:
2、修改kernel-3.2/drivers/staging/iio目录下的iio.h文件:
3、复制网上找到kernel 4.4.1版本中的/drivers/iio/humidity目录到kernel-3.2/drivers/staging/iio目录下,并修改Kconfig
4、修改Makefile
在make menuconfig
5、因为kernel 4.4 相对 kernel 3.2 增加很对新函数所以不能直接使用原先的dht11.c驱动文件,需要自己重新编写,废话不多少。
很明显,我基本上没有使用原先驱动的思路,而是自己写的。
6、修改arch/arm/mach-omap2/board-am335xevm.c增加一个device驱动
重新编译并烧写新内核。
在/sys/bus/iio/devices可以看到一个新的iio设备
获取的温度和湿度数据。注意获取真实数字需要除以100,例如2800/100=28摄氏度,3100/100=31%PH
也可以在下面的路径读取。其实是一样的。
由于我所使用的平台是 kernel 3.2版本,在对DHT11的驱动上这一版本并没支持,需要自己的移植。虽然kernel 4.x有了支持,但是对整体版本升级,有所得不偿失。我就自己移植了。
下面的记录就是对移植过程的记录:
1、修改kernel-3.2/drivers/staging/iio目录下的industrialio-core.c文件:
static const char * const iio_chan_type_name_spec[] = { [IIO_VOLTAGE] = "voltage", [IIO_CURRENT] = "current", [IIO_POWER] = "power", [IIO_ACCEL] = "accel", [IIO_ANGL_VEL] = "anglvel", [IIO_MAGN] = "magn", [IIO_LIGHT] = "illuminance", [IIO_INTENSITY] = "intensity", [IIO_PROXIMITY] = "proximity", [IIO_TEMP] = "temp", [IIO_HUMIDITYRELATIVE] = "humidityrelative", //增加湿度 [IIO_INCLI] = "incli", [IIO_ROT] = "rot", [IIO_ANGL] = "angl", [IIO_TIMESTAMP] = "timestamp", [IIO_CAPACITANCE] = "capacitance", };蓝色的文集是增加的,这个版本已经支持了温度,但是没有支持湿度,因此需要增加。
2、修改kernel-3.2/drivers/staging/iio目录下的iio.h文件:
enum iio_chan_type { /* real channel types */ IIO_VOLTAGE, IIO_CURRENT, IIO_POWER, IIO_ACCEL, IIO_ANGL_VEL, IIO_MAGN, IIO_LIGHT, IIO_INTENSITY, IIO_PROXIMITY, IIO_TEMP, IIO_HUMIDITYRELATIVE, //增加湿度 IIO_INCLI, IIO_ROT, IIO_ANGL, IIO_TIMESTAMP, IIO_CAPACITANCE, };
3、复制网上找到kernel 4.4.1版本中的/drivers/iio/humidity目录到kernel-3.2/drivers/staging/iio目录下,并修改Kconfig
source "drivers/staging/iio/humidity/Kconfig"
4、修改Makefile
obj-y += humidity/
在make menuconfig
x -> Device Drivers x x -> Staging drivers (STAGING [=y]) x x -> Industrial I/O support (IIO [=y]) x x -> Humidity sensors x
5、因为kernel 4.4 相对 kernel 3.2 增加很对新函数所以不能直接使用原先的dht11.c驱动文件,需要自己重新编写,废话不多少。
#include <linux/err.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/printk.h> #include <linux/slab.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/sysfs.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/wait.h> #include <linux/bitops.h> #include <linux/completion.h> #include <linux/mutex.h> #include <linux/delay.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/ktime.h> //#include <linux/timekeeping.h> //#include "/home/zuoyi/works/kernel-3.2/drivers/staging/iio/iio.h" #include "../iio.h" #define DRIVER_NAME "dht11" /* Convert GPIO signal to GPIO pin number */ #define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio)) #define DHT11_GPIO GPIO_TO_PIN(1, 26) #define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */ #define DHT11_EDGES_PREAMBLE 2 #define DHT11_BITS_PER_READ 40 /* * Note that when reading the sensor actually 84 edges are detected, but * since the last edge is not significant, we only store 83: */ #define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \ DHT11_EDGES_PREAMBLE + 1) /* Data transmission timing (nano seconds) */ #define DHT11_START_TRANSMISSION 18 /* ms */ #define DHT11_SENSOR_RESPONSE 80000 #define DHT11_START_BIT 50000 #define DHT11_DATA_BIT_LOW 27000 #define DHT11_DATA_BIT_HIGH 70000 struct dht11 { struct device *dev; int gpio; int irq; struct completion completion; /* The iio sysfs interface doesn't prevent concurrent reads: */ struct mutex lock; s64 timestamp; int temperature; int humidity; /* num_edges: -1 means "no transmission in progress" */ int num_edges; struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ]; }; /* 读取单字节(8 bit)数据 */ static char DHT11_read_byte ( void ) { char DHT11_byte ; unsigned char i ; unsigned char temp ; DHT11_byte = 0 ; for ( i = 0 ; i < 8 ; i ++ ) { temp = 0 ; while ( ! (gpio_get_value(DHT11_GPIO) ) ) { temp ++ ; if ( temp > 12 ) return 1 ; udelay ( 5 ) ; } temp = 0 ; while ( gpio_get_value(DHT11_GPIO) ) { temp ++ ; if ( temp > 20 ) return 1 ; udelay ( 5 ) ; } if ( temp > 6 ) { DHT11_byte <<= 1 ; DHT11_byte |= 1 ; } else { DHT11_byte <<= 1 ; DHT11_byte |= 0 ; } } return DHT11_byte ; } static int dht11_read_raw(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long m) { struct dht11 *dht11 = iio_priv(iio_dev); int ret;//, timeres; unsigned char DataTemp; unsigned char i; unsigned char err; char tempBuf[5]={0}; unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; mutex_lock(&dht11->lock); err = 0 ; /* 管脚设置为输出并拉低电平 */ gpio_direction_output(DHT11_GPIO, 0); msleep ( 18 ); //mdelay ( 18 ); gpio_set_value(DHT11_GPIO, 1); udelay ( 40 ); gpio_direction_input(DHT11_GPIO); if ( !err ) { DataTemp = 10 ; while ( !( gpio_get_value(DHT11_GPIO) ) && DataTemp ) { DataTemp --; udelay ( 10 ); } if ( !DataTemp ) { err = 1; ret = -EFAULT; goto err; } } if ( !err ) { DataTemp = 10 ; while ( gpio_get_value(DHT11_GPIO) && DataTemp ) { DataTemp --; udelay ( 10 ); } if ( !DataTemp ) { err = 1; ret = -EFAULT; goto err; } } if ( !err ) { for ( i = 0; i < 5; i ++ ) { tempBuf[i] = DHT11_read_byte () ; } DataTemp = 0 ; for ( i = 0; i < 4; i ++ ) { DataTemp += tempBuf[i] ; } if ( DataTemp != tempBuf[4] ) { ret = -EFAULT; goto err; } } hum_int = tempBuf[0]; hum_dec = tempBuf[1]; temp_int = tempBuf[2]; temp_dec = tempBuf[3]; checksum = tempBuf[4]; if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) return -EIO; //printk( "Humidity:%d.%d %%RH Temperature:%d.%d C sum is:%d\n", tempBuf[0], tempBuf[1], tempBuf[2], tempBuf[3],tempBuf[4] ) ; dht11->temperature = (((temp_int & 0x7f)* 100) + temp_dec) * ((temp_int & 0x80) ? -1 : 1); dht11->humidity = ((hum_int * 100) + hum_dec); ret = IIO_VAL_INT; if (chan->type == IIO_TEMP) *val = dht11->temperature; else if (chan->type == IIO_HUMIDITYRELATIVE) *val = dht11->humidity; else ret = -EINVAL; err: dht11->num_edges = -1; mutex_unlock(&dht11->lock); /* 管脚设置为输出并拉高 */ gpio_direction_output(DHT11_GPIO, 1); return ret; } static const struct iio_info dht11_iio_info = { .driver_module = THIS_MODULE, .read_raw = dht11_read_raw, }; //static const struct iio_chan_spec dht11_chan_spec[] = { // { .type = IIO_TEMP, // //.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, // { .type = IIO_HUMIDITYRELATIVE, // //.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), } //}; static const struct iio_chan_spec dht11_chan_spec[] = { { .type = IIO_TEMP, //.indexed = 2, .channel = 1, }, { .type = IIO_HUMIDITYRELATIVE, //.indexed = 1, .channel = 0, } }; static const struct of_device_id dht11_dt_ids[] = { { .compatible = "dht11", }, { } }; MODULE_DEVICE_TABLE(of, dht11_dt_ids); /* 探测函数 */ static int dht11_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; //struct device_node *node = dev->of_node; struct dht11 *dht11; struct iio_dev *iio; int ret; /* 1、分配一个IIO设备 */ // iio = devm_iio_device_alloc(dev, sizeof(*dht11)); // if (!iio) { // dev_err(dev, "Failed to allocate IIO device\n"); // return -ENOMEM; // } iio = iio_allocate_device(sizeof(struct dht11)); if (!iio) { dev_err(dev, "Failed to allocate IIO device\n"); return -ENOMEM; } /* 2、设置IIO设备 */ dht11 = iio_priv(iio); dht11->dev = dev; /* 1、申请管脚 */ ret = gpio_request(DHT11_GPIO, "dht11_gpio"); if (ret) goto free_master; /* 2、管脚设置为输出并拉高 */ gpio_direction_output(DHT11_GPIO, 1); platform_set_drvdata(pdev, iio); init_completion(&dht11->completion); mutex_init(&dht11->lock); iio->name = pdev->name; iio->dev.parent = &pdev->dev; iio->info = &dht11_iio_info; iio->modes = INDIO_DIRECT_MODE; iio->channels = dht11_chan_spec; iio->num_channels = ARRAY_SIZE(dht11_chan_spec); /* 3、注册一个IIO设备 */ return iio_device_register(iio); free_master: return ret; } static struct platform_driver dht11_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = dht11_dt_ids, }, .probe = dht11_probe, }; module_platform_driver(dht11_driver); MODULE_AUTHOR("zue "); MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver"); MODULE_LICENSE("GPL v2");
很明显,我基本上没有使用原先驱动的思路,而是自己写的。
6、修改arch/arm/mach-omap2/board-am335xevm.c增加一个device驱动
/* add a dht11 */ static struct platform_device dht11_device = { .name = "dht11", .id = -1, }; static void dht11_init(int evm_id, int profile ) { int err; err = platform_device_register(&dht11_device); if (err) pr_err("failed to register dht11 device\n"); else pr_info("register dht11 device ok\n"); }
static struct evm_dev_cfg ok335x_dev_cfg[] = { ...... {dht11_init, DEV_ON_BASEBOARD, PROFILE_ALL},
重新编译并烧写新内核。
[ 0.091666] register dht11 device ok
在/sys/bus/iio/devices可以看到一个新的iio设备
/sys/bus/iio/devices # ls iio:device0 iio:device1
/sys/devices/platform/dht11/iio:device1 # ls -l total 0 -r--r--r-- 1 0 0 4096 Jun 28 15:36 dev -r--r--r-- 1 0 0 4096 Jun 28 15:36 in_humidityrelative_raw -r--r--r-- 1 0 0 4096 Jun 28 15:36 in_temp_raw -r--r--r-- 1 0 0 4096 Jun 28 15:36 name drwxr-xr-x 2 0 0 0 Jun 28 15:36 power lrwxrwxrwx 1 0 0 0 Jun 28 15:36 subsystem -> ../../../../bus/iio -rw-r--r-- 1 0 0 4096 Jun 28 15:36 uevent
/sys/devices/platform/dht11/iio:device1 # cat name dht11 /sys/devices/platform/dht11/iio:device1 # cat in_temp_raw 2800 /sys/devices/platform/dht11/iio:device1 # cat in_humidityrelative_raw 3100
获取的温度和湿度数据。注意获取真实数字需要除以100,例如2800/100=28摄氏度,3100/100=31%PH
也可以在下面的路径读取。其实是一样的。
/sys/devices/platform/dht11/iio:device1 # ls -l total 0 -r--r--r-- 1 0 0 4096 Jun 28 15:36 dev -r--r--r-- 1 0 0 4096 Jun 28 15:36 in_humidityrelative_raw -r--r--r-- 1 0 0 4096 Jun 28 15:36 in_temp_raw -r--r--r-- 1 0 0 4096 Jun 28 15:36 name drwxr-xr-x 2 0 0 0 Jun 28 15:36 power lrwxrwxrwx 1 0 0 0 Jun 28 15:36 subsystem -> ../../../../bus/iio -rw-r--r-- 1 0 0 4096 Jun 28 15:36 uevent
相关文章推荐
- [Linux驱动开发] cramfs文件系统制作及移植
- [Linux驱动开发] jffs2 文件系统制作及移植
- ThinkPHP框架在Linux系统中报找不到模版文件的错误
- 在Linux DeviceTree增添dtsi文件并在驱动中读取节点信息写入sys文件系统
- Nginx配置CI框架问题(Linux平台下Centos系统)
- [Linux]Grub和initrd对文件系统驱动的支持
- Linux 驱动相关文件系统
- 不同系统平台之间(Linux与Linux、Linux与Unix)利用NFS实现文件共享方法
- Linux设备模型——设备驱动模型和sysfs文件系统解读
- Linux 4.3 将移除 EXT3 文件系统驱动
- linux设备驱动学习--proc文件系统
- 概述Linux系统的驱动框架及驱动加载
- U-boot移植 (v2012.04.1 S3C2440平台) (五) DM9000驱动支持,yaffs文件系统下载支持
- Linux 文件系统与设备驱动
- Linux设备驱动开发详解-Note(11)--- Linux 文件系统与设备文件系统(3)
- Linux 下磁盘分区和创建文件系统(基于Ubuntu平台)
- Linux下的C编程实战(开发平台搭建,文件系统编程,进程控制与进程通信编程,“线程”控制与“线程”通信编程,驱动程序设计,专家问答)
- 一个简单的文件系统过滤驱动框架
- 在连续两个平台的uboot和Linux系统移植过程中,在千兆网口调试这块都遇到了很大的麻烦。由于寄存器数量庞大,千兆网口MAC和PHY内部结构复杂,MAC和PHY接口种类多,千兆以太网驱动的调试成
- 关于Linux平台下的ZFS文件系统最新情况说明